diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5e978e070332..c66b16031c63 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -5,7 +5,7 @@ - [Introduction](#introduction) - [Getting Started](#getting-started) - [Meet the Team](#meet-the-team) - - [Head Maintainer and Project Manager](#head-maintainer-and-project-manager) + - [Head Maintainer and Maintainer Managers](#head-maintainer-and-maintainer-managers) - [Maintainers](#maintainers) - [Staff Tools and Major Rule changing PR’s](#staff-tools-and-major-rule-changing-prs) - [Issue Managers](#issue-managers) @@ -16,6 +16,7 @@ - [Writing understandable code](#writing-understandable-code) - [Misc](#misc) - [Pull Request Process](#pull-request-process) + - [A note on balance impacting PRs](#a-note-on-balance-impacting-prs) - [Good Boy Points](#good-boy-points) - [Porting features/sprites/sounds/tools from other codebases](#porting-featuresspritessoundstools-from-other-codebases) - [Things you can work on](#things-you-can-work-on) @@ -52,9 +53,9 @@ You can of course, as always, ask for help on the Discord channels or the forums ## Meet the Team -### Head Maintainer and Project Manager +### Head Maintainer and Maintainer Managers -The Head Maintainer and Project Manager are responsible for controlling, adding, and removing maintainers from the project. In addition to filling the role of a normal maintainer, they have sole authority on who becomes a maintainer, as well as who remains a maintainer and who does not. +The Head Maintainer and Maintainer Managers are responsible for controlling, adding, and removing maintainers from the project. In addition to filling the role of a normal maintainer, they have sole authority on who becomes a maintainer, as well as who remains a maintainer and who does not. ### Maintainers @@ -73,10 +74,10 @@ These are the few directives we have for project maintainers. - Try to get secondary maintainer approval before merging if you are able to. - PRs with empty commits intended to generate a changelog. - Do not merge PRs that contain content from the [banned content list](./CONTRIBUTING.md#banned-content). -- Do not merge PRs that contain balance changes without GA approval. Exceptions include: - - Any PR that has been un-reviewed by a GA for 7 days. +- Do not merge PRs that contain balance changes without Maintainer Manager approval. Exceptions include: + - Any PR that has been un-reviewed by a Maintainer Manager for 7 days. - Do not remove the DNM label that another Maintainer has applied. Exceptions include: - - GAs removing a DNM label placed by a Maintainer for Balance/Design reasons + - Maintainer Managers removing a DNM label placed by a Maintainer for Balance/Design reasons These are not steadfast rules as maintainers are expected to use their best judgement when operating. @@ -158,31 +159,13 @@ There is no strict process when it comes to merging pull requests. Pull requests * After leaving reviews on an open pull request, maintainers should convert it to a draft. Once you have addressed all their comments to the best of your ability, feel free to mark the pull as `Ready for Review` again. -### A note on balance review and PR denial +### A note on balance impacting PRs -Certain PRs, such as those which directly change number values (i.e. health, recoil, damage) or add large pieces of content to the game (i.e. a new gun, a new dropship weapon, or a new xeno structure) can have the potential to highly impact game balance or gameflow. As such, they are subject to another level of review known as "balance review". +Certain PRs, such as those which directly change number values (i.e. health, recoil, damage) or add large pieces of content to the game (i.e. a new gun, a new dropship weapon, or a new xeno structure) can have the potential to highly impact game balance or gameflow. -* Any gameplay architect may balance review PRs, after the PR has been open for 7 days without architect review any normal maintainer may balance review it. +* If a Maintainer Manager or Head Maintainer has not reviewed a pull request that impacts balance in 7 days, maintainers may review and merge the PR themselves. -* In the process of architect review, changes may be requested as normal, the PR may be approved, or the PR may be denied. - -* It should go without saying that denied PRs may not be reopened or remade without changes and prior approval. - -* We understand that having something you have worked on for quite some time being denied can be frustrating. Therefore, it is recommmended that you check with an architect or maintainer before beginning coding your PR if you have any doubts that your PR will be accepted. This will save everyone's time and energy. - -## Good Boy Points - -Each GitHub account has a score known as Good Boy Points, or GBP. This is a system we use to ensure that the codebase stays maintained and that contributors fix bugs as well as add features. - -The GBP gain or loss for a PR depends on the type of changes the PR makes, represented by the tags assigned to the PR by the CM-SS13 github bot or maintainers. Generally speaking, fixing bugs, updating sprites, or improving maps increases your GBP score, while adding mechanics, or rebalancing things will cost you GBP. - -The GBP change of a PR is the sum of greatest positive and lowest negative values it has. For example, a PR that has tags worth +10, +4, -1, -7, will net 3 GBP (10 - 7). - -Negative GBP increases the likelihood of a maintainer closing your PR. With that chance being higher the lower your GBP is. Be sure to use the proper tags in the changelog to prevent unnecessary GBP loss. Maintainers reserve the right to change tags as they deem appropriate. - -There is no benefit to having a higher positive GBP score, since GBP only comes into consideration when it is negative. - -You can see each tag and their GBP values [Here](https://github.com/cmss13-devs/cmss13/blob/master/.github/gbp.toml). +* We understand that having something you have worked on for quite some time being denied can be frustrating. Therefore, it is recommended that you check with a maintainer before beginning to code your PR if you have any doubts that it will be accepted. This will save everyone's time and energy. ## Porting features/sprites/sounds/tools from other codebases diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8f8ccbe07f60..cb1790053744 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -26,8 +26,8 @@ Put screenshots and videos here with an empty line between the screenshots and t # Changelog - - + + :cl: add: Added something diff --git a/.github/alternate_byond_versions.txt b/.github/alternate_byond_versions.txt new file mode 100644 index 000000000000..005803964cca --- /dev/null +++ b/.github/alternate_byond_versions.txt @@ -0,0 +1,9 @@ +# This file contains extra tests to run for specific BYOND versions. +# This is useful for making sure we maintain compatibility with both older and newer versions, +# while still having our main tests run on a guaranteed pinned version. + +# Format is version: map +# Example: +# 500.1337: runtimestation + +515.1610: lv624 diff --git a/.github/gbp.toml b/.github/gbp.toml deleted file mode 100644 index 85dd702803e2..000000000000 --- a/.github/gbp.toml +++ /dev/null @@ -1,23 +0,0 @@ -no_balance_label = "GBP: No Update" -reset_label = "GBP: Reset" - -[points] -"Accessibility" = 3 -"Admin" = 2 -"Atomic" = 2 -"Balance" = -5 -"Code Improvement" = 2 -"Fix" = 3 -"Grammar and Formatting" = 1 -"Hard Deletes" = 12 -"Logging" = 1 -"Feature" = -5 -"Performance" = 12 -"Priority: CRITICAL" = 20 -"Priority: High" = 15 -"Quality of Life" = 1 -"Refactor" = 6 -"Roadmap" = 15 -"Sound" = 3 -"Sprites" = 3 -"UI" = 3 diff --git a/.github/guides/STANDARDS.md b/.github/guides/STANDARDS.md index fc764d09c816..c9b988bd07ff 100644 --- a/.github/guides/STANDARDS.md +++ b/.github/guides/STANDARDS.md @@ -126,7 +126,7 @@ While we normally encourage (and in some cases, even require) bringing out of da This is a simple one - as we will eventually move to 515, we will need to ditch this kind of callback. So please don't add any new ones. Make our lives easier. ### PROC_REF Macros - When referencing procs in RegisterSignal, Callback and other procs you should use PROC_REF,TYPE_PROC_REF and GLOBAL_PROC_REF macros. + When referencing procs in RegisterSignal, Callback and other procs you should use PROC_REF, TYPE_PROC_REF and GLOBAL_PROC_REF macros. They ensure compilation fails if the reffered to procs change names or get removed. The macro to be used depends on how the proc you're in relates to the proc you want to use: @@ -168,6 +168,8 @@ This is a simple one - as we will eventually move to 515, we will need to ditch addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(funny)), 100)) ``` + Note that the same rules go for verbs too! We have VERB_REF() and TYPE_VERB_REF() as you need it in these same cases. GLOBAL_VERB_REF() isn't a thing however, as verbs are not global. + ### Signal Handlers All procs that are registered to listen for signals using `RegisterSignal()` must contain at the start of the proc `SIGNAL_HANDLER` eg; diff --git a/.github/workflows/autowiki.yml b/.github/workflows/autowiki.yml new file mode 100644 index 000000000000..82d0ac76f32f --- /dev/null +++ b/.github/workflows/autowiki.yml @@ -0,0 +1,52 @@ +name: Autowiki +on: + schedule: + - cron: "5 4 * * *" + workflow_dispatch: +permissions: + contents: read + +jobs: + autowiki: + runs-on: ubuntu-20.04 + steps: + - name: "Check for AUTOWIKI_USERNAME" + id: secrets_set + env: + ENABLER_SECRET: ${{ secrets.AUTOWIKI_USERNAME }} + run: | + unset SECRET_EXISTS + if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi + echo "SECRETS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT + - name: Checkout + if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: actions/checkout@v3 + - name: Restore BYOND cache + if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: actions/cache@v3 + with: + path: ~/BYOND + key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }} + - name: Install rust-g + if: steps.secrets_set.outputs.SECRETS_ENABLED + run: | + sudo dpkg --add-architecture i386 + sudo apt update || true + sudo apt install -o APT::Immediate-Configure=false libssl1.1:i386 + bash tools/ci/install_rust_g.sh + - name: Compile and generate Autowiki files + if: steps.secrets_set.outputs.SECRETS_ENABLED + run: | + bash tools/ci/install_byond.sh + source $HOME/BYOND/byond/bin/byondsetup + tools/build/build --ci autowiki + - name: Run Autowiki + if: steps.secrets_set.outputs.SECRETS_ENABLED + env: + USERNAME: ${{ secrets.AUTOWIKI_USERNAME }} + PASSWORD: ${{ secrets.AUTOWIKI_PASSWORD }} + run: | + cd tools/autowiki + npm install + cd ../.. + node tools/autowiki/autowiki.js data/autowiki_edits.txt data/autowiki_files/ diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index 2ce412ec1f07..683f3909b447 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -8,7 +8,7 @@ jobs: run_linters: if: "!contains(github.event.head_commit.message, '[ci skip]')" name: Run Linters - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest concurrency: group: run_linters-${{ github.head_ref || github.run_id }} cancel-in-progress: true @@ -63,7 +63,7 @@ jobs: compile_all_maps: if: "!contains(github.event.head_commit.message, '[ci skip]')" name: Compile Maps - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Restore BYOND cache @@ -80,9 +80,10 @@ jobs: find_all_maps: if: "!contains(github.event.head_commit.message, '[ci skip]')" name: Find Maps to Test - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest outputs: maps: ${{ steps.map_finder.outputs.maps }} + alternate_tests: ${{ steps.alternate_test_finder.outputs.alternate_tests }} concurrency: group: find_all_maps-${{ github.head_ref || github.run_id }} cancel-in-progress: true @@ -91,10 +92,16 @@ jobs: - name: Find Maps id: map_finder run: | - echo "$(ls -mw0 maps/*.json)" > maps_output.txt + shopt -s extglob + echo "$(ls -mw0 maps/!(*override*).json)" > maps_output.txt sed -i -e s+maps/+\"+g -e s+.json+\"+g maps_output.txt echo "Maps: $(cat maps_output.txt)" echo "maps={\"paths\":[$(cat maps_output.txt)]}" >> $GITHUB_OUTPUT + - name: Find Alternate Tests + id: alternate_test_finder + run: | + ALTERNATE_TESTS_JSON=$(jq -nRc '[inputs | capture("^(?[0-9]+)\\.(?[0-9]+): (?.+)$")]' .github/alternate_byond_versions.txt) + echo "alternate_tests=$ALTERNATE_TESTS_JSON" >> $GITHUB_OUTPUT run_all_tests: if: "!contains(github.event.head_commit.message, '[ci skip]')" name: Unit Tests @@ -109,3 +116,50 @@ jobs: uses: ./.github/workflows/run_unit_tests.yml with: map: ${{ matrix.map }} + + run_alternate_tests: + if: "!contains(github.event.head_commit.message, '[ci skip]') && needs.find_all_maps.outputs.alternate_tests != '[]'" + name: Alternate Tests + needs: [find_all_maps] + strategy: + fail-fast: false + matrix: + setup: ${{ fromJSON(needs.find_all_maps.outputs.alternate_tests) }} + concurrency: + group: run_all_tests-${{ github.head_ref || github.run_id }}-${{ matrix.setup.major }}.${{ matrix.setup.minor }}-${{ matrix.setup.map }} + cancel-in-progress: true + uses: ./.github/workflows/run_unit_tests.yml + with: + map: ${{ matrix.setup.map }} + major: ${{ matrix.setup.major }} + minor: ${{ matrix.setup.minor }} + + check_alternate_tests: + if: "!contains(github.event.head_commit.message, '[ci skip]') && needs.find_all_maps.outputs.alternate_tests != '[]'" + name: Check Alternate Tests + needs: [run_alternate_tests] + runs-on: ubuntu-latest + steps: + - run: echo Alternate tests passed. + + test_windows: + if: "!contains(github.event.head_commit.message, '[ci skip]')" + name: Windows Build + runs-on: windows-latest + concurrency: + group: test_windows-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + steps: + - uses: actions/checkout@v3 + - name: Restore Yarn cache + uses: actions/cache@v3 + with: + path: tgui/.yarn/cache + key: ${{ runner.os }}-yarn-${{ hashFiles('tgui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: Compile + run: pwsh tools/ci/build.ps1 + env: + DM_EXE: "C:\\byond\\bin\\dm.exe" diff --git a/.github/workflows/compile_changelogs.yml b/.github/workflows/compile_changelogs.yml index 1f6e72092627..85947f08b18b 100644 --- a/.github/workflows/compile_changelogs.yml +++ b/.github/workflows/compile_changelogs.yml @@ -8,7 +8,7 @@ on: jobs: compile: name: "Compile changelogs" - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps" id: value_holder diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml index 9e70bf488482..b65a5213ab4a 100644 --- a/.github/workflows/conflicts.yml +++ b/.github/workflows/conflicts.yml @@ -7,9 +7,11 @@ on: types: [ready_for_review, opened, synchronize, reopened] jobs: triage: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: eps1lon/actions-label-merge-conflict@v2.1.0 with: dirtyLabel: 'Merge Conflict' + commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request." + commentOnClean: "Conflicts have been resolved. A maintainer will review the pull request shortly." repoToken: ${{ secrets.BOT_TOKEN_CM || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/gbp.yml b/.github/workflows/gbp.yml deleted file mode 100644 index 9c92e5f379dc..000000000000 --- a/.github/workflows/gbp.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: GBP -on: - pull_request_target: - types: [closed, opened] -jobs: - gbp: - runs-on: ubuntu-latest - steps: - - name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps" - id: value_holder - env: - ENABLER_SECRET: ${{ secrets.ACTION_ENABLER }} - run: | - unset SECRET_EXISTS - if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi - echo "::set-output name=ACTIONS_ENABLED::$SECRET_EXISTS" - - name: Checkout - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v3 - - name: Setup git - if: steps.value_holder.outputs.ACTIONS_ENABLED - run: | - git config --global user.name "gbp-action" - git config --global user.email "<>" - - name: Checkout alternate branch - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v3 - with: - ref: "gbp-balances" # The branch name - path: gbp-balances - # This is to ensure we keep the gbp.toml from master - # without having to update our separate branch. - - name: Copy configuration - if: steps.value_holder.outputs.ACTIONS_ENABLED - run: cp ./.github/gbp.toml ./gbp-balances/.github/gbp.toml - - name: GBP action - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: tgstation/gbp-action@master - with: - branch: "gbp-balances" - directory: ./gbp-balances - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/gbp_collect.yml b/.github/workflows/gbp_collect.yml deleted file mode 100644 index dc2af17a12de..000000000000 --- a/.github/workflows/gbp_collect.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: GBP Collection -# Every hour at the :20 minute mark. GitHub tells us to pick odd hours, instead of just using the start. -on: - schedule: - - cron: "20 * * * *" - workflow_dispatch: -jobs: - gbp_collection: - runs-on: ubuntu-latest - steps: - - name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps" - id: value_holder - env: - ENABLER_SECRET: ${{ secrets.ACTION_ENABLER }} - run: | - unset SECRET_EXISTS - if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi - echo "::set-output name=ACTIONS_ENABLED::$SECRET_EXISTS" - - name: Checkout - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v3 - - name: Setup git - if: steps.value_holder.outputs.ACTIONS_ENABLED - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - - name: Checkout alternate branch - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v3 - with: - ref: "gbp-balances" # The branch name - path: gbp-balances - # This is to ensure we keep the gbp.toml from master - # without having to update our separate branch. - - name: Copy configuration - if: steps.value_holder.outputs.ACTIONS_ENABLED - run: cp ./.github/gbp.toml ./gbp-balances/.github/gbp.toml - - name: GBP action - if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: tgstation/gbp-action@master - with: - collect: "true" - directory: ./gbp-balances - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml index 6075e3029acd..c2898dfa9c57 100644 --- a/.github/workflows/generate_documentation.yml +++ b/.github/workflows/generate_documentation.yml @@ -6,7 +6,7 @@ on: jobs: generate_documentation: if: "!contains(github.event.head_commit.message, '[ci skip]')" - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest concurrency: gen-docs steps: - uses: actions/checkout@v3 @@ -21,7 +21,7 @@ jobs: run: | ~/dmdoc touch dmdoc/.nojekyll - echo codedocs.tgstation13.org > dmdoc/CNAME + echo docs.cm-ss13.com > dmdoc/CNAME - name: Deploy uses: JamesIves/github-pages-deploy-action@3.7.1 with: diff --git a/.github/workflows/remove_guide_comments.yml b/.github/workflows/remove_guide_comments.yml new file mode 100644 index 000000000000..d5d405909e21 --- /dev/null +++ b/.github/workflows/remove_guide_comments.yml @@ -0,0 +1,18 @@ +# Removes guide comments from PRs when opened, so that when we merge them +# and reuse the pull request description, the clutter is not left behind +name: Remove guide comments +on: + pull_request_target: + types: [opened] +jobs: + remove_guide_comments: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Remove guide comments + uses: actions/github-script@v6 + with: + script: | + const { removeGuideComments } = await import('${{ github.workspace }}/tools/pull_request_hooks/removeGuideComments.js') + await removeGuideComments({ github, context }) diff --git a/.github/workflows/run_approval.yml b/.github/workflows/run_approval.yml index 1708d41949f4..1d452c5f8aa7 100644 --- a/.github/workflows/run_approval.yml +++ b/.github/workflows/run_approval.yml @@ -1,11 +1,11 @@ name: Automatic Approve Workflows on: - schedule: + schedule: - cron: "*/10 * * * *" jobs: automatic-approve: name: Automatic Approve Workflows - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Automatic Approve uses: mheap/automatic-approve-action@v1 diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml index 6e2b2188eb52..539b0fa01082 100644 --- a/.github/workflows/run_unit_tests.yml +++ b/.github/workflows/run_unit_tests.yml @@ -15,7 +15,7 @@ on: type: string jobs: run_unit_tests: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Restore BYOND cache @@ -27,7 +27,7 @@ jobs: run: | sudo dpkg --add-architecture i386 sudo apt update || true - sudo apt install -o APT::Immediate-Configure=false libssl1.1:i386 + sudo apt install -o APT::Immediate-Configure=false zlib1g-dev:i386 libssl-dev:i386 bash tools/ci/install_rust_g.sh - name: Configure version run: | @@ -38,7 +38,7 @@ jobs: run: | bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup - tools/build/build --ci dm -DCIBUILDING -DANSICOLORS + tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -Werror - name: Run Tests run: | source $HOME/BYOND/byond/bin/byondsetup diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index fe2417ca3eb8..13cb50704387 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ on: jobs: stale: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/stale@v4 diff --git a/.github/workflows/update_changelog.yml b/.github/workflows/update_changelog.yml index b7d8702c5cc7..0b30a268d4aa 100644 --- a/.github/workflows/update_changelog.yml +++ b/.github/workflows/update_changelog.yml @@ -7,7 +7,7 @@ on: jobs: update-changelog: concurrency: changelog - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps" id: value_holder diff --git a/.github/workflows/update_tgs_dmapi.yml b/.github/workflows/update_tgs_dmapi.yml new file mode 100644 index 000000000000..b197e62f392f --- /dev/null +++ b/.github/workflows/update_tgs_dmapi.yml @@ -0,0 +1,47 @@ +name: Update TGS DMAPI + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +jobs: + update-dmapi: + runs-on: ubuntu-latest + name: Update the TGS DMAPI + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Branch + run: | + git branch -f tgs-dmapi-update + git checkout tgs-dmapi-update + git reset --hard master + + - name: Apply DMAPI update + uses: tgstation/tgs-dmapi-updater@v2 + with: + header-path: 'code/__DEFINES/tgs.dm' + library-path: 'code/modules/tgs' + + - name: Commit and Push + continue-on-error: true + run: | + git config user.name tgstation-server + git config user.email tgstation-server@users.noreply.github.com + git add . + git commit -m 'Update TGS DMAPI' + git push -f -u origin tgs-dmapi-update + + - name: Create Pull Request + uses: repo-sync/pull-request@v2 + if: ${{ success() }} + with: + source_branch: "tgs-dmapi-update" + destination_branch: "master" + pr_title: "Automatic TGS DMAPI Update" + pr_body: "This pull request updates the TGS DMAPI to the latest version. Please note any breaking or unimplemented changes before merging." + pr_label: "Tools" + pr_allow_empty: false + github_token: ${{ secrets.BOT_TOKEN_CM }} diff --git a/.tgs.yml b/.tgs.yml new file mode 100644 index 000000000000..ba3fc6b26c66 --- /dev/null +++ b/.tgs.yml @@ -0,0 +1,12 @@ +version: 1 +byond: "514.1588" +static_files: + - name: config + - name: data +linux_scripts: + PreCompile.sh: tools/tgs_scripts/PreCompile.sh + WatchdogLaunch.sh: tools/tgs_scripts/WatchdogLaunch.sh + InstallDeps.sh: tools/tgs_scripts/InstallDeps.sh +windows_scripts: + PreCompile.bat: tools/tgs_scripts/PreCompile.bat +security: Trusted diff --git a/.vscode/extensions.json b/.vscode/extensions.json index f836f1244940..6f4cf3dd8d31 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,12 +1,5 @@ { "recommendations": [ - "gbasood.byond-dm-language-support", - "platymuus.dm-langclient", - "arcanis.vscode-zipfs", - "EditorConfig.EditorConfig", - "anturk.dmi-editor", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "donkie.vscode-tgstation-test-adapter" + "cmss13-devs.cm-extpack" ] } diff --git a/BSQL.dll b/BSQL.dll deleted file mode 100644 index 22c29343d1bc..000000000000 Binary files a/BSQL.dll and /dev/null differ diff --git a/code/__DEFINES/ARES.dm b/code/__DEFINES/ARES.dm new file mode 100644 index 000000000000..ec84a6ab5992 --- /dev/null +++ b/code/__DEFINES/ARES.dm @@ -0,0 +1,63 @@ +/// Generic access for 1:1 conversations with ARES and unrestricted commands. +#define ARES_ACCESS_BASIC 0 +/// Secure Access, can read ARES Announcements and Bioscans. +#define ARES_ACCESS_COMMAND 1 +#define ARES_ACCESS_JOE 2 +/// CL, can read Apollo Log and also Delete Announcements. +#define ARES_ACCESS_CORPORATE 3 +/// Senior Command, can Delete Bioscans. +#define ARES_ACCESS_SENIOR 4 +/// Synth, CE & Commanding Officer, can read the access log. +#define ARES_ACCESS_CE 5 +#define ARES_ACCESS_SYNTH 6 +#define ARES_ACCESS_CO 7 +/// High Command, can read the deletion log. +#define ARES_ACCESS_HIGH 8 +#define ARES_ACCESS_WY_COMMAND 9 +/// Debugging. Allows me to view everything without using a high command rank. Unlikely to stay in a full merge. +#define ARES_ACCESS_DEBUG 10 + +#define ARES_RECORD_ANNOUNCE "Announcement Record" +#define ARES_RECORD_ANTIAIR "AntiAir Control Log" +#define ARES_RECORD_ASRS "Requisition Record" +#define ARES_RECORD_BIOSCAN "Bioscan Record" +#define ARES_RECORD_BOMB "Orbital Bombardment Record" +#define ARES_RECORD_DELETED "Deleted Record" +#define ARES_RECORD_SECURITY "Security Update" +#define ARES_RECORD_MAINTENANCE "Maintenance Ticket" +#define ARES_RECORD_ACCESS "Access Ticket" + +/// Not by ARES logged through marine_announcement() +#define ARES_LOG_NONE 0 +/// Logged with all announcements +#define ARES_LOG_MAIN 1 +/// Logged in the security updates +#define ARES_LOG_SECURITY 2 + +/// Access levels specifically for Working Joe management console +#define APOLLO_ACCESS_REQUEST 0 +#define APOLLO_ACCESS_REPORTER 1 +#define APOLLO_ACCESS_TEMP 2 +#define APOLLO_ACCESS_AUTHED 3 +#define APOLLO_ACCESS_JOE 4 +#define APOLLO_ACCESS_DEBUG 5 + +/// Ticket statuses, both for Access and Maintenance +/// Pending assignment/rejection +#define TICKET_PENDING "pending" +/// Assigned to a WJ +#define TICKET_ASSIGNED "assigned" +/// Cancelled by reporter +#define TICKET_CANCELLED "cancelled" +/// Rejected by WJs +#define TICKET_REJECTED "rejected" +/// Completed by WJs +#define TICKET_COMPLETED "completed" + +/// Checks for if buttons can be used, these may yet be removed and internalised to the UI programming +#define TICKET_OPEN "OPEN" +#define TICKET_CLOSED "CLOSED" + +/// Cooldowns +#define COOLDOWN_ARES_SENSOR 60 SECONDS +#define COOLDOWN_ARES_ACCESS_CONTROL 20 SECONDS diff --git a/code/__DEFINES/__game.dm b/code/__DEFINES/__game.dm index adaa767c28b4..113b78dbada1 100644 --- a/code/__DEFINES/__game.dm +++ b/code/__DEFINES/__game.dm @@ -39,6 +39,7 @@ block( \ #define MAP_RUNTIME "USS Runtime" #define MAP_LV522_CHANCES_CLAIM "LV-522 Chance's Claim" // Highpop Only #define MAP_NEW_VARADERO "New Varadero"//ice colony underground but as its own map +#define MAP_CHINOOK "Chinook 91 GSO" //admin level #define GAMEMODE_WHISKEY_OUTPOST "Whiskey Outpost" #define GAMEMODE_HIVE_WARS "Hive Wars" @@ -106,6 +107,7 @@ block( \ #define SOUND_REBOOT (1<<5) #define SOUND_ADMIN_MEME (1<<6) #define SOUND_ADMIN_ATMOSPHERIC (1<<7) +#define SOUND_ARES_MESSAGE (1<<8) //toggles_chat #define CHAT_OOC (1<<0) @@ -390,6 +392,7 @@ block( \ #define FIRE_MISSION_WEAPON_REMOVED 8 #define FIRE_MISSION_WEAPON_UNUSABLE 16 #define FIRE_MISSION_WEAPON_OUT_OF_AMMO 32 +#define FIRE_MISSION_NOT_EXECUTABLE -1 //Defines for firemission state #define FIRE_MISSION_STATE_IDLE 0 diff --git a/code/__DEFINES/__rust_g.dm b/code/__DEFINES/__rust_g.dm index c6a73b5531cf..6c1b5c2d3ffa 100644 --- a/code/__DEFINES/__rust_g.dm +++ b/code/__DEFINES/__rust_g.dm @@ -101,6 +101,14 @@ #define rustg_noise_get_at_coordinates(seed, x, y) RUSTG_CALL(RUST_G, "noise_get_at_coordinates")(seed, x, y) +#define RUSTG_REDIS_ERROR_CHANNEL "RUSTG_REDIS_ERROR_CHANNEL" + +#define rustg_redis_connect(addr) RUSTG_CALL(RUST_G, "redis_connect")(addr) +/proc/rustg_redis_disconnect() return RUSTG_CALL(RUST_G, "redis_disconnect")() +#define rustg_redis_subscribe(channel) RUSTG_CALL(RUST_G, "redis_subscribe")(channel) +/proc/rustg_redis_get_messages() return RUSTG_CALL(RUST_G, "redis_get_messages")() +#define rustg_redis_publish(channel, message) RUSTG_CALL(RUST_G, "redis_publish")(channel, message) + #define rustg_sql_connect_pool(options) RUSTG_CALL(RUST_G, "sql_connect_pool")(options) #define rustg_sql_query_async(handle, query, params) RUSTG_CALL(RUST_G, "sql_query_async")(handle, query, params) #define rustg_sql_query_blocking(handle, query, params) RUSTG_CALL(RUST_G, "sql_query_blocking")(handle, query, params) diff --git a/code/__DEFINES/__spacemandmm.dm b/code/__DEFINES/__spacemandmm.dm index f78495968ee4..b62bbee4259a 100644 --- a/code/__DEFINES/__spacemandmm.dm +++ b/code/__DEFINES/__spacemandmm.dm @@ -34,6 +34,9 @@ /proc/enable_debugging(mode, port) CRASH("auxtools not loaded") +/proc/auxtools_expr_stub() + CRASH("auxtools not loaded") + /world/Del() var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") if (debug_server) diff --git a/code/__DEFINES/_macros.dm b/code/__DEFINES/_macros.dm index 9f1dbd932cde..31f4b2aca084 100644 --- a/code/__DEFINES/_macros.dm +++ b/code/__DEFINES/_macros.dm @@ -8,12 +8,17 @@ #define subtypesof(A) (typesof(A) - A) +#ifdef EXPERIMENT_515_DONT_CACHE_REF +/// Takes a datum as input, returns its ref string +#define text_ref(datum) ref(datum) +#else /// Takes a datum as input, returns its ref string, or a cached version of it /// This allows us to cache \ref creation, which ensures it'll only ever happen once per datum, saving string tree time /// It is slightly less optimal then a []'d datum, but the cost is massively outweighed by the potential savings /// It will only work for datums mind, for datum reasons /// : because of the embedded typecheck #define text_ref(datum) (isdatum(datum) ? (datum:cached_ref ||= "\ref[datum]") : ("\ref[datum]")) +#endif #define addToListNoDupe(L, index) if(L) L[index] = null; else L = list(index) diff --git a/code/__DEFINES/_tick.dm b/code/__DEFINES/_tick.dm index fddf34202315..385e409682eb 100644 --- a/code/__DEFINES/_tick.dm +++ b/code/__DEFINES/_tick.dm @@ -1,3 +1,5 @@ +#define MAPTICK_LAST_INTERNAL_TICK_USAGE (world.map_cpu) + /// Tick limit while running normally #define TICK_BYOND_RESERVE 2 #define TICK_LIMIT_RUNNING 80 diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index e15cfb156eb8..97e4b0dbd1e8 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -35,15 +35,27 @@ most of them are tied into map-placed objects. This should be reworked in the fu #define ACCESS_MARINE_RESEARCH 28 #define ACCESS_MARINE_SEA 29 #define ACCESS_MARINE_KITCHEN 30 -#define ACCESS_MARINE_CAPTAIN 31 -#define ACCESS_MARINE_RTO_PREP 32 +#define ACCESS_MARINE_CO 31 +#define ACCESS_MARINE_TL_PREP 32 #define ACCESS_MARINE_MAINT 34 #define ACCESS_MARINE_OT 35 #define ACCESS_MARINE_SYNTH 36 +#define ACCESS_MARINE_ASO 37 +#define ACCESS_MARINE_CHAPLAIN 38 -//Surface access levels +// AI Core Accesses +/// Used in temporary passes +#define ACCESS_MARINE_AI_TEMP 90 +/// Used as dedicated access to ARES Core. +#define ACCESS_MARINE_AI 91 +/// Used to access Maintenance Protocols on ARES Interface. +#define ACCESS_ARES_DEBUG 92 + +//================================================= + +//Civilian access levels #define ACCESS_CIVILIAN_PUBLIC 100 #define ACCESS_CIVILIAN_LOGISTICS 101 #define ACCESS_CIVILIAN_ENGINEERING 102 @@ -51,15 +63,138 @@ most of them are tied into map-placed objects. This should be reworked in the fu #define ACCESS_CIVILIAN_BRIG 104 #define ACCESS_CIVILIAN_MEDBAY 105 #define ACCESS_CIVILIAN_COMMAND 106 +#define ACCESS_PRESS 110 + +///The generic "I'm a bad guy" access +#define ACCESS_ILLEGAL_PIRATE 120 + +//================================================= + +//Weyland Yutani access levels (200-229) +///Found on just about all corporate ID cards +#define ACCESS_WY_GENERAL 200 +///WY employee override for most colonial areas +#define ACCESS_WY_COLONIAL 201 +#define ACCESS_WY_MEDICAL 202 +#define ACCESS_WY_SECURITY 203 +#define ACCESS_WY_ENGINEERING 204 +#define ACCESS_WY_FLIGHT 205 +#define ACCESS_WY_RESEARCH 206 +///WY access given to field executives, like a marine liaison. +#define ACCESS_WY_EXEC 207 + +#define ACCESS_WY_PMC 210 +#define ACCESS_WY_PMC_TL 211 +#define ACCESS_WY_ARMORY 212 +///Secret research or other projects with highly restricted access +#define ACCESS_WY_SECRETS 213 + +#define ACCESS_WY_LEADERSHIP 215 +///Senior leadership, the highest ranks +#define ACCESS_WY_SENIOR_LEAD 216 + +//================================================= + +//Union of Progressive Peoples access levels (230-259) +///Found on just about all Union ID cards +#define ACCESS_UPP_GENERAL 230 +#define ACCESS_UPP_MEDICAL 231 +#define ACCESS_UPP_ENGINEERING 232 +#define ACCESS_UPP_SECURITY 233 +#define ACCESS_UPP_ARMORY 234 +#define ACCESS_UPP_FLIGHT 235 +#define ACCESS_UPP_RESEARCH 236 + +#define ACCESS_UPP_COMMANDO 239 +#define ACCESS_UPP_LEADERSHIP 240 +///Senior leadership, the highest ranks +#define ACCESS_UPP_SENIOR_LEAD 241 -//Special access levels. Should be alright to modify these. -#define ACCESS_WY_PMC_GREEN 180 -#define ACCESS_WY_PMC_ORANGE 181 -#define ACCESS_WY_PMC_RED 182 -#define ACCESS_WY_PMC_BLACK 183 -#define ACCESS_WY_PMC_WHITE 184 -#define ACCESS_WY_CORPORATE 200 -#define ACCESS_ILLEGAL_PIRATE 201 -#define ACCESS_WY_CORPORATE_DS 202 -#define ACCESS_PRESS 203 //================================================= + +//Colonial Liberation Front access levels (260-289) +///Found on just about all CLF ID cards +#define ACCESS_CLF_GENERAL 260 +#define ACCESS_CLF_MEDICAL 261 +#define ACCESS_CLF_ENGINEERING 262 +#define ACCESS_CLF_SECURITY 263 +#define ACCESS_CLF_ARMORY 264 +#define ACCESS_CLF_FLIGHT 265 + +#define ACCESS_CLF_LEADERSHIP 270 +///Senior leadership, the highest ranks +#define ACCESS_CLF_SENIOR_LEAD 271 + +//================================================= + +//Three World Empire access levels (290-319) +///Found on just about all Imperial ID cards +#define ACCESS_TWE_GENERAL 290 +#define ACCESS_TWE_MEDICAL 291 +#define ACCESS_TWE_ENGINEERING 292 +#define ACCESS_TWE_SECURITY 293 +#define ACCESS_TWE_ARMORY 294 +#define ACCESS_TWE_FLIGHT 295 +#define ACCESS_TWE_RESEARCH 296 + +#define ACCESS_TWE_COMMANDO 299 +#define ACCESS_TWE_LEADERSHIP 300 +///Senior leadership, the highest ranks +#define ACCESS_TWE_SENIOR_LEAD 301 + +//================================================= + +// Yautja Access Levels +/// Requires a visible ID chip to open +#define ACCESS_YAUTJA_SECURE 390 +/// Elders+ only +#define ACCESS_YAUTJA_ELDER 391 +/// Ancients only +#define ACCESS_YAUTJA_ANCIENT 392 + +///Temporary, just so I can flag places I need to change +#define ACCESS_COME_BACK_TO_ME 999 + + +//Big lists of access codes, so I can get rid of the half a million different "get_bla_bla_bla_access" procs. +//See /proc/get_access(access_list = ACCESS_LIST_GLOBAL) +///Well... everything (non Yautja). +#define ACCESS_LIST_GLOBAL "EVERYTHING" + +///Most of the USCM Access Levels used on the USS Almayer, excluding highly restricted ones. +#define ACCESS_LIST_MARINE_MAIN "Almayer (Main)" +///All USCM Access levels used on the USS Almayer +#define ACCESS_LIST_MARINE_ALL "Almayer (ALL)" +///Used by the Wey-Yu - USCM Liaison +#define ACCESS_LIST_MARINE_LIAISON "Wey-Yu (Liaison)" + +///The accesses granted to emergency responders. +#define ACCESS_LIST_EMERGENCY_RESPONSE "Almayer (ERT)" +///Access used by United Americas responders. +#define ACCESS_LIST_UA "United Americas" + +///Generic/basic access to Wey-Yu stuff +#define ACCESS_LIST_WY_BASE "Wey-Yu (Basic)" +///Wey-Yu Corp Security access. +#define ACCESS_LIST_WY_GOON "Wey-Yu (Goons)" +///Wey-Yu PMCs access. +#define ACCESS_LIST_WY_PMC "Wey-Yu (PMC)" +///Access levels for WY senior leadership +#define ACCESS_LIST_WY_SENIOR "Wey-Yu (Senior Lead)" +///All access levels associated with Weyland Yutani +#define ACCESS_LIST_WY_ALL "Wey-Yu (ALL)" + +///All the access levels in the civillian category, excluding Press. +#define ACCESS_LIST_COLONIAL_ALL "Colonial (ALL)" +///Used by the Wey-Yu - Civil Authority Liaison +#define ACCESS_LIST_CIVIL_LIAISON "Colonial (Liaison)" +///The access used by delivery ERT (Pizza/Souto) +#define ACCESS_LIST_DELIVERY "Delivery" + +///All access levels associated with UPP +#define ACCESS_LIST_UPP_ALL "UPP (ALL)" + +///Generic/basic access to CLF stuff +#define ACCESS_LIST_CLF_BASE "CLF (Basic)" +///All access levels associated with CLF +#define ACCESS_LIST_CLF_ALL "CLF (ALL)" diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index f6f04969b41b..6844721cd7f0 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -2,10 +2,6 @@ #define DMM_COORDINATE_COMMAND "//coord" -/atom/proc/Admin_Coordinates_Readable(area_name, admin_jump_ref) - var/turf/T = get_turf(src) - return T ? "[area_name ? "[get_area_name(T, TRUE)] " : " "]([T.x],[T.y],[T.z])" : "nonexistent location" - ///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 @@ -31,6 +27,7 @@ var/global/list/note_categories = list("Admin", "Merit", "Commanding Officer", " #define ADMIN_FLW(user) "(FLW)" #define ADMIN_PP(user) "(PP)" #define ADMIN_VV(atom) "(VV)" +#define ADMIN_PM(client) client ? "(PM)" : "(NO CLIENT)" #define ADMIN_SM(user) "(SM)" #define ADMIN_NOTES(user) "(N)" #define ADMIN_CL(user) "(CL)" @@ -41,12 +38,23 @@ var/global/list/note_categories = list("Admin", "Merit", "Commanding Officer", " #define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_PP(user)] [ADMIN_NOTES(user)] [ADMIN_VV(user)] [ADMIN_CL(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)]" #define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" #define ADMIN_JMP(src) "(JMP)" +#define ADMIN_JMP_USER(user) "(JMP)" #define COORD(src) "[src ? src.Admin_Coordinates_Readable() : "nonexistent location"]" #define AREACOORD(src) "[src ? src.Admin_Coordinates_Readable(TRUE) : "nonexistent location"]" #define ADMIN_COORDJMP(src) "[src ? src.Admin_Coordinates_Readable(FALSE, TRUE) : "nonexistent location"]" #define ADMIN_VERBOSEJMP(src) "[src ? src.Admin_Coordinates_Readable(TRUE, TRUE) : "nonexistent location"]" #define ADMIN_INDIVIDUALLOG(user) "(LOGS)" -#define ADMIN_TAG(datum) "(TAG)" +#define ADMIN_TAG(datum) "(TAG)" +#define CC_MARK(user) "(MARK)" +#define CC_REPLY(user) "(RPLY)" +#define OBSERVER_JMP(observer, atom) atom ? "(JMP)" : "" +#define ARES_MARK(user) "(MARK)" +#define ARES_REPLY(user, ref) "(RPLY)" + +/atom/proc/Admin_Coordinates_Readable(area_name, admin_jump_ref) + var/turf/T = get_turf(src) + var/msg = T ? "[area_name ? "[get_area_name(T, TRUE)] " : " "]([T.x],[T.y],[T.z])" : "nonexistent location" + return T && admin_jump_ref ? "[msg] [ADMIN_JMP(T)]" : msg /// for [/proc/check_asay_links], if there are any actionable refs in the asay message, this index in the return list contains the new message text to be printed #define ASAY_LINK_NEW_MESSAGE_INDEX "!asay_new_message" @@ -63,3 +71,6 @@ var/global/list/note_categories = list("Admin", "Merit", "Commanding Officer", " #define ANTIGRIEF_NEW_PLAYERS 1 /// Enables antigrief entirely: Nobody can activate explosives on the Almayer, unless the ship crashed. #define ANTIGRIEF_ENABLED 2 + +/// Proc has been blocked by IsAdminAdvancedProcCall() +#define PROC_BLOCKED "PROCCALL BLOCKED" diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index 5869650da273..fcc3e7784cb5 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -37,3 +37,7 @@ /// This was a define, but I changed it to a variable so it can be changed in-game.(kept the all-caps definition because... code...) -Errorage var/MAX_EXPLOSION_RANGE = 14 + +/// Used in /obj/structure/pipes/vents/proc/create_gas +#define VENT_GAS_SMOKE "Smoke" +#define VENT_GAS_CN20 "CN20 Nerve Gas" diff --git a/code/__DEFINES/autofire.dm b/code/__DEFINES/autofire.dm new file mode 100644 index 000000000000..934cdcd7dc79 --- /dev/null +++ b/code/__DEFINES/autofire.dm @@ -0,0 +1,4 @@ +// Controls how many buckets should be kept, each representing a tick. Max is ten seconds, to have better perf. +#define AUTOFIRE_BUCKET_LEN (world.fps * 10) +/// Helper for getting the correct bucket +#define AUTOFIRE_BUCKET_POS(next_fire) (((round((next_fire - SSautomatedfire.head_offset) / world.tick_lag) + 1) % AUTOFIRE_BUCKET_LEN) || AUTOFIRE_BUCKET_LEN) diff --git a/code/__DEFINES/blood.dm b/code/__DEFINES/blood.dm index 8f63521caac7..b0d7ce2daf43 100644 --- a/code/__DEFINES/blood.dm +++ b/code/__DEFINES/blood.dm @@ -4,3 +4,16 @@ #define BLOOD_FEET (1<<2) #define BLOOD_ALL (BLOOD_BODY|BLOOD_HANDS|BLOOD_FEET) + +#define BLOOD_COLOR_HUMAN "#A10808" +#define BLOOD_COLOR_SYNTHETIC "#EEEEEE" + +#define BLOOD_COLOR_NEAERA "#1d2cbf" + +#define BLOOD_COLOR_XENO "#dffc00" +#define BLOOD_COLOR_XENO_ROYAL "#bbb900" + +#define BLOOD_COLOR_YAUTJA "#20d450" +#define BLOOD_COLOR_YAUTJA_DARK "#5A934A" + +#define BLOOD_COLOR_ZOMBIE "#333333" diff --git a/code/__DEFINES/bsql.dm b/code/__DEFINES/bsql.dm deleted file mode 100644 index 7200984eb01d..000000000000 --- a/code/__DEFINES/bsql.dm +++ /dev/null @@ -1,125 +0,0 @@ -//BSQL - DMAPI -#define BSQL_VERSION "v1.3.0.0" - -//types of connections -#define BSQL_CONNECTION_TYPE_MARIADB "MySql" -#define BSQL_CONNECTION_TYPE_SQLSERVER "SqlServer" - -#define BSQL_DEFAULT_TIMEOUT 5 -#define BSQL_DEFAULT_THREAD_LIMIT 50 - -//Call this before rebooting or shutting down your world to clean up gracefully. This invalidates all active connection and operation datums -/world/proc/BSQL_Shutdown() - return - -/* -Called whenever a library call is made with verbose information, override and do with as you please -message: English debug message -*/ -/world/proc/BSQL_Debug(msg) - return - -/* -Create a new database connection, does not perform the actual connect -connection_type: The BSQL connection_type to use -asyncTimeout: The timeout to use for normal operations, 0 for infinite, defaults to BSQL_DEFAULT_TIMEOUT -blockingTimeout: The timeout to use for blocking operations, must be less than or equal to asyncTimeout, 0 for infinite, defaults to asyncTimeout -threadLimit: The limit of additional threads BSQL will run simultaneously, defaults to BSQL_DEFAULT_THREAD_LIMIT -*/ -/datum/BSQL_Connection/New(connection_type, asyncTimeout, blockingTimeout, threadLimit) - return ..() - -/* -Starts an operation to connect to a database. Should only have 1 successful call -ipaddress: The ip/hostname of the target server -port: The port of the target server -username: The username to login to the target server -password: The password for the target server -database: Optional database to connect to. Must be used when trying to do database operations, `USE x` is not sufficient - Returns: A /datum/BSQL_Operation representing the connection or null if an error occurred -*/ -/datum/BSQL_Connection/proc/BeginConnect(ipaddress, port, username, password, database) - return - -/* -Properly quotes a string for use by the database. The connection must be open for this proc to succeed -str: The string to quote - Returns: The string quoted on success, null on error -*/ -/datum/BSQL_Connection/proc/Quote(str) - return - -/* -Starts an operation for a query -query: The text of the query. Only one query allowed per invocation, no semicolons - Returns: A /datum/BSQL_Operation/Query representing the running query and subsequent result set or null if an error occurred - Note for MariaDB: The underlying connection is pooled. In order to use connection state based properties (i.e. LAST_INSERT_ID()) you can guarantee multiple queries will use the same connection by running BSQL_DEL_CALL(query) on the finished /datum/BSQL_Operation/Query and then creating the next one with another call to BeginQuery() with no sleeps in between -*/ -/datum/BSQL_Connection/proc/BeginQuery(query) - return - -/* -Checks if the operation is complete. This, in some cases must be called multiple times with false return before a result is present regardless of timespan. For best performance check it once per tick - Returns: TRUE if the operation is complete, FALSE if it's not, null on error -*/ -/datum/BSQL_Operation/proc/IsComplete() - return - -/* -Blocks the entire game until the given operation completes. IsComplete should not be checked after calling this to avoid potential side effects. -Returns: TRUE on success, FALSE if the operation wait time exceeded the connection's blockingTimeout setting -*/ -/datum/BSQL_Operation/proc/WaitForCompletion() - return - -/* -Get the error message associated with an operation. Should not be used while IsComplete() returns FALSE - Returns: The error message, if any. null otherwise -*/ -/datum/BSQL_Operation/proc/GetError() - return - -/* -Get the error code associated with an operation. Should not be used while IsComplete() returns FALSE - Returns: The error code, if any. null otherwise -*/ -/datum/BSQL_Operation/proc/GetErrorCode() - return - -/* -Gets an associated list of column name -> value representation of the most recent row in the query. Only valid if IsComplete() returns TRUE. If this returns null and no errors are present there are no more results in the query. Important to note that once IsComplete() returns TRUE it must not be called again without checking this or the row values may be lost - Returns: An associated list of column name -> value for the row. Values will always be either strings or null -*/ -/datum/BSQL_Operation/Query/proc/CurrentRow() - return - - -/* -Code configuration options below -Define this to avoid modifying this file but the following defines must be declared somewhere else before BSQL/includes.dm is included -*/ -#ifndef BSQL_EXTERNAL_CONFIGURATION - -//Modify this if you disagree with byond's GC schemes. Ensure this is called for all connections and operations when they are deleted or they will leak native resources until /world/proc/BSQL_Shutdown() is called -#define BSQL_DEL_PROC(path) ##path/Del() - -//The equivalent of calling del() in your codebase -#define BSQL_DEL_CALL(obj) del(##obj) - -//Returns TRUE if an object is delete -#define BSQL_IS_DELETED(obj) (obj == null) - -//Modify this to add protections to the connection and query datums -#define BSQL_PROTECT_DATUM(path) - -//Modify this to change up error handling for the library -#define BSQL_ERROR(message) CRASH("BSQL: [##message]") - -#endif - -/* -Copyright 2018 Jordan Brown -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. -*/ diff --git a/code/__DEFINES/camera.dm b/code/__DEFINES/camera.dm index 58b1b8acbd84..9d797b964d61 100644 --- a/code/__DEFINES/camera.dm +++ b/code/__DEFINES/camera.dm @@ -6,6 +6,7 @@ #define CAMERA_NET_ALAMO "Alamo" #define CAMERA_NET_NORMANDY "Normandy" #define CAMERA_NET_COLONY "Colony" +#define CAMERA_NET_ARES "ARES" #define CAMERA_NET_MILITARY "Military" #define CAMERA_NET_OVERWATCH "Overwatch" diff --git a/code/__DEFINES/chat.dm b/code/__DEFINES/chat.dm index c21cb94b0140..85966e4032e2 100644 --- a/code/__DEFINES/chat.dm +++ b/code/__DEFINES/chat.dm @@ -15,6 +15,7 @@ #define MESSAGE_TYPE_ADMINCHAT "adminchat" #define MESSAGE_TYPE_MODCHAT "modchat" #define MESSAGE_TYPE_MENTOR "mentor" +#define MESSAGE_TYPE_STAFF_IC "staff_ic" #define MESSAGE_TYPE_EVENTCHAT "eventchat" #define MESSAGE_TYPE_ADMINLOG "adminlog" #define MESSAGE_TYPE_ATTACKLOG "attacklog" diff --git a/code/__DEFINES/chemistry.dm b/code/__DEFINES/chemistry.dm index 81031200b51c..078ccbdc2d94 100644 --- a/code/__DEFINES/chemistry.dm +++ b/code/__DEFINES/chemistry.dm @@ -49,6 +49,7 @@ // Nutrition levels #define NUTRITION_MAX 550 +#define NUTRITION_HIGH 540 #define NUTRITION_NORMAL 400 #define NUTRITION_LOW 250 #define NUTRITION_VERYLOW 50 @@ -82,6 +83,7 @@ #define CHEM_EFFECT_RESIST_NEURO (1<<1) #define CHEM_EFFECT_HYPER_THROTTLE (1<<2) //universal understand but not speech #define CHEM_EFFECT_ORGAN_STASIS (1<<3) //peri stabiliser +#define CHEM_EFFECT_NO_BLEEDING (1<<4) //replacement for quickclot //Blood plasma @@ -156,6 +158,8 @@ #define PROPERTY_NEOGENETIC "neogenetic" #define PROPERTY_REPAIRING "repairing" #define PROPERTY_HEMOGENIC "hemogenic" +#define PROPERTY_YAUTJA_HEMOGENIC "yautja-hemogenic" +#define PROPERTY_HEMOSTATIC "hemostatic" #define PROPERTY_NERVESTIMULATING "nerve-stimulating" #define PROPERTY_MUSCLESTIMULATING "muscle-stimulating" #define PROPERTY_PAINKILLING "painkilling" diff --git a/code/__DEFINES/clans.dm b/code/__DEFINES/clans.dm index 54c9d11616e5..1b95d11c030c 100644 --- a/code/__DEFINES/clans.dm +++ b/code/__DEFINES/clans.dm @@ -49,14 +49,14 @@ /// Scales with clan size #define CLAN_LIMIT_SIZE 2 -var/global/list/datum/rank/clan_ranks = list( - CLAN_RANK_UNBLOODED = new /datum/rank/unblooded(), - CLAN_RANK_YOUNG = new /datum/rank/young(), - CLAN_RANK_BLOODED = new /datum/rank/blooded(), - CLAN_RANK_ELITE = new /datum/rank/elite(), - CLAN_RANK_ELDER = new /datum/rank/elder(), - CLAN_RANK_LEADER = new /datum/rank/leader(), - CLAN_RANK_ADMIN = new /datum/rank/ancient() +var/global/list/datum/yautja_rank/clan_ranks = list( + CLAN_RANK_UNBLOODED = new /datum/yautja_rank/unblooded(), + CLAN_RANK_YOUNG = new /datum/yautja_rank/young(), + CLAN_RANK_BLOODED = new /datum/yautja_rank/blooded(), + CLAN_RANK_ELITE = new /datum/yautja_rank/elite(), + CLAN_RANK_ELDER = new /datum/yautja_rank/elder(), + CLAN_RANK_LEADER = new /datum/yautja_rank/leader(), + CLAN_RANK_ADMIN = new /datum/yautja_rank/ancient() ) var/global/list/clan_ranks_ordered = list( diff --git a/code/__DEFINES/client_prefs.dm b/code/__DEFINES/client_prefs.dm new file mode 100644 index 000000000000..b1e194354555 --- /dev/null +++ b/code/__DEFINES/client_prefs.dm @@ -0,0 +1,34 @@ +#define BE_ALIEN_AFTER_DEATH (1<<0) +#define BE_AGENT (1<<1) + +#define TOGGLE_IGNORE_SELF (1<<0) // Determines whether you will not hurt yourself when clicking yourself +#define TOGGLE_HELP_INTENT_SAFETY (1<<1) // Determines whether help intent will be completely harmless +#define TOGGLE_MIDDLE_MOUSE_CLICK (1<<2) // This toggles whether selected ability for xeno uses middle mouse clicking or shift clicking +#define TOGGLE_DIRECTIONAL_ATTACK (1<<3) // This toggles whether attacks for xeno use directional attacks +#define TOGGLE_AUTO_EJECT_MAGAZINE_OFF (1<<4) // This toggles whether guns with auto ejectors will not auto eject their magazines + // MUTUALLY EXCLUSIVE TO TOGGLE_AUTO_EJECT_MAGAZINE_TO_HAND +#define TOGGLE_AUTO_EJECT_MAGAZINE_TO_HAND (1<<5) // This toggles whether guns with auto ejectors will cause you to unwield your gun and put the empty magazine in your hand + // MUTUALLY EXCLUSIVE TO TOGGLE_AUTO_EJECT_MAGAZINE +#define TOGGLE_EJECT_MAGAZINE_TO_HAND (1<<6) // This toggles whether manuallye jecting magazines from guns will cause you to unwield your gun + // and put the empty magazine in your hand +#define TOGGLE_AUTOMATIC_PUNCTUATION (1<<7) // Whether your sentences will automatically be punctuated with a period +#define TOGGLE_COMBAT_CLICKDRAG_OVERRIDE (1<<8) // Whether disarm/harm intents cause clicks to trigger immediately when the mouse button is depressed. +#define TOGGLE_ALTERNATING_DUAL_WIELD (1<<9) // Whether dual-wielding fires both guns at once or swaps between them. +#define TOGGLE_FULLSCREEN (1<<10) // See /client/proc/toggle_fullscreen in client_procs.dm +#define TOGGLE_MEMBER_PUBLIC (1<<11) //determines if you get a byond logo by your name in ooc if you're a member or not +#define TOGGLE_OOC_FLAG (1<<12) // determines if your country flag appears by your name in ooc chat +#define TOGGLE_MIDDLE_MOUSE_SWAP_HANDS (1<<13) //Toggle whether middle click swaps your hands +#define TOGGLE_AMBIENT_OCCLUSION (1<<14) // toggles if ambient occlusion is turned on or off +#define TOGGLE_VEND_ITEM_TO_HAND (1<<15) // This toggles whether items from vendors will be automatically put into your hand. +#define TOGGLE_START_JOIN_CURRENT_SLOT (1<<16) // Whether joining at roundstart ignores assigned character slot for the job and uses currently selected slot. +#define TOGGLE_LATE_JOIN_CURRENT_SLOT (1<<17) //Whether joining during the round ignores assigned character slot for the job and uses currently selected slot. +#define TOGGLE_ABILITY_DEACTIVATION_OFF (1<<18) // This toggles whether selecting the same ability again can toggle it off + +#define JOB_SLOT_RANDOMISED_SLOT -1 +#define JOB_SLOT_CURRENT_SLOT 0 +#define JOB_SLOT_RANDOMISED_TEXT "Randomise name and appearance" +#define JOB_SLOT_CURRENT_TEXT "Current character" + +#define AGE_MIN 19 //youngest a character can be +#define AGE_MAX 90 //oldest a character can be //no. you are not allowed to be 160. +#define MAX_GEAR_COST 7 //Used in chargen for loadout limit. diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 71c659054952..31df07648fc0 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -18,3 +18,20 @@ //the define for visible message range in combat #define COMBAT_MESSAGE_RANGE 3 #define DEFAULT_MESSAGE_RANGE 7 + +#define BAYONET_DRAW_DELAY (1 SECONDS) + +//Predator decloak multpliers based on the standard. +#define DECLOAK_STANDARD (10 SECONDS) +/// Forced for any unspecified reason. +#define DECLOAK_FORCED 1 +/// Caused by being worn by non humans. +#define DECLOAK_SPECIES 0.75 +/// Caused by fire extinguisher. +#define DECLOAK_EXTINGUISHER 1.5 +/// Caused by predalien screech. +#define DECLOAK_PREDALIEN 2 +/// Caused by being in a body of water. +#define DECLOAK_SUBMERGED 2 +/// Caused by an EMP. +#define DECLOAK_EMP 3 diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm index d288310406c7..30b2627bb1b0 100644 --- a/code/__DEFINES/conflict.dm +++ b/code/__DEFINES/conflict.dm @@ -54,30 +54,24 @@ #define GUN_TRIGGER_SAFETY (1<<1) #define GUN_UNUSUAL_DESIGN (1<<2) #define GUN_SILENCED (1<<3) -#define GUN_AUTOMATIC (1<<4) ///If checking for ammo with current.mag you have to check it against numerical values, as booleans will not trigger. -#define GUN_INTERNAL_MAG (1<<5) -#define GUN_AUTO_EJECTOR (1<<6) -#define GUN_AMMO_COUNTER (1<<7) -#define GUN_BURST_ON (1<<8) -#define GUN_BURST_FIRING (1<<9) -#define GUN_FLASHLIGHT_ON (1<<10) -#define GUN_WY_RESTRICTED (1<<11) -#define GUN_SPECIALIST (1<<12) -#define GUN_WIELDED_FIRING_ONLY (1<<13) -#define GUN_HAS_FULL_AUTO (1<<14) -#define GUN_FULL_AUTO_ON (1<<15) +#define GUN_INTERNAL_MAG (1<<4) +#define GUN_AUTO_EJECTOR (1<<5) +#define GUN_AMMO_COUNTER (1<<6) +#define GUN_BURST_FIRING (1<<7) +#define GUN_FLASHLIGHT_ON (1<<8) +#define GUN_WY_RESTRICTED (1<<9) +#define GUN_SPECIALIST (1<<10) +#define GUN_WIELDED_FIRING_ONLY (1<<11) /// removes unwielded accuracy and scatter penalties (not recoil) -#define GUN_ONE_HAND_WIELDED (1<<16) -#define GUN_ANTIQUE (1<<17) +#define GUN_ONE_HAND_WIELDED (1<<12) +#define GUN_ANTIQUE (1<<13) /// Whether the gun has been fired by its current user (reset upon `dropped()`) -#define GUN_RECOIL_BUILDUP (1<<18) -/// support weapon, bipod will grant IFF -#define GUN_SUPPORT_PLATFORM (1<<19) -#define GUN_BURST_ONLY (1<<20) -#define GUN_FULL_AUTO_ONLY (1<<21) +#define GUN_RECOIL_BUILDUP (1<<14) +/// support weapon, bipod will grant autofire +#define GUN_SUPPORT_PLATFORM (1<<15) /// No gun description, only base desc -#define GUN_NO_DESCRIPTION (1<<22) +#define GUN_NO_DESCRIPTION (1<<16) // NOTE: Don't add flags past 1<<23, it'll break things due to BYOND limitations. You can usually use a Component instead. #define USES_STREAKS (1<<0) @@ -85,15 +79,17 @@ #define MOVES_WHEN_LEVERING (1<<2) //Gun attachable related flags. -#define ATTACH_REMOVABLE 1 -#define ATTACH_ACTIVATION 2 +#define ATTACH_REMOVABLE (1<<0) +#define ATTACH_ACTIVATION (1<<1) /// for attachments that fire bullets -#define ATTACH_PROJECTILE 4 -#define ATTACH_RELOADABLE 8 +#define ATTACH_PROJECTILE (1<<2) +#define ATTACH_RELOADABLE (1<<3) /// is a weapon that fires stuff -#define ATTACH_WEAPON 16 +#define ATTACH_WEAPON (1<<4) +/// This attachment should override ignore if it is empty +#define ATTACH_IGNORE_EMPTY (1<<5) /// This attachment should activate if you attack() with it attached. -#define ATTACH_MELEE 32 +#define ATTACH_MELEE (1<<6) //Ammo magazine defines, for flags_magazine @@ -103,6 +99,8 @@ #define AMMUNITION_HANDFUL_BOX (1<<2) #define AMMUNITION_HIDE_AMMO (1<<3) #define AMMUNITION_CANNOT_REMOVE_BULLETS (1<<4) +/// If this magazine can transfer to other magazines of the same type by slapping one with the other +#define AMMUNITION_SLAP_TRANSFER (1<<5) //Slowdown from various armors. /// How much shoes slow you down by default. Negative values speed you up @@ -140,6 +138,9 @@ #define WIELD_DELAY_VERY_SLOW 10 #define WIELD_DELAY_HORRIBLE 12 +///This is how long you must wait after throwing something to throw again +#define THROW_DELAY (0.4 SECONDS) + //Explosion level thresholds. Upper bounds #define EXPLOSION_THRESHOLD_VLOW 50 #define EXPLOSION_THRESHOLD_LOW 100 @@ -197,6 +198,7 @@ // human armor #define CLOTHING_ARMOR_NONE 0 +#define CLOTHING_ARMOR_VERYLOW 5 #define CLOTHING_ARMOR_LOW 10 #define CLOTHING_ARMOR_MEDIUMLOW 15 #define CLOTHING_ARMOR_MEDIUM 20 @@ -229,6 +231,7 @@ //OB timings #define OB_TRAVEL_TIMING 12 SECONDS #define OB_CRASHING_DOWN 1 SECONDS +#define OB_CLUSTER_DURATION 45 SECONDS //================================================= //Health of various items diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm index 65511df13beb..e1f221dccbde 100644 --- a/code/__DEFINES/cooldowns.dm +++ b/code/__DEFINES/cooldowns.dm @@ -1,6 +1,7 @@ #define COOLDOWN_MOB_AUDIO "mob_audio_cooldown" #define COOLDOWN_IDLOCK_TEXTALERT "mob_idlock_textalert" #define COOLDOWN_HIJACK_BARRAGE "gamemode_explosive_barrage" +#define COOLDOWN_HIJACK_GROUND_CHECK "gamemode_ground_check" #define COOLDOWN_ITEM_HOOD_SOUND "item_hood_sound" //Define for ship alt diff --git a/code/__DEFINES/db_defs.dm b/code/__DEFINES/db_defs.dm index 2adf0f0be2aa..6665e83a2bca 100644 --- a/code/__DEFINES/db_defs.dm +++ b/code/__DEFINES/db_defs.dm @@ -126,3 +126,8 @@ // This table is for local filtering only. Use for logs that you want to query this round #define DB_TABLEHINT_LOCAL 1 + +#define DB_AND new /datum/db/filter/and +#define DB_OR new /datum/db/filter/or +#define DB_COMP new /datum/db/filter/comparison +#define DB_COMP2 new /datum/db/filter/compare_two diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm index 617ee135a4c0..b38339d1af17 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm @@ -28,6 +28,8 @@ #define COMSIG_HUMAN_OVERLAY_APPLIED "human_overlay_applied" /// From /mob/living/carbon/human/remove_overlay(): (cache_index, overlay_image) #define COMSIG_HUMAN_OVERLAY_REMOVED "human_overlay_removed" +/// From /datum/flaying_datum +#define COMSIG_HUMAN_FLAY_ATTEMPT "human_flay_attempt" #define COMSIG_HUMAN_BONEBREAK_PROBABILITY "human_bonebreak_probability" @@ -50,5 +52,14 @@ //from /mob/living/carbon/human/equip_to_slot() #define COMSIG_HUMAN_EQUIPPED_ITEM "human_equipped_item" +/// From /mob/proc/equip_to_slot_if_possible() +#define COMSIG_HUMAN_ATTEMPTING_EQUIP "human_attempting_equip" + #define COMPONENT_HUMAN_CANCEL_ATTEMPT_EQUIP (1<<0) + //from /mob/living/carbon/human/Life() #define COMSIG_HUMAN_SET_UNDEFIBBABLE "human_set_undefibbable" + +/// from /datum/surgery_step/proc/attempt_step() +#define COMSIG_HUMAN_SURGERY_APPLY_MODIFIERS "human_surgery_apply_modifiers" +/// From /mob/living/carbon/human/proc/get_flags_cold_protection() +#define COMSIG_HUMAN_COLD_PROTECTION_APPLY_MODIFIERS "human_cold_protection_apply_modifiers" diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm index bdae2114ff23..323e0ee6966c 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm @@ -43,6 +43,9 @@ #define COMSIG_MOB_DRAGGED "mob_dragged" /// From /obj/item/proc/unequipped() #define COMSIG_MOB_ITEM_UNEQUIPPED "mob_item_unequipped" +/// From /mob/proc/equip_to_slot_if_possible() +#define COMSIG_MOB_ATTEMPTING_EQUIP "mob_attempting_equip" + #define COMPONENT_MOB_CANCEL_ATTEMPT_EQUIP (1<<0) /// For when a mob is devoured by a Xeno #define COMSIG_MOB_DEVOURED "mob_devoured" @@ -105,3 +108,11 @@ #define COMSIG_MOB_STAT_SET_ALIVE "mob_stat_set_alive" //from /mob/living/set_stat() #define COMSIG_MOB_STAT_SET_DEAD "mob_stat_set_dead" + +#define COMSIG_GHOST_MOVED "ghost_moved" + +#define COMSIG_MOB_MOUSEDOWN "mob_mousedown" //from /client/MouseDown(): (atom/object, turf/location, control, params) +#define COMSIG_MOB_MOUSEUP "mob_mouseup" //from /client/MouseUp(): (atom/object, turf/location, control, params) +#define COMSIG_MOB_MOUSEDRAG "mob_mousedrag" //from /client/MouseDrag(): (atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params) + #define COMSIG_MOB_CLICK_CANCELED (1<<0) + #define COMSIG_MOB_CLICK_HANDLED (1<<1) diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm index 676bf3580821..b7bbca9f64a3 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_item.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm @@ -2,6 +2,8 @@ #define COMSIG_ITEM_ATTEMPT_ATTACK "item_attempt_attack" //Triggered on the target mob. #define COMPONENT_CANCEL_ATTACK (1<<0) +#define COMSIG_ITEM_ATTACK_AIRLOCK "item_attack_airlocK" + #define COMPONENT_CANCEL_AIRLOCK_ATTACK (1<<0) /// from /obj/item/attackby() : (obj/item, mob/user) #define COMSIG_ITEM_ATTACKED "item_attacked" @@ -36,3 +38,25 @@ #define COMSIG_ITEM_ZOOM "item_zoom" /// from /obj/item/proc/unzoom() : (mob/user) #define COMSIG_ITEM_UNZOOM "item_unzoom" + +//Signals for automatic fire at component +#define COMSIG_AUTOMATIC_SHOOTER_START_SHOOTING_AT "start_shooting_at" +#define COMSIG_AUTOMATIC_SHOOTER_STOP_SHOOTING_AT "stop_shooting_at" +#define COMSIG_AUTOMATIC_SHOOTER_SHOOT "shoot" + +//Signals for gun auto fire component +#define COMSIG_GET_BURST_FIRE "get_burst_fire" + #define BURST_FIRING (1<<0) + +#define COMSIG_GUN_FIRE "gun_fire" +#define COMSIG_GUN_STOP_FIRE "gun_stop_fire" +#define COMSIG_GUN_FIRE_MODE_TOGGLE "gun_fire_mode_toggle" +#define COMSIG_GUN_AUTOFIREDELAY_MODIFIED "gun_autofiredelay_modified" +#define COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED "gun_burst_shots_to_fire_modified" +#define COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED "gun_burst_shot_delay_modified" + +/// from /obj/item/weapon/gun/proc/recalculate_attachment_bonuses() : () +#define COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES "gun_recalculate_attachment_bonuses" + +/// from /obj/item/weapon/gun/proc/load_into_chamber() : () +#define COMSIG_GUN_INTERRUPT_FIRE "gun_interrupt_fire" diff --git a/code/__DEFINES/dcs/signals/atom/signals_obj.dm b/code/__DEFINES/dcs/signals/atom/signals_obj.dm index f52ec6eccf52..aebd0d09d0d2 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_obj.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_obj.dm @@ -4,6 +4,8 @@ /// From /obj/effect/alien/weeds/Initialize() #define COMSIG_WEEDNODE_GROWTH_COMPLETE "weednode_growth_complete" +/// From /obj/effect/alien/weeds/Initialize() +#define COMSIG_WEEDNODE_GROWTH "weednode_growth" /// From /obj/effect/alien/weeds/proc/on_weed_expand() #define COMSIG_WEEDNODE_CANNOT_EXPAND_FURTHER "weednode_cannot_expand_further" @@ -22,3 +24,8 @@ /// from /obj/structure/transmitter/update_icon() #define COMSIG_TRANSMITTER_UPDATE_ICON "transmitter_update_icon" + +#define COMSIG_TENT_COLLAPSING "tent_collapsing" + +/// from /obj/proc/afterbuckle() +#define COSMIG_OBJ_AFTER_BUCKLE "signal_obj_after_buckle" diff --git a/code/__DEFINES/dcs/signals/atom/signals_turf.dm b/code/__DEFINES/dcs/signals/atom/signals_turf.dm index f76abcda681a..6a0788bcf871 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_turf.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_turf.dm @@ -4,6 +4,7 @@ #define COMSIG_TURF_ENTER "turf_enter" #define COMPONENT_TURF_ALLOW_MOVEMENT (1<<0) #define COMPONENT_TURF_DENY_MOVEMENT (1<<1) +#define COMSIG_TURF_ENTERED "turf_entered" /// Called when a bullet hits a turf #define COMSIG_TURF_BULLET_ACT "turf_bullet_act" diff --git a/code/__DEFINES/dcs/signals/signals_datum.dm b/code/__DEFINES/dcs/signals/signals_datum.dm index a7a93c4ea114..7696d8ad6037 100644 --- a/code/__DEFINES/dcs/signals/signals_datum.dm +++ b/code/__DEFINES/dcs/signals/signals_datum.dm @@ -61,3 +61,6 @@ // from /datum/emergency_call/proc/spawn_candidates() #define COMSIG_ERT_SETUP "ert_setup" + +// from /proc/update_living_queens() : /mob/living/carbon/xenomorph/queen +#define COMSIG_HIVE_NEW_QUEEN "hive_new_queen" diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 007a71d4d0f1..a288ac2c8be7 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -47,3 +47,15 @@ // Used for smothering fires upon weather event start/stop #define COMSIG_GLOB_WEATHER_CHANGE "!weather_event_changed" + +/// From /obj/structure/machinery/telecomms/proc/tcomms_shutdown(), called when the relay turns off +#define COMSIG_GLOB_GROUNDSIDE_TELECOMM_TURNED_OFF "!groundside_telecomm_turned_off" + +/// From /datum/admins/proc/force_predator_round() +#define COMSIG_GLOB_PREDATOR_ROUND_TOGGLED "!predator_round_toglged" + +/// From /datum/game_mode/colonialmarines/proc/check_ground_humans() +#define COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING "!groundside_forsaken_handling" + +/// From +#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "yautja_armory_opened" diff --git a/code/__DEFINES/defenses.dm b/code/__DEFINES/defenses.dm index 57eb0c86f939..db615c2a0c78 100644 --- a/code/__DEFINES/defenses.dm +++ b/code/__DEFINES/defenses.dm @@ -8,7 +8,7 @@ // Defines for barricade upgrades #define BARRICADE_UPGRADE_BURN "Biohazard Upgrade (+Burn)" #define BARRICADE_UPGRADE_BRUTE "Reinforced Upgrade (+Brute)" -#define BARRICADE_UPGRADE_EXPLOSIVE "Explosive Upgrade (+Explosive)" +#define BARRICADE_UPGRADE_ANTIFF "Composite Upgrade (++Explosive, ++Projectile, ++Fire)" // Defines for defense stats #define DEFENSE_FUNCTIONAL 0 diff --git a/code/__DEFINES/dropships.dm b/code/__DEFINES/dropships.dm index 56a865309456..f7df570a2864 100644 --- a/code/__DEFINES/dropships.dm +++ b/code/__DEFINES/dropships.dm @@ -9,3 +9,4 @@ #define DROPSHIP_MAX_AUTO_DELAY 60 SECONDS #define DROPSHIP_MIN_AUTO_DELAY 10 SECONDS #define DROPSHIP_AUTO_RETRY_COOLDOWN 20 SECONDS +#define DROPSHIP_MEDEVAC_COOLDOWN 20 SECONDS diff --git a/code/__DEFINES/emote_panels.dm b/code/__DEFINES/emote_panels.dm new file mode 100644 index 000000000000..59959818da74 --- /dev/null +++ b/code/__DEFINES/emote_panels.dm @@ -0,0 +1,12 @@ +#define JOE_EMOTE_CATEGORY_GREETING "Greeting" +#define JOE_EMOTE_CATEGORY_TASK_UPDATE "Task Update" +#define JOE_EMOTE_CATEGORY_RESTRICTED_AREA "Restricted Area" +#define JOE_EMOTE_CATEGORY_FAREWELL "Farewell" +#define JOE_EMOTE_CATEGORY_QUIP "Quip" +#define JOE_EMOTE_CATEGORY_WARNING "Warning" +#define JOE_EMOTE_CATEGORY_QUESTION "Question" +#define JOE_EMOTE_CATEGORY_NOTICE "Notice" + +#define YAUTJA_EMOTE_CATEGORY_FAKESOUND "Fake Sound" +#define YAUTJA_EMOTE_CATEGORY_VOICE "Voice Synthesizer" +#define YAUTJA_EMOTE_CATEGORY_SPECIES "Yautja" diff --git a/code/__DEFINES/equipment.dm b/code/__DEFINES/equipment.dm index 1fe038fa249b..461eae27a2a3 100644 --- a/code/__DEFINES/equipment.dm +++ b/code/__DEFINES/equipment.dm @@ -82,7 +82,6 @@ #define NOTABLEMERGE (1<<13) /// Has heat source but isn't 'on fire' and thus can be stored #define IGNITING_ITEM (1<<14) - //========================================================================================== @@ -459,7 +458,7 @@ GLOBAL_LIST_INIT(slot_to_contained_sprite_shorthand, list( #define ACCESSORY_SLOT_MEDAL "Medal" #define ACCESSORY_SLOT_PONCHO "Ponchos" -/// Used for uniform armour inserts. +/// Used for uniform armor inserts. #define ACCESSORY_SLOT_ARMOR_C "Chest armor" #define ACCESSORY_SLOT_ARMOR_A "Arm armor" @@ -545,7 +544,6 @@ var/global/list/uniform_categories = list( //================================================= //================================================= -#define PHONE_RTO "RTO" #define PHONE_MARINE "Marine" #define PHONE_UPP_SOLDIER "Soldier" #define PHONE_IO "IO" diff --git a/code/__DEFINES/guns.dm b/code/__DEFINES/guns.dm index a89d98805e73..b29f7c7439f2 100644 --- a/code/__DEFINES/guns.dm +++ b/code/__DEFINES/guns.dm @@ -37,3 +37,11 @@ #define REVOLVER_TIP_COLOR_INCENDIARY AMMO_BAND_COLOR_INCENDIARY #define REVOLVER_TIP_COLOR_PENETRATING AMMO_BAND_COLOR_PENETRATING #define REVOLVER_TIP_COLOR_TOXIN AMMO_BAND_COLOR_TOXIN + +#define GUN_FIREMODE_SEMIAUTO "semi-auto fire mode" +#define GUN_FIREMODE_BURSTFIRE "burst-fire mode" +#define GUN_FIREMODE_AUTOMATIC "automatic fire mode" + +//autofire component fire callback return flags +#define AUTOFIRE_CONTINUE (1<<0) +#define AUTOFIRE_SUCCESS (1<<1) diff --git a/code/__DEFINES/human.dm b/code/__DEFINES/human.dm index 6e2d82d5cc4f..846119d6b55d 100644 --- a/code/__DEFINES/human.dm +++ b/code/__DEFINES/human.dm @@ -213,8 +213,3 @@ #define RELIGION_AGNOSTICISM "Agnostic" #define MAXIMUM_DROPPED_OBJECTS_REMEMBERED 2 - -///////////////////MISC HUMAN FLAGS (LINKED TO VAR: FLAGS_HUMAN_MISC)/////////////////// - -#define HUMAN_FLAG_CHANGED (1<<0) - diff --git a/code/__DEFINES/job.dm b/code/__DEFINES/job.dm index d1ea56f75b7f..eac5121f173e 100644 --- a/code/__DEFINES/job.dm +++ b/code/__DEFINES/job.dm @@ -12,15 +12,15 @@ #define SQUAD_SOF "SOF" // Job name defines -#define JOB_SQUAD_MARINE "Squad Rifleman" +#define JOB_SQUAD_MARINE "Rifleman" #define JOB_SQUAD_LEADER "Squad Leader" -#define JOB_SQUAD_ENGI "Squad Combat Technician" -#define JOB_SQUAD_MEDIC "Squad Hospital Corpsman" -#define JOB_SQUAD_SPECIALIST "Squad Weapons Specialist" -#define JOB_SQUAD_RTO "Squad Radio Telephone Operator" -#define JOB_SQUAD_SMARTGUN "Squad Smartgunner" +#define JOB_SQUAD_ENGI "Combat Technician" +#define JOB_SQUAD_MEDIC "Hospital Corpsman" +#define JOB_SQUAD_SPECIALIST "Weapons Specialist" +#define JOB_SQUAD_TEAM_LEADER "Fireteam Leader" +#define JOB_SQUAD_SMARTGUN "Smartgunner" #define JOB_SQUAD_ROLES /datum/timelock/squad -#define JOB_SQUAD_ROLES_LIST list(JOB_SQUAD_MARINE, JOB_SQUAD_LEADER, JOB_SQUAD_ENGI, JOB_SQUAD_MEDIC, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_RTO) +#define JOB_SQUAD_ROLES_LIST list(JOB_SQUAD_MARINE, JOB_SQUAD_LEADER, JOB_SQUAD_ENGI, JOB_SQUAD_MEDIC, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_TEAM_LEADER) var/global/list/job_squad_roles = JOB_SQUAD_ROLES_LIST @@ -38,7 +38,7 @@ var/global/list/job_squad_roles = JOB_SQUAD_ROLES_LIST #define ENGINEERING_SURVIVOR "Engineering Survivor" #define CORPORATE_SURVIVOR "Corporate Survivor" #define HOSTILE_SURVIVOR "Hostile Survivor" //AKA Marine Killers assuming they survive. Will do cultist survivor at some point. -#define SURVIVOR_VARIANT_LIST list(ANY_SURVIVOR, CIVILIAN_SURVIVOR, SECURITY_SURVIVOR, SCIENTIST_SURVIVOR, MEDICAL_SURVIVOR, ENGINEERING_SURVIVOR, CORPORATE_SURVIVOR, HOSTILE_SURVIVOR) +#define SURVIVOR_VARIANT_LIST list(ANY_SURVIVOR = "Any", CIVILIAN_SURVIVOR = "Civ", SECURITY_SURVIVOR = "Sec", SCIENTIST_SURVIVOR = "Sci", MEDICAL_SURVIVOR = "Med", ENGINEERING_SURVIVOR = "Eng", CORPORATE_SURVIVOR = "W-Y", HOSTILE_SURVIVOR = "CLF") //-1 is infinite amount, these are soft caps and can be bypassed by randomization #define MAX_SURVIVOR_PER_TYPE list(ANY_SURVIVOR = -1, CIVILIAN_SURVIVOR = -1, SECURITY_SURVIVOR = 2, SCIENTIST_SURVIVOR = 2, MEDICAL_SURVIVOR = 3, ENGINEERING_SURVIVOR = 4, CORPORATE_SURVIVOR = 2, HOSTILE_SURVIVOR = 1) @@ -52,10 +52,12 @@ var/global/list/job_squad_roles = JOB_SQUAD_ROLES_LIST #define JOB_CMO "Chief Medical Officer" #define JOB_DOCTOR "Doctor" +#define JOB_SURGEON "Surgeon" + #define JOB_NURSE "Nurse" #define JOB_RESEARCHER "Researcher" #define JOB_MEDIC_ROLES /datum/timelock/medic -#define JOB_MEDIC_ROLES_LIST list(JOB_SQUAD_MEDIC, JOB_CMO, JOB_DOCTOR, JOB_NURSE, JOB_RESEARCHER) +#define JOB_MEDIC_ROLES_LIST list(JOB_SQUAD_MEDIC, JOB_CMO, JOB_DOCTOR, JOB_NURSE, JOB_RESEARCHER, JOB_SURGEON) #define JOB_CORPORATE_LIAISON "Corporate Liaison" #define JOB_COMBAT_REPORTER "Combat Correspondent" @@ -70,10 +72,13 @@ var/global/list/job_squad_roles = JOB_SQUAD_ROLES_LIST #define JOB_COMMAND_ROLES_LIST list(JOB_CO, JOB_XO, JOB_SO) var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST +#define JOB_AUXILIARY_OFFICER "Auxiliary Support Officer" #define JOB_PILOT "Pilot Officer" #define JOB_DROPSHIP_CREW_CHIEF "Dropship Crew Chief" #define JOB_CREWMAN "Vehicle Crewman" #define JOB_INTEL "Intelligence Officer" +#define JOB_AUXILIARY_ROLES /datum/timelock/auxiliary +#define JOB_AUXILIARY_ROLES_LIST list(JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_CREWMAN, JOB_INTEL) #define JOB_POLICE "Military Police" #define JOB_WARDEN "Military Warden" @@ -89,7 +94,7 @@ var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST #define JOB_ENGINEER_ROLES /datum/timelock/engineer #define JOB_ENGINEER_ROLES_LIST list(JOB_SQUAD_ENGI, JOB_MAINT_TECH, JOB_ORDNANCE_TECH, JOB_CHIEF_ENGINEER) -#define JOB_CHIEF_REQUISITION "Requisitions Officer" +#define JOB_CHIEF_REQUISITION "Quartermaster" #define JOB_CARGO_TECH "Cargo Technician" #define JOB_REQUISITION_ROLES /datum/timelock/requisition #define JOB_REQUISITION_ROLES_LIST list(JOB_CHIEF_REQUISITION, JOB_CARGO_TECH) @@ -141,7 +146,7 @@ var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST #define JOB_WO_CHIEF_ENGINEER "Bunker Crew Master" #define JOB_WO_ORDNANCE_TECH "Bunker Crew" -#define JOB_WO_CHIEF_REQUISITION "Quartermaster" +#define JOB_WO_CHIEF_REQUISITION "Bunker Quartermaster" #define JOB_WO_REQUISITION "Bunker Crew Logistics" #define JOB_WO_CMO "Head Surgeon" @@ -161,24 +166,25 @@ var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST //------------------------------------ //-------- PMC --------// -#define JOB_PMC "PMC Standard" +#define JOB_PMC_STANDARD "Weyland-Yutani PMC (Standard)" #define JOB_PMC_ENGINEER "PMC Corporate Technician" #define JOB_PMC_MEDIC "PMC Corporate Medic" #define JOB_PMC_DOCTOR "PMC Trauma Surgeon" #define JOB_PMC_INVESTIGATOR "PMC Medical Investigator" +#define JOB_PMC_DETAINER "Weyland-Yutani PMC (Detainer)" #define JOB_PMC_ELITE "PMC Elite" #define JOB_PMC_GUNNER "PMC Support Weapons Specialist" //Renamed from Specialist to Support Specialist as it only has SG skills. #define JOB_PMC_SNIPER "PMC Weapons Specialist" //Renamed from Sharpshooter to specialist as it uses specialist skills. -#define JOB_PMC_CREWMAN "PMC Crewman" +#define JOB_PMC_CREWMAN "Weyland-Yutani PMC (Crewman)" #define JOB_PMC_NINJA "PMC Ninja" #define JOB_PMC_XENO_HANDLER "PMC Xeno Handler" #define JOB_PMC_COMMANDO "PMC Commando" #define JOB_PMC_LEADER "PMC Leader" #define JOB_PMC_LEAD_INVEST "PMC Lead Investigator" #define JOB_PMC_DIRECTOR "PMC Site Director" -#define JOB_PMC_SYNTH "PMC Support Synthetic" +#define JOB_PMC_SYNTH "PMC Support Synthetic" -#define JOB_PMC_GRUNT_LIST list(JOB_PMC, JOB_PMC_ENGINEER, JOB_PMC_MEDIC, JOB_PMC_INVESTIGATOR, JOB_PMC_ELITE, JOB_PMC_GUNNER, JOB_PMC_SNIPER, JOB_PMC_CREWMAN, JOB_PMC_NINJA, JOB_PMC_XENO_HANDLER, JOB_PMC_COMMANDO, JOB_PMC_LEADER, JOB_PMC_LEAD_INVEST) +#define JOB_PMC_GRUNT_LIST list(JOB_PMC_STANDARD, JOB_PMC_ENGINEER, JOB_PMC_MEDIC, JOB_PMC_INVESTIGATOR, JOB_PMC_DETAINER, JOB_PMC_ELITE, JOB_PMC_GUNNER, JOB_PMC_SNIPER, JOB_PMC_CREWMAN, JOB_PMC_NINJA, JOB_PMC_XENO_HANDLER, JOB_PMC_COMMANDO, JOB_PMC_LEADER, JOB_PMC_LEAD_INVEST) //-------- WY --------// @@ -196,6 +202,7 @@ var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST //-------- WY Goons --------// #define JOB_WY_GOON "WY Corporate Security" #define JOB_WY_GOON_LEAD "WY Corporate Security Lead" +#define JOB_WY_GOON_RESEARCHER "WY Research Consultant" #define JOB_WY_GOON_LIST list(JOB_WY_GOON, JOB_WY_GOON_LEAD) @@ -226,6 +233,17 @@ var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST #define CMB_GRUNT_LIST list(JOB_CMB, JOB_CMB_TL) +//-------- FORECON --------// + +#define JOB_FORECON_CO "Reconnaissance Commander" +#define JOB_FORECON_SL "Reconnaissance Squad Leader" +#define JOB_FORECON_SYN "Reconnaissance Synthetic" +#define JOB_FORECON_SNIPER "Reconnaissance Sniper" +#define JOB_FORECON_MARKSMAN "Reconnaissance Marksman" +#define JOB_FORECON_SUPPORT "Reconnaissance Support Technician" +#define JOB_FORECON_RIFLEMAN "Reconnaissance Rifleman" +#define JOB_FORECON_SMARTGUNNER "Reconnaissance Smartgunner" + //-------- UPP --------// #define JOB_UPP "UPP Private" #define JOB_UPP_CONSCRIPT "UPP Conscript" @@ -322,18 +340,19 @@ var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST #define JOB_XENOMORPH "Xenomorph" #define JOB_XENOMORPH_QUEEN "Queen" -// For colouring the ranks in the statistics menu +// For coloring the ranks in the statistics menu #define JOB_PLAYTIME_TIER_1 (10 HOURS) #define JOB_PLAYTIME_TIER_2 (25 HOURS) #define JOB_PLAYTIME_TIER_3 (70 HOURS) #define JOB_PLAYTIME_TIER_4 (175 HOURS) #define XENO_NO_AGE -1 -#define XENO_NORMAL 0 -#define XENO_MATURE 1 -#define XENO_ELDER 2 -#define XENO_ANCIENT 3 -#define XENO_PRIME 4 +#define XENO_YOUNG 0 +#define XENO_NORMAL 1 +#define XENO_MATURE 2 +#define XENO_ELDER 3 +#define XENO_ANCIENT 4 +#define XENO_PRIME 5 /// For monthly time tracking #define JOB_OBSERVER "Observer" diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 342fcec1d394..1878ca63f34e 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -188,6 +188,8 @@ #define COMSIG_KB_OBSERVER_JOIN_XENO "keybinding_observer_join_as_xeno" #define COMSIG_KB_OBSERVER_JOIN_ERT "keybinding_observer_join_ert" +#define COMSIG_KB_OBSERVER_JOIN_PREDATOR "keybinding_observer_join_pred" +#define COMSIG_KB_OBSERVER_JOIN_LESSER_DRONE "keybinding_observer_join_lesser_drone" #define CATEGORY_CLIENT "CLIENT" #define CATEGORY_EMOTE "EMOTE" diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm index 8cac90defb26..e4c4041a3dda 100644 --- a/code/__DEFINES/language.dm +++ b/code/__DEFINES/language.dm @@ -12,7 +12,7 @@ #define LANGUAGE_XENOMORPH "Xenomorph" #define LANGUAGE_HIVEMIND "Hivemind" -#define LANGUAGE_APOLLO "Apollo Link" +#define LANGUAGE_APOLLO "APOLLO Link" #define LANGUAGE_TELEPATH "Telepath Implant" @@ -20,6 +20,8 @@ #define ALL_SYNTH_LANGUAGES list(LANGUAGE_ENGLISH, LANGUAGE_JAPANESE, LANGUAGE_CHINESE, LANGUAGE_RUSSIAN, LANGUAGE_GERMAN, LANGUAGE_SPANISH, LANGUAGE_YAUTJA, LANGUAGE_XENOMORPH) +#define ALL_SYNTH_LANGUAGES_UPP list(LANGUAGE_RUSSIAN, LANGUAGE_ENGLISH, LANGUAGE_JAPANESE, LANGUAGE_CHINESE, LANGUAGE_GERMAN, LANGUAGE_SPANISH, LANGUAGE_YAUTJA, LANGUAGE_XENOMORPH) + //Chinese language sound bitflags //initial flags diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 0691b5a14e22..3cbd0d6dac44 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -16,7 +16,7 @@ #define TURF_LAYER 2 #define ABOVE_TURF_LAYER 2.01 -#define INTERIOR_WALL_NORTH_LAYER 2.02 +#define WALL_LAYER 2.02 #define LATTICE_LAYER 2.15 @@ -124,12 +124,15 @@ #define FACEHUGGER_LAYER 4.13 /// For WEATHER #define WEATHER_LAYER 4.14 -#define INTERIOR_WALL_SOUTH_LAYER 5.2 -#define INTERIOR_DOOR_LAYER 5.21 //#define FLY_LAYER 5 #define RIPPLE_LAYER 5.1 +#define INTERIOR_DOOR_INSIDE_LAYER 5.19 +#define INTERIOR_WALL_SOUTH_LAYER 5.2 +#define INTERIOR_DOOR_LAYER 5.21 +#define INTERIOR_WALLMOUNT_LAYER 5.3 +#define INTERIOR_ROOF_LAYER 5.5 #define ABOVE_FLY_LAYER 6 @@ -174,9 +177,12 @@ /// NEVER HAVE ANYTHING BELOW THIS PLANE ADJUST IF YOU NEED MORE SPACE #define LOWEST_EVER_PLANE -200 +/// Floor plane, self explanatory. Used for Ambient Occlusion filter #define FLOOR_PLANE -7 +/// Game Plane, where most of the game objects reside #define GAME_PLANE -6 -#define ABOVE_GAME_PLANE -5 +/// Roof plane, disappearing when entering buildings +#define ROOF_PLANE -4 /// To keep from conflicts with SEE_BLACKNESS internals #define BLACKNESS_PLANE 0 diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm index ac050e467a71..5a4ba7676233 100644 --- a/code/__DEFINES/lighting.dm +++ b/code/__DEFINES/lighting.dm @@ -1,3 +1,5 @@ #define LIGHTING_PLANE_ALPHA_VISIBLE 255 +///The dim natural vision of Yautja +#define LIGHTING_PLANE_ALPHA_YAUTJA 235 #define LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE 127 #define LIGHTING_PLANE_ALPHA_INVISIBLE 0 diff --git a/code/__DEFINES/machinery.dm b/code/__DEFINES/machinery.dm index fa92aca24b80..536851bc2df0 100644 --- a/code/__DEFINES/machinery.dm +++ b/code/__DEFINES/machinery.dm @@ -5,3 +5,14 @@ #define USE_POWER_NONE 0 #define USE_POWER_IDLE 1 #define USE_POWER_ACTIVE 2 + +// used by the simulator to select mob type + +#define HUMAN_MODE "Unarmoured Humans" +#define UPP_MODE "UPP Conscripts" +#define CLF_MODE "CLF Guerillas" +#define RUNNER_MODE "Xenomorph Runners" +#define SPITTER_MODE "Xenomorph Spitters" +#define DEFENDER_MODE "Xenomorph Defenders" +#define RAVAGER_MODE "Xenomorph Ravagers" +#define CRUSHER_MODE "Xenomorph Crushers" diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm index 1f3c99c87e43..3f6a4a44ee07 100644 --- a/code/__DEFINES/maps.dm +++ b/code/__DEFINES/maps.dm @@ -26,7 +26,6 @@ require only minor tweaks. #define ZTRAIT_MARINE_MAIN_SHIP "Marine Main Ship" #define ZTRAIT_ADMIN "Admin" #define ZTRAIT_AWAY "Away" -#define ZTRAIT_LOWORBIT "LowOrbit" #define ZTRAIT_INTERIORS "Interiors" #define ZTRAIT_TECHTREE "TechTree" @@ -67,7 +66,6 @@ require only minor tweaks. #define ZTRAITS_MAIN_SHIP list(ZTRAIT_MARINE_MAIN_SHIP = TRUE) #define ZTRAITS_GROUND list(ZTRAIT_GROUND = TRUE) #define ZTRAITS_ADMIN list(ZTRAIT_ADMIN = TRUE) -#define ZTRAITS_LOWORBIT list(ZTRAIT_LOWORBIT = TRUE) #define ZTRAITS_SPACE list(ZTRAIT_LINKAGE = CROSSLINKED, ZTRAIT_SPACE_RUINS = TRUE) #define ZTRAITS_INTERIORS list(ZTRAIT_INTERIORS = TRUE) @@ -79,7 +77,6 @@ require only minor tweaks. #define DEFAULT_MAP_TRAITS list(\ DECLARE_LEVEL("CentCom", ZTRAITS_ADMIN),\ - DECLARE_LEVEL("LowOrbit", ZTRAITS_LOWORBIT),\ ) // Camera lock flags @@ -107,8 +104,10 @@ require only minor tweaks. #define GROUND_MAP "ground_map" #define SHIP_MAP "ship_map" #define ALL_MAPTYPES list(GROUND_MAP, SHIP_MAP) +#define OVERRIDE_MAPS_TO_FILENAME list(GROUND_MAP = "next_map_override.dmm", SHIP_MAP = "next_ship_override.dmm") #define MAP_TO_FILENAME list(GROUND_MAP = "data/next_map.json", SHIP_MAP = "data/next_ship.json") #define HUNTERSHIPS_TEMPLATE_PATH "maps/predship/huntership.dmm" +#define OVERRIDE_DEFAULT_MAP_CONFIG list(GROUND_MAP = "maps/override_ground.json", SHIP_MAP = "maps/override_ship.json") // traity things #define MAP_COLD "COLD" diff --git a/code/__DEFINES/minimap.dm b/code/__DEFINES/minimap.dm index 343e4578709c..c9f21484f622 100644 --- a/code/__DEFINES/minimap.dm +++ b/code/__DEFINES/minimap.dm @@ -4,7 +4,8 @@ #define MINIMAP_FLAG_PMC (1<<2) #define MINIMAP_FLAG_UPP (1<<3) #define MINIMAP_FLAG_CLF (1<<4) -#define MINIMAP_FLAG_ALL (1<<5) - 1 +#define MINIMAP_FLAG_YAUTJA (1<<5) +#define MINIMAP_FLAG_ALL (1<<6) - 1 ///Converts the overworld x and y to minimap x and y values #define MINIMAP_SCALE 2 @@ -15,7 +16,7 @@ GLOBAL_LIST_INIT(all_minimap_flags, bitfield2list(MINIMAP_FLAG_ALL)) -//Turf colours +//Turf colors #define MINIMAP_SOLID "#ebe5e5ee" #define MINIMAP_DOOR "#451e5eb8" #define MINIMAP_FENCE "#8d2294ad" @@ -26,7 +27,7 @@ GLOBAL_LIST_INIT(all_minimap_flags, bitfield2list(MINIMAP_FLAG_ALL)) #define MINIMAP_ICE "#93cae0b0" #define MINIMAP_WATER "#94b0d59c" -//Area colours +//Area colors #define MINIMAP_AREA_ENGI "#c19504e7" #define MINIMAP_AREA_ENGI_CAVE "#5a4501e7" #define MINIMAP_AREA_MEDBAY "#3dbf75ee" @@ -59,6 +60,7 @@ GLOBAL_LIST_INIT(all_minimap_flags, bitfield2list(MINIMAP_FLAG_ALL)) #define MINIMAP_ICON_COLOR_COMMANDER "#c6fcfc" #define MINIMAP_ICON_COLOR_HEAD "#F0C542" +#define MINIMAP_ICON_COLOR_SILVER "#c0c0c0" #define MINIMAP_ICON_COLOR_BRONZE "#eb9545" #define MINIMAP_ICON_COLOR_DOCTOR "#b83737" diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index ecfed76836f5..b024f22ebfff 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -44,6 +44,8 @@ #define AREA_ALLOW_XENO_JOIN (1<<2) /// Flags the area as a containment area #define AREA_CONTAINMENT (1<<3) +/// Flags the area as permanently unweedable. Still requires is_resin_allowed = FALSE +#define AREA_UNWEEDABLE (1<<4) /// Default number of ticks for do_after #define DA_DEFAULT_NUM_TICKS 5 @@ -111,7 +113,7 @@ // These behaviors are either of the person performing the action or any targets. /// You cannot move the person while this action is being performed -#define BEHAVIOR_IMMOBILE (1<<18) +#define BEHAVIOR_IMMOBILE (1<<19) // *************************************** // // END DO_AFTER FLAGS // @@ -128,7 +130,7 @@ /// Helmets #define SIZE_TINY 1 -/// Armour, pouch slots/pockets +/// Armor, pouch slots/pockets #define SIZE_SMALL 2 /// Backpacks, belts. Size of pistols, general magazines #define SIZE_MEDIUM 3 @@ -282,6 +284,8 @@ #define COOLDOWN_COMM_CENTRAL 30 SECONDS #define COOLDOWN_COMM_DESTRUCT 5 MINUTES +///Cooldown for pred recharge +#define COOLDOWN_BRACER_CHARGE 3 MINUTES // magic value to use for indicating a proc slept #define PROC_RETURN_SLEEP -1 diff --git a/code/__DEFINES/mob_hud.dm b/code/__DEFINES/mob_hud.dm index 69b4aa29eab2..2704e52d2f85 100644 --- a/code/__DEFINES/mob_hud.dm +++ b/code/__DEFINES/mob_hud.dm @@ -58,7 +58,10 @@ #define TRACKER_CSL "_csl" // Charlie Squad Leader #define TRACKER_DSL "_dsl" // Delta Squad Leader #define TRACKER_ESL "_esl" // Echo Squad Leader +#define TRACKER_FSL "_fsl" // Cryo Squad Leader //for tracking the queen/hivecore on xeno locator huds #define TRACKER_QUEEN "Queen" #define TRACKER_HIVE "Hive Core" +#define TRACKER_LEADER "Leader" +#define TRACKER_TUNNEL "Tunnel" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 495b5fb472c5..c0886ab871f9 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -11,8 +11,6 @@ #define OVEREAT_TIME 200 //================================================= -#define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien. - #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 @@ -133,8 +131,9 @@ #define XENO_HIVE_MUTATED "xeno_hive_mutated" #define XENO_HIVE_FORSAKEN "xeno_hive_forsaken" #define XENO_HIVE_YAUTJA "xeno_hive_yautja" +#define XENO_HIVE_RENEGADE "xeno_hive_renegade" -#define ALL_XENO_HIVES list(XENO_HIVE_NORMAL, XENO_HIVE_CORRUPTED, XENO_HIVE_ALPHA, XENO_HIVE_BRAVO, XENO_HIVE_CHARLIE, XENO_HIVE_DELTA, XENO_HIVE_FERAL, XENO_HIVE_TAMED, XENO_HIVE_MUTATED, XENO_HIVE_FORSAKEN, XENO_HIVE_YAUTJA) +#define ALL_XENO_HIVES list(XENO_HIVE_NORMAL, XENO_HIVE_CORRUPTED, XENO_HIVE_ALPHA, XENO_HIVE_BRAVO, XENO_HIVE_CHARLIE, XENO_HIVE_DELTA, XENO_HIVE_FERAL, XENO_HIVE_TAMED, XENO_HIVE_MUTATED, XENO_HIVE_FORSAKEN, XENO_HIVE_YAUTJA, XENO_HIVE_RENEGADE) //================================================= @@ -223,6 +222,7 @@ //Mob sizes #define MOB_SIZE_SMALL 0 #define MOB_SIZE_HUMAN 1 +#define MOB_SIZE_XENO_VERY_SMALL 1.5 #define MOB_SIZE_XENO_SMALL 2 #define MOB_SIZE_XENO 3 #define MOB_SIZE_BIG 4 diff --git a/code/__DEFINES/mode.dm b/code/__DEFINES/mode.dm index 1ea370087545..bb31f4d84b1e 100644 --- a/code/__DEFINES/mode.dm +++ b/code/__DEFINES/mode.dm @@ -14,6 +14,7 @@ #define EVACUATION_STATUS_IN_PROGRESS 2 #define EVACUATION_STATUS_COMPLETE 3 +#define NUCLEAR_TIME_LOCK 90 MINUTES #define NUKE_EXPLOSION_INACTIVE 0 #define NUKE_EXPLOSION_ACTIVE 1 #define NUKE_EXPLOSION_IN_PROGRESS 2 @@ -68,34 +69,13 @@ #define MODE_NO_COMBAT_CAS (1<<6) /// Prevents POs and DCCs from creating combat CAS equipment #define MODE_LZ_PROTECTION (1<<7) /// Prevents the LZ from being mortared #define MODE_SHIPSIDE_SD (1<<8) /// Toggles whether Predators can big SD when not on the groundmap +#define MODE_HARDCORE_PERMA (1<<9) /// Toggles Hardcore for all marines, meaning they instantly perma upon death +#define MODE_DISPOSABLE_MOBS (1<<10) // Toggles if mobs fit in disposals or not. Off by default. #define ROUNDSTATUS_FOG_DOWN 1 #define ROUNDSTATUS_PODDOORS_OPEN 2 -#define LATEJOIN_MARINES_PER_LATEJOIN_LARVA 3 - -#define BE_ALIEN_AFTER_DEATH 1 -#define BE_AGENT 2 - -#define TOGGLE_IGNORE_SELF (1<<0) // Determines whether you will not hurt yourself when clicking yourself -#define TOGGLE_HELP_INTENT_SAFETY (1<<1) // Determines whether help intent will be completely harmless -#define TOGGLE_MIDDLE_MOUSE_CLICK (1<<2) // This toggles whether selected ability for xeno uses middle mouse clicking or shift clicking -#define TOGGLE_DIRECTIONAL_ATTACK (1<<3) // This toggles whether attacks for xeno use directional attacks -#define TOGGLE_AUTO_EJECT_MAGAZINE_OFF (1<<4) // This toggles whether guns with auto ejectors will not auto eject their magazines - // MUTUALLY EXCLUSIVE TO TOGGLE_AUTO_EJECT_MAGAZINE_TO_HAND -#define TOGGLE_AUTO_EJECT_MAGAZINE_TO_HAND (1<<5) // This toggles whether guns with auto ejectors will cause you to unwield your gun and put the empty magazine in your hand - // MUTUALLY EXCLUSIVE TO TOGGLE_AUTO_EJECT_MAGAZINE -#define TOGGLE_EJECT_MAGAZINE_TO_HAND (1<<6) // This toggles whether manuallyejecting magazines from guns will cause you to unwield your gun - // and put the empty magazine in your hand -#define TOGGLE_AUTOMATIC_PUNCTUATION (1<<7) // Whether your sentences will automatically be punctuated with a period -#define TOGGLE_COMBAT_CLICKDRAG_OVERRIDE (1<<8) // Whether disarm/harm intents cause clicks to trigger immediately when the mouse button is depressed. -#define TOGGLE_ALTERNATING_DUAL_WIELD (1<<9) // Whether dual-wielding fires both guns at once or swaps between them. -#define TOGGLE_FULLSCREEN (1<<10) // See /client/proc/toggle_fullscreen in client_procs.dm -#define TOGGLE_MEMBER_PUBLIC (1<<11) //determines if you get a byond logo by your name in ooc if you're a member or not -#define TOGGLE_OOC_FLAG (1<<12) // determines if your country flag appears by your name in ooc chat -#define TOGGLE_MIDDLE_MOUSE_SWAP_HANDS (1<<13) //Toggle whether middle click swaps your hands -#define TOGGLE_AMBIENT_OCCLUSION (1<<14) // toggles if ambient occlusion is turned on or off -#define TOGGLE_VEND_ITEM_TO_HAND (1<<15) // This toggles whether items from vendors will be automatically put into your hand. +#define LATEJOIN_MARINES_PER_LATEJOIN_LARVA 2.5 //================================================= #define SHOW_ITEM_ANIMATIONS_NONE 0 //Do not show any item pickup animations @@ -110,16 +90,8 @@ //================================================= -var/list/be_special_flags = list( - "Xenomorph after unrevivable death" = BE_ALIEN_AFTER_DEATH, - "Agent" = BE_AGENT, -) - -#define AGE_MIN 19 //youngest a character can be -#define AGE_MAX 90 //oldest a character can be //no. you are not allowed to be 160. //Number of marine players against which the Marine's gear scales #define MARINE_GEAR_SCALING_NORMAL 30 -#define MAX_GEAR_COST 7 //Used in chargen for loadout limit. #define RESOURCE_NODE_SCALE 95 //How many players minimum per extra set of resource nodes #define RESOURCE_NODE_QUANTITY_PER_POP 11 //How many resources total per pop @@ -136,31 +108,37 @@ var/list/be_special_flags = list( //================================================= //Role defines, specifically lists of roles for job bans, crew manifests and the like. -var/global/list/ROLES_COMMAND = list(JOB_CO, JOB_XO, JOB_SO, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_CREWMAN, JOB_POLICE, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_CHIEF_REQUISITION, JOB_CHIEF_ENGINEER, JOB_CMO, JOB_CHIEF_POLICE, JOB_SEA, JOB_SYNTH, JOB_WARDEN) +var/global/list/ROLES_COMMAND = list(JOB_CO, JOB_XO, JOB_SO, JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_CREWMAN, JOB_POLICE, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_CHIEF_REQUISITION, JOB_CHIEF_ENGINEER, JOB_CMO, JOB_CHIEF_POLICE, JOB_SEA, JOB_SYNTH, JOB_WARDEN) -#define ROLES_OFFICERS list(JOB_CO, JOB_XO, JOB_SO, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_SEA, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_SYNTH, JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE) +//Marine roles +#define ROLES_OFFICERS list(JOB_CO, JOB_XO, JOB_SO, JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_SEA, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_SYNTH, JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE) var/global/list/ROLES_CIC = list(JOB_CO, JOB_XO, JOB_SO, JOB_WO_CO, JOB_WO_XO) -var/global/list/ROLES_AUXIL_SUPPORT = list(JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_WO_PILOT) +var/global/list/ROLES_AUXIL_SUPPORT = list(JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_WO_PILOT) var/global/list/ROLES_MISC = list(JOB_SYNTH, JOB_WORKING_JOE, JOB_SEA, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_MESS_SERGEANT, JOB_WO_CORPORATE_LIAISON, JOB_WO_SYNTH) var/global/list/ROLES_POLICE = list(JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE) var/global/list/ROLES_ENGINEERING = list(JOB_CHIEF_ENGINEER, JOB_ORDNANCE_TECH, JOB_MAINT_TECH, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH) var/global/list/ROLES_REQUISITION = list(JOB_CHIEF_REQUISITION, JOB_CARGO_TECH, JOB_WO_CHIEF_REQUISITION, JOB_WO_REQUISITION) var/global/list/ROLES_MEDICAL = list(JOB_CMO, JOB_RESEARCHER, JOB_DOCTOR, JOB_NURSE, JOB_WO_CMO, JOB_WO_RESEARCHER, JOB_WO_DOCTOR) -var/global/list/ROLES_MARINES = list(JOB_SQUAD_LEADER, JOB_SQUAD_RTO, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE) +var/global/list/ROLES_MARINES = list(JOB_SQUAD_LEADER, JOB_SQUAD_TEAM_LEADER, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE) var/global/list/ROLES_SQUAD_ALL = list(SQUAD_MARINE_1, SQUAD_MARINE_2, SQUAD_MARINE_3, SQUAD_MARINE_4, SQUAD_MARINE_5, SQUAD_MARINE_CRYO) +//Groundside roles var/global/list/ROLES_XENO = list(JOB_XENOMORPH_QUEEN, JOB_XENOMORPH) var/global/list/ROLES_WHITELISTED = list(JOB_SYNTH_SURVIVOR, JOB_CO_SURVIVOR, JOB_PREDATOR) var/global/list/ROLES_SPECIAL = list(JOB_SURVIVOR) -var/global/list/ROLES_REGULAR_ALL = ROLES_CIC + ROLES_POLICE + ROLES_AUXIL_SUPPORT + ROLES_MISC + ROLES_ENGINEERING + ROLES_REQUISITION + ROLES_MEDICAL + ROLES_MARINES + ROLES_SPECIAL + ROLES_WHITELISTED + ROLES_XENO - ROLES_WO -var/global/list/ROLES_FACTION_CLASH = ROLES_REGULAR_ALL - ROLES_XENO - ROLES_SPECIAL - ROLES_WHITELISTED + JOB_PREDATOR +var/global/list/ROLES_USCM = ROLES_CIC + ROLES_POLICE + ROLES_AUXIL_SUPPORT + ROLES_MISC + ROLES_ENGINEERING + ROLES_REQUISITION + ROLES_MEDICAL + ROLES_MARINES - ROLES_WO +var/global/list/ROLES_GROUND = ROLES_XENO + ROLES_SPECIAL + ROLES_WHITELISTED + +var/global/list/ROLES_DISTRESS_SIGNAL = ROLES_USCM + ROLES_GROUND +var/global/list/ROLES_FACTION_CLASH = ROLES_USCM + JOB_PREDATOR + var/global/list/ROLES_UNASSIGNED = list(JOB_SQUAD_MARINE) var/global/list/ROLES_WO = list(JOB_WO_CO, JOB_WO_XO, JOB_WO_CORPORATE_LIAISON, JOB_WO_SYNTH, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_WO_PILOT, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH, JOB_WO_CHIEF_REQUISITION, JOB_WO_REQUISITION, JOB_WO_CMO, JOB_WO_DOCTOR, JOB_WO_RESEARCHER, JOB_WO_SQUAD_MARINE, JOB_WO_SQUAD_MEDIC, JOB_WO_SQUAD_ENGINEER, JOB_WO_SQUAD_SMARTGUNNER, JOB_WO_SQUAD_SPECIALIST, JOB_WO_SQUAD_LEADER) //Role lists used for switch() checks in show_blurb_uscm(). Cosmetic, determines ex. "Engineering, USS Almayer", "2nd Bat. 'Falling Falcons'" etc. #define BLURB_USCM_COMBAT JOB_CO, JOB_XO, JOB_SO, JOB_WO_CO, JOB_WO_XO, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_SEA,\ - JOB_SQUAD_LEADER, JOB_SQUAD_RTO, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE + JOB_SQUAD_LEADER, JOB_SQUAD_TEAM_LEADER, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE #define BLURB_USCM_FLIGHT JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF #define BLURB_USCM_MP JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE #define BLURB_USCM_ENGI JOB_CHIEF_ENGINEER, JOB_ORDNANCE_TECH, JOB_MAINT_TECH, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH, JOB_WO_PILOT @@ -207,7 +185,7 @@ var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL, #define WHITELIST_EVERYTHING (WHITELISTS_GENERAL|WHITELISTS_COUNCIL|WHITELISTS_LEADER) -#define isCouncil(A) (RoleAuthority.roles_whitelist[A.ckey] & (WHITELIST_YAUTJA_COUNCIL | WHITELIST_SYNTHETIC_COUNCIL | WHITELIST_COMMANDER_COUNCIL)) +#define isCouncil(A) (RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_YAUTJA_COUNCIL) || (RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_SYNTHETIC_COUNCIL) || (RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_COMMANDER_COUNCIL) //================================================= @@ -245,6 +223,7 @@ var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL, #define FACTION_CLF "CLF" #define FACTION_PMC "PMC" #define FACTION_CONTRACTOR "VAI" +#define FACTION_MARSHAL "Colonial Marshal" #define FACTION_WY_DEATHSQUAD "WY Death Squad" #define FACTION_MERCENARY "Mercenary" #define FACTION_FREELANCER "Freelancer" @@ -261,7 +240,7 @@ var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL, #define FACTION_LIST_MARINE list(FACTION_MARINE) #define FACTION_LIST_HUMANOID list(FACTION_MARINE, FACTION_PMC, FACTION_WY, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_UPP, FACTION_FREELANCER, FACTION_SURVIVOR, FACTION_NEUTRAL, FACTION_COLONIST, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_YAUTJA, FACTION_ZOMBIE) -#define FACTION_LIST_ERT list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_UPP, FACTION_FREELANCER, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO) +#define FACTION_LIST_ERT list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_UPP, FACTION_FREELANCER, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_MARSHAL) #define FACTION_LIST_WY list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY) #define FACTION_LIST_MARINE_WY list(FACTION_MARINE, FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY) #define FACTION_LIST_MARINE_UPP list(FACTION_MARINE, FACTION_UPP) @@ -279,6 +258,9 @@ var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL, #define FACTION_LIST_XENOMORPH list(FACTION_XENOMORPH, FACTION_XENOMORPH_CORRPUTED, FACTION_XENOMORPH_ALPHA, FACTION_XENOMORPH_BRAVO, FACTION_XENOMORPH_CHARLIE, FACTION_XENOMORPH_DELTA) +// Faction allegiances within a certain faction. + +#define FACTION_ALLEGIANCE_USCM_COMMANDER list("Doves", "Hawks", "Magpies", "Unaligned") // global vars to prevent spam of the "one xyz alive" messages diff --git a/code/__DEFINES/objects.dm b/code/__DEFINES/objects.dm index 6a3e32e743c6..0a34ac9d6fe9 100644 --- a/code/__DEFINES/objects.dm +++ b/code/__DEFINES/objects.dm @@ -108,7 +108,6 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse #define IS_PRY_CAPABLE_CROWBAR 2 //actual crowbar #define IS_PRY_CAPABLE_FORCE 3 //can force open even powered airlocks - #define SELF_DESTRUCT_MACHINE_INACTIVE 0 #define SELF_DESTRUCT_MACHINE_ACTIVE 1 #define SELF_DESTRUCT_MACHINE_ARMED 2 @@ -137,11 +136,16 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse #define CLEANABLE_MISC "misc" //Anything else //For nuke announcements -#define NUKE_SHOW_TIMER_TEN_SEC 1 -#define NUKE_SHOW_TIMER_MINUTE 2 -#define NUKE_SHOW_TIMER_HALF 4 +#define NUKE_SHOW_TIMER_TEN_SEC (1<<0) +#define NUKE_SHOW_TIMER_MINUTE (1<<1) +#define NUKE_SHOW_TIMER_HALF (1<<2) #define NUKE_SHOW_TIMER_ALL (NUKE_SHOW_TIMER_TEN_SEC|NUKE_SHOW_TIMER_MINUTE|NUKE_SHOW_TIMER_HALF) +#define NUKE_DECRYPT_SHOW_TIMER_COMPLETE (1<<3) +#define NUKE_DECRYPT_SHOW_TIMER_MINUTE (1<<4) +#define NUKE_DECRYPT_SHOW_TIMER_HALF (1<<5) +#define NUKE_DECRYPT_SHOW_TIMER_ALL (NUKE_SHOW_TIMER_TEN_SEC|NUKE_SHOW_TIMER_HALF|NUKE_DECRYPT_SHOW_TIMER_COMPLETE|NUKE_DECRYPT_SHOW_TIMER_MINUTE|NUKE_DECRYPT_SHOW_TIMER_HALF) + //For recipes #define ONE_TYPE_PER_TURF 1 #define ONE_TYPE_PER_BORDER 2 diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index 5ba530274389..2093f80be50e 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -30,6 +30,13 @@ #define GC_QUEUE_HARDDELETE 3 //! short queue for things that hard delete instead of going thru the gc subsystem, this is purely so if they *can* softdelete, they will soft delete rather then wasting time with a hard delete. #define GC_QUEUE_COUNT 3 //! Number of queues, used for allocating the nested lists. Don't forget to increase this if you add a new queue stage + +// 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) diff --git a/code/__DEFINES/redis.dm b/code/__DEFINES/redis.dm new file mode 100644 index 000000000000..12f12ee4225e --- /dev/null +++ b/code/__DEFINES/redis.dm @@ -0,0 +1,8 @@ +#define REDIS_PUBLISH(channel, data...) SSredis.publish(channel, json_encode(list("source" = SSredis.instance_name, "round_id" = GLOB.round_id, ##data))) +#define LOG_REDIS(type, contents) if(SSredis.redis_logging) SSredis.publish("byond.log.[SSredis.instance_name].[type]", contents) + +#define CONFIG_DISABLED "config_disabled" + +#define SHUTDOWN "Server Shutdown" +#define TGS_COMPILE "TGS Compile" + diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm index 4b76279d89bb..126a8f82ece8 100644 --- a/code/__DEFINES/shuttles.dm +++ b/code/__DEFINES/shuttles.dm @@ -36,7 +36,7 @@ #define GAMEMODE_IMMUNE (1<<0) // Ripples, effects that signal a shuttle's arrival -#define SHUTTLE_RIPPLE_TIME 100 +#define SHUTTLE_RIPPLE_TIME 5 SECONDS #define TRANSIT_REQUEST 1 #define TRANSIT_READY 2 @@ -98,6 +98,12 @@ #define MOBILE_SHUTTLE_ID_ERT_SMALL "ert_rescue_shuttle" #define MOBILE_SHUTTLE_ID_ERT_BIG "ert_boarding_shuttle" +#define MOBILE_TRIJENT_ELEVATOR "trijentshuttle2" +#define STAT_TRIJENT_LZ1 "trigent_lz1" +#define STAT_TRIJENT_LZ2 "trigent_lz2" +#define STAT_TRIJENT_ENGI "trigent_engineering" +#define STAT_TRIJENT_OMEGA "trigent_omega" + #define MOBILE_SHUTTLE_LIFEBOAT_PORT "lifeboat-port" #define MOBILE_SHUTTLE_LIFEBOAT_STARBOARD "lifeboat-starboard" #define MOBILE_SHUTTLE_VEHICLE_ELEVATOR "vehicle_elevator" diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm index fc9ac3327c20..fdd1a8f083ad 100644 --- a/code/__DEFINES/skills.dm +++ b/code/__DEFINES/skills.dm @@ -39,14 +39,24 @@ //spec_weapons skill //hidden. who can and can't use specialist weapons #define SKILL_SPEC_DEFAULT 0 -#define SKILL_SPEC_ROCKET 1 //can use the demolitionist specialist gear -#define SKILL_SPEC_SCOUT 2 -#define SKILL_SPEC_SNIPER 3 -#define SKILL_SPEC_GRENADIER 4 -#define SKILL_SPEC_PYRO 5 -#define SKILL_SPEC_SMARTGUN 6 //for smartgunners -#define SKILL_SPEC_UPP 7 //for upp -#define SKILL_SPEC_ALL 8 //can use all specialist gear +/// Is trained to use specialist gear, but hasn't picked a kit. +#define SKILL_SPEC_TRAINED 1 +/// Can use RPG +#define SKILL_SPEC_ROCKET 2 +/// Can use thermal cloaks and custom M4RA rifle +#define SKILL_SPEC_SCOUT 3 +/// Can use sniper rifles and camo suits +#define SKILL_SPEC_SNIPER 4 +/// Can use the rotary grenade launcher and heavy armor +#define SKILL_SPEC_GRENADIER 5 +/// Can use heavy flamers +#define SKILL_SPEC_PYRO 6 +/// Can use smartguns +#define SKILL_SPEC_SMARTGUN 7 +/// UPP special training +#define SKILL_SPEC_UPP 8 +/// Can use ALL specialist weapons +#define SKILL_SPEC_ALL 9 //construction skill #define SKILL_CONSTRUCTION_DEFAULT 0 @@ -152,8 +162,8 @@ //pilot skill, hidden #define SKILL_PILOT_DEFAULT 0 -#define SKILL_PILOT_TRAINED 1 // DCC, Synth -#define SKILL_PILOT_EXPERT 2 // Pilot +#define SKILL_PILOT_TRAINED 1 // DCC +#define SKILL_PILOT_EXPERT 2 // Pilot, Synth #define SKILL_PILOT_MAX 2 //Navigations skill - for seting orbital alt diff --git a/code/__DEFINES/sounds.dm b/code/__DEFINES/sounds.dm index 51279e0ca0cd..f01ddfc86792 100644 --- a/code/__DEFINES/sounds.dm +++ b/code/__DEFINES/sounds.dm @@ -71,6 +71,7 @@ #define AMBIENCE_ALMAYER 'sound/ambience/almayerambience.ogg' #define AMBIENCE_LV624 'sound/ambience/ambienceLV624.ogg' #define AMBIENCE_BIGRED 'sound/ambience/desert.ogg' +#define AMBIENCE_NV 'sound/ambience/ambienceNV.ogg' #define AMBIENCE_PRISON 'sound/ambience/shipambience.ogg' #define AMBIENCE_TRIJENT 'sound/ambience/desert.ogg' diff --git a/code/__DEFINES/speech_channels.dm b/code/__DEFINES/speech_channels.dm index 405506678407..3f6e4720bde9 100644 --- a/code/__DEFINES/speech_channels.dm +++ b/code/__DEFINES/speech_channels.dm @@ -4,6 +4,5 @@ #define ME_CHANNEL "Me" #define OOC_CHANNEL "OOC" #define LOOC_CHANNEL "LOOC" -#define MOD_CHANNEL "MSAY" #define ADMIN_CHANNEL "ASAY" #define MENTOR_CHANNEL "Mentor" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 8008e1a0c930..47d65d1377d5 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -111,14 +111,21 @@ #define SS_INIT_TICKER_SPAWN 999 #define SS_INIT_INPUT 85 -#define SS_INIT_RUST 26 +#define SS_INIT_FAIL_TO_TOPIC 84 +#define SS_INIT_TOPIC 83 +#define SS_INIT_LOBBYART 82 +#define SS_INIT_RUST 30 +#define SS_INIT_INFLUXDRIVER 28 #define SS_INIT_SUPPLY_SHUTTLE 25 #define SS_INIT_GARBAGE 24 #define SS_INIT_ROUND 23.6 #define SS_INIT_EVENTS 23.5 #define SS_INIT_JOB 23 +#define SS_INIT_REDIS 22.5 +#define SS_INIT_REAGENTS 22.1 #define SS_INIT_MAPPING 22 #define SS_INIT_NIGHTMARE 21.5 +#define SS_INIT_TIMETRACK 21.1 #define SS_INIT_HUMANS 21 #define SS_INIT_MAP 20 #define SS_INIT_COMPONENT 19.5 @@ -129,7 +136,9 @@ #define SS_INIT_MORE_INIT 16 #define SS_INIT_AIR 15 #define SS_INIT_TELEPORTER 13 -#define SS_INIT_LIGHTING 12 +#define SS_INIT_INFLUXMCSTATS 12 +#define SS_INIT_INFLUXSTATS 11 +#define SS_INIT_LIGHTING 10 #define SS_INIT_DEFCON 9 #define SS_INIT_LAW 6 #define SS_INIT_FZ_TRANSITIONS 5 @@ -155,7 +164,6 @@ #define SS_INIT_PLAYTIME -29 #define SS_INIT_PREDSHIPS -30 #define SS_INIT_OBJECTIVES -31 -#define SS_INIT_LOBBYART -33 #define SS_INIT_MINIMAP -34 #define SS_INIT_STATPANELS -98 #define SS_INIT_CHAT -100 //Should be last to ensure chat remains smooth during init. @@ -166,6 +174,7 @@ #define SS_PRIORITY_INPUT 1000 #define SS_PRIORITY_TIMER 700 +#define SS_PRIORITY_AUTOFIRE 450 #define SS_PRIORITY_SOUND 250 #define SS_PRIORITY_TICKER 200 #define SS_PRIORITY_NIGHTMARE 180 @@ -208,12 +217,15 @@ #define SS_PRIORITY_UNSPECIFIED 30 #define SS_PRIORITY_PROCESS 25 #define SS_PRIORITY_SOUNDSCAPE 24 +#define SS_PRIORITY_INFLUXDRIVER 23 #define SS_PRIORITY_PAGER_STATUS 22 #define SS_PRIORITY_LIGHTING 20 #define SS_PRIORITY_TRACKING 19 +#define SS_PRIORITY_DATABASE 15 #define SS_PRIORITY_MINIMAPS 11 #define SS_PRIORITY_PING 10 -#define SS_PRIORITY_DATABASE 15 +#define SS_PRIORITY_INFLUXMCSTATS 9 +#define SS_PRIORITY_INFLUXSTATS 8 #define SS_PRIORITY_PLAYTIME 5 #define SS_PRIORITY_PERFLOGGING 4 #define SS_PRIORITY_CORPSESPAWNER 3 diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index 83e06658c573..22c3827022ff 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "6.0.6" +#define TGS_DMAPI_VERSION "6.5.2" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -12,8 +12,8 @@ // Comment this out once you've filled in the below. #error TGS API unconfigured -// Uncomment this if you wish to allow the game to interact with TGS 3. -// This will raise the minimum required security level of your game to TGS_SECURITY_TRUSTED due to it utilizing call()() +// Uncomment this if you wish to allow the game to interact with TGS 3.. +// This will raise the minimum required security level of your game to TGS_SECURITY_TRUSTED due to it utilizing call()(). //#define TGS_V3_API // Required interfaces (fill in with your codebase equivalent): @@ -52,44 +52,46 @@ // EVENT CODES -/// Before a reboot mode change, extras parameters are the current and new reboot mode enums +/// Before a reboot mode change, extras parameters are the current and new reboot mode enums. #define TGS_EVENT_REBOOT_MODE_CHANGE -1 -/// Before a port change is about to happen, extra parameters is new port +/// Before a port change is about to happen, extra parameters is new port. #define TGS_EVENT_PORT_SWAP -2 -/// Before the instance is renamed, extra parameter is the new name +/// Before the instance is renamed, extra parameter is the new name. #define TGS_EVENT_INSTANCE_RENAMED -3 -/// After the watchdog reattaches to DD, extra parameter is the new [/datum/tgs_version] of the server +/// After the watchdog reattaches to DD, extra parameter is the new [/datum/tgs_version] of the server. #define TGS_EVENT_WATCHDOG_REATTACH -4 +/// When the watchdog sends a health check to DD. No parameters. +#define TGS_EVENT_HEALTH_CHECK -5 -/// When the repository is reset to its origin reference. Parameters: Reference name, Commit SHA +/// When the repository is reset to its origin reference. Parameters: Reference name, Commit SHA. #define TGS_EVENT_REPO_RESET_ORIGIN 0 -/// When the repository performs a checkout. Parameters: Checkout git object +/// When the repository performs a checkout. Parameters: Checkout git object. #define TGS_EVENT_REPO_CHECKOUT 1 -/// When the repository performs a fetch operation. No parameters +/// When the repository performs a fetch operation. No parameters. #define TGS_EVENT_REPO_FETCH 2 -/// When the repository test merges. Parameters: PR Number, PR Sha, (Nullable) Comment made by TGS user +/// When the repository test merges. Parameters: PR Number, PR Sha, (Nullable) Comment made by TGS user. #define TGS_EVENT_REPO_MERGE_PULL_REQUEST 3 -/// Before the repository makes a sychronize operation. Parameters: Absolute repostiory path +/// Before the repository makes a sychronize operation. Parameters: Absolute repostiory path. #define TGS_EVENT_REPO_PRE_SYNCHRONIZE 4 -/// Before a BYOND install operation begins. Parameters: [/datum/tgs_version] of the installing BYOND +/// Before a BYOND install operation begins. Parameters: [/datum/tgs_version] of the installing BYOND. #define TGS_EVENT_BYOND_INSTALL_START 5 /// When a BYOND install operation fails. Parameters: Error message #define TGS_EVENT_BYOND_INSTALL_FAIL 6 -/// When the active BYOND version changes. Parameters: (Nullable) [/datum/tgs_version] of the current BYOND, [/datum/tgs_version] of the new BYOND +/// When the active BYOND version changes. Parameters: (Nullable) [/datum/tgs_version] of the current BYOND, [/datum/tgs_version] of the new BYOND. #define TGS_EVENT_BYOND_ACTIVE_VERSION_CHANGE 7 -/// When the compiler starts running. Parameters: Game directory path, origin commit SHA +/// When the compiler starts running. Parameters: Game directory path, origin commit SHA. #define TGS_EVENT_COMPILE_START 8 -/// When a compile is cancelled. No parameters +/// When a compile is cancelled. No parameters. #define TGS_EVENT_COMPILE_CANCELLED 9 -/// When a compile fails. Parameters: Game directory path, [TRUE]/[FALSE] based on if the cause for failure was DMAPI validation +/// When a compile fails. Parameters: Game directory path, [TRUE]/[FALSE] based on if the cause for failure was DMAPI validation. #define TGS_EVENT_COMPILE_FAILURE 10 -/// When a compile operation completes. Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the [TGS_EVENT_DEPLOYMENT_COMPLETE] instead. Parameters: Game directory path +/// When a compile operation completes. Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the [TGS_EVENT_DEPLOYMENT_COMPLETE] instead. Parameters: Game directory path. #define TGS_EVENT_COMPILE_COMPLETE 11 -/// When an automatic update for the current instance begins. No parameters +/// When an automatic update for the current instance begins. No parameters. #define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12 -/// When the repository encounters a merge conflict: Parameters: Base SHA, target SHA, base reference, target reference +/// When the repository encounters a merge conflict: Parameters: Base SHA, target SHA, base reference, target reference. #define TGS_EVENT_REPO_MERGE_CONFLICT 13 -/// When a deployment completes. No Parameters +/// When a deployment completes. No Parameters. #define TGS_EVENT_DEPLOYMENT_COMPLETE 14 /// Before the watchdog shuts down. Not sent for graceful shutdowns. No parameters. #define TGS_EVENT_WATCHDOG_SHUTDOWN 15 @@ -104,6 +106,12 @@ #define TGS_EVENT_WORLD_PRIME 21 // DMAPI also doesnt implement this // #define TGS_EVENT_DREAM_DAEMON_LAUNCH 22 +/// After a single submodule update is performed. Parameters: Updated submodule name. +#define TGS_EVENT_REPO_SUBMODULE_UPDATE 23 +/// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, byond version. +#define TGS_EVENT_PRE_DREAM_MAKER 24 +/// Whenever a deployment folder is deleted from disk. Parameters: Game directory path. +#define TGS_EVENT_DEPLOYMENT_CLEANUP 25 // OTHER ENUMS @@ -158,28 +166,28 @@ /datum/tgs_revision_information /// Full SHA of the commit. var/commit - /// ISO 8601 timestamp of when the commit was created + /// ISO 8601 timestamp of when the commit was created. var/timestamp /// Full sha of last known remote commit. This may be null if the TGS repository is not currently tracking a remote branch. var/origin_commit /// Represents a version. /datum/tgs_version - /// The suite/major version number + /// The suite/major version number. var/suite - // This group of variables can be null to represent a wild card - /// The minor version number. null for wildcards + // This group of variables can be null to represent a wild card. + /// The minor version number. null for wildcards. var/minor - /// The patch version number. null for wildcards + /// The patch version number. null for wildcards. var/patch - /// Legacy version number. Generally null + /// Legacy version number. Generally null. var/deprecated_patch - /// Unparsed string value + /// Unparsed string value. var/raw_parameter - /// String value minus prefix + /// String value minus prefix. var/deprefixed_parameter /** @@ -225,40 +233,49 @@ var/is_admin_channel /// [TRUE]/[FALSE] if the channel is a private message channel for a [/datum/tgs_chat_user]. var/is_private_channel - /// Tag string associated with the channel in TGS + /// Tag string associated with the channel in TGS. var/custom_tag + /// [TRUE]/[FALSE] if the channel supports embeds. + var/embeds_supported // Represents a chat user /datum/tgs_chat_user /// TGS internal user ID. var/id - // The user's display name. + /// The user's display name. var/friendly_name - // The string to use to ping this user in a message. + /// The string to use to ping this user in a message. var/mention - /// The [/datum/tgs_chat_channel] the user was from + /// The [/datum/tgs_chat_channel] the user was from. var/datum/tgs_chat_channel/channel +/// User definable handler for TGS events. +/datum/tgs_event_handler + /// If the handler receieves [TGS_EVENT_HEALTH_CHECK] events. + var/receive_health_checks = FALSE + /** * User definable callback for handling TGS events. * - * event_code - One of the TGS_EVENT_ defines. Extra parameters will be documented in each + * event_code - One of the TGS_EVENT_ defines. Extra parameters will be documented in each. */ /datum/tgs_event_handler/proc/HandleEvent(event_code, ...) set waitfor = FALSE return -/// User definable chat command +/// User definable chat command. /datum/tgs_chat_command - /// The string to trigger this command on a chat bot. e.g `@bot name ...` or `!tgs name ...` + /// The string to trigger this command on a chat bot. e.g `@bot name ...` or `!tgs name ...`. var/name = "" - /// The help text displayed for this command + /// The help text displayed for this command. var/help_text = "" - /// If this command should be available to game administrators only + /// If this command should be available to game administrators only. var/admin_only = FALSE + /// A subtype of [/datum/tgs_chat_command] that is ignored when enumerating available commands. Use this to create shared base /datums for commands. + var/ignore_type /** - * Process command activation. Should return a string to respond to the issuer with. + * Process command activation. Should return a [/datum/tgs_message_content] to respond to the issuer with. * * sender - The [/datum/tgs_chat_user] who issued the command. * params - The trimmed string following the command `/datum/tgs_chat_command/var/name]. @@ -266,6 +283,107 @@ /datum/tgs_chat_command/proc/Run(datum/tgs_chat_user/sender, params) CRASH("[type] has no implementation for Run()") +/// User definable chat message. +/datum/tgs_message_content + /// The tring content of the message. Must be provided in New(). + var/text + + /// The [/datum/tgs_chat_embed] to embed in the message. Not supported on all chat providers. + var/datum/tgs_chat_embed/structure/embed + +/datum/tgs_message_content/New(text) + if(!istext(text)) + TGS_ERROR_LOG("[/datum/tgs_message_content] created with no text!") + text = null + + src.text = text + +/// User definable chat embed. Currently mirrors Discord chat embeds. See https://discord.com/developers/docs/resources/channel#embed-object-embed-structure for details. +/datum/tgs_chat_embed/structure + var/title + var/description + var/url + + /// Timestamp must be encoded as: time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss"). Use the active timezone. + var/timestamp + + /// Colour must be #AARRGGBB or #RRGGBB hex string. + var/colour + + /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure for details. + var/datum/tgs_chat_embed/media/image + + /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-thumbnail-structure for details. + var/datum/tgs_chat_embed/media/thumbnail + + /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure for details. + var/datum/tgs_chat_embed/media/video + + var/datum/tgs_chat_embed/footer/footer + var/datum/tgs_chat_embed/provider/provider + var/datum/tgs_chat_embed/provider/author/author + + var/list/datum/tgs_chat_embed/field/fields + +/// Common datum for similar discord embed medias. +/datum/tgs_chat_embed/media + /// Must be set in New(). + var/url + var/width + var/height + var/proxy_url + +/datum/tgs_chat_embed/media/New(url) + if(!istext(url)) + CRASH("[/datum/tgs_chat_embed/media] created with no url!") + + src.url = url + +/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure for details. +/datum/tgs_chat_embed/footer + /// Must be set in New(). + var/text + var/icon_url + var/proxy_icon_url + +/datum/tgs_chat_embed/footer/New(text) + if(!istext(text)) + CRASH("[/datum/tgs_chat_embed/footer] created with no text!") + + src.text = text + +/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-provider-structure for details. +/datum/tgs_chat_embed/provider + var/name + var/url + +/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure for details. Must have name set in New(). +/datum/tgs_chat_embed/provider/author + var/icon_url + var/proxy_icon_url + +/datum/tgs_chat_embed/provider/author/New(name) + if(!istext(name)) + CRASH("[/datum/tgs_chat_embed/provider/author] created with no name!") + + src.name = name + +/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure for details. Must have name and value set in New(). +/datum/tgs_chat_embed/field + var/name + var/value + var/is_inline + +/datum/tgs_chat_embed/field/New(name, value) + if(!istext(name)) + CRASH("[/datum/tgs_chat_embed/field] created with no name!") + + if(!istext(value)) + CRASH("[/datum/tgs_chat_embed/field] created with no value!") + + src.name = name + src.value = value + // API FUNCTIONS /// Returns the maximum supported [/datum/tgs_version] of the DMAPI. @@ -285,75 +403,73 @@ // No function below this succeeds if it TgsAvailable() returns FALSE or if TgsNew() has yet to be called. /** - * Forces a hard reboot of DreamDaemon by ending the process. + * Forces a hard reboot of DreamDaemon by ending the process. This function may sleep! * * Unlike del(world) clients will try to reconnect. - * If TGS has not requested a [TGS_REBOOT_MODE_SHUTDOWN] DreamDaemon will be launched again + * If TGS has not requested a [TGS_REBOOT_MODE_SHUTDOWN] DreamDaemon will be launched again. */ /world/proc/TgsEndProcess() return /** - * Send a message to connected chats. + * Send a message to connected chats. This function may sleep! * - * message - The string to send. + * message - The [/datum/tgs_message_content] to send. * admin_only: If [TRUE], message will be sent to admin connected chats. Vice-versa applies. */ -/world/proc/TgsTargetedChatBroadcast(message, admin_only = FALSE) +/world/proc/TgsTargetedChatBroadcast(datum/tgs_message_content/message, admin_only = FALSE) return /** - * Send a private message to a specific user. + * Send a private message to a specific user. This function may sleep! * - * message - The string to send. + * message - The [/datum/tgs_message_content] to send. * user: The [/datum/tgs_chat_user] to PM. */ -/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user) +/world/proc/TgsChatPrivateMessage(datum/tgs_message_content/message, datum/tgs_chat_user/user) return -// The following functions will sleep if a call to TgsNew() is sleeping - /** - * Send a message to connected chats that are flagged as game-related in TGS. + * Send a message to connected chats that are flagged as game-related in TGS. This function may sleep! * - * message - The string to send. + * message - The [/datum/tgs_message_content] to send. * channels - Optional list of [/datum/tgs_chat_channel]s to restrict the message to. */ -/world/proc/TgsChatBroadcast(message, list/channels = null) +/world/proc/TgsChatBroadcast(datum/tgs_message_content/message, list/channels = null) return -/// Returns the current [/datum/tgs_version] of TGS if it is running the server, null otherwise. +/// Returns the current [/datum/tgs_version] of TGS if it is running the server, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsVersion() return -/// Returns the current [/datum/tgs_version] of the DMAPI being used if it was activated, null otherwise. +/// Returns the current [/datum/tgs_version] of the DMAPI being used if it was activated, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsApiVersion() return -/// Returns the name of the TGS instance running the game if TGS is present, null otherwise. +/// Returns the name of the TGS instance running the game if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsInstanceName() return -/// Return the current [/datum/tgs_revision_information] of the running server if TGS is present, null otherwise. +/// Return the current [/datum/tgs_revision_information] of the running server if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsRevision() return -/// Returns the current BYOND security level as a TGS_SECURITY_ define if TGS is present, null otherwise. +/// Returns the current BYOND security level as a TGS_SECURITY_ define if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsSecurityLevel() return -/// Returns a list of active [/datum/tgs_revision_information/test_merge]s if TGS is present, null otherwise. +/// Returns a list of active [/datum/tgs_revision_information/test_merge]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsTestMerges() return -/// Returns a list of connected [/datum/tgs_chat_channel]s if TGS is present, null otherwise. +/// Returns a list of connected [/datum/tgs_chat_channel]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsChatChannelInfo() return /* The MIT License -Copyright (c) 2017 Jordan Brown +Copyright (c) 2017-2023 Jordan Brown Permission is hereby granted, free of charge, to any person obtaining a copy of this software and diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm index 865088ee72fc..ca6408961eab 100644 --- a/code/__DEFINES/tgui.dm +++ b/code/__DEFINES/tgui.dm @@ -32,7 +32,7 @@ /// Creates a message packet for sending via output() // This is {"type":type,"payload":payload}, but pre-encoded. This is much faster // than doing it the normal way. -// To ensure this is correct, this is unit tested in tgui_create_message. However, CM does not have unit tests available. +// To ensure this is correct, this is unit tested in tgui_create_message. #define TGUI_CREATE_MESSAGE(type, payload) ( \ "%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \ ) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index c2c0fad24c6a..f7407587b075 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -123,10 +123,12 @@ #define TRAIT_SUPER_STRONG "t_super_strong" /// Foreign biology. Basic medHUDs won't show the mob. (Yautja, Zombies) #define TRAIT_FOREIGN_BIO "t_foreign_bio" -/// Eye color changes on intent. (G1 Synths) +/// Eye color changes on intent. (G1 Synths and WJs) #define TRAIT_INTENT_EYES "t_intent_eyes" /// Masked synthetic biology. Basic medHUDs will percieve the mob as human. (Infiltrator Synths) #define TRAIT_INFILTRATOR_SYNTH "t_infiltrator_synth" +/// Makes it impossible to strip the inventory of this mob. +#define TRAIT_UNSTRIPPABLE "t_unstrippable" // HIVE TRAITS /// If the Hive is a Xenonid Hive @@ -149,7 +151,7 @@ #define TRAIT_TWOBORE_TRAINING "t_twobore" /// If the mob has equipment that alleviates nearsightedness #define TRAIT_NEARSIGHTED_EQUIPMENT "t_nearsighted_eq" -/// If the mob is affected by drag delay.area +/// If the mob is affected by drag delay. #define TRAIT_DEXTROUS "t_dextrous" /// If the mob is currently charging (xeno only) #define TRAIT_CHARGING "t_charging" @@ -157,6 +159,8 @@ #define TRAIT_LEADERSHIP "t_leadership" /// If the mob can see the reagents contents of stuff #define TRAIT_REAGENT_SCANNER "reagent_scanner" +/// If the mob cannot eat/be fed +#define TRAIT_CANNOT_EAT "t_cannot_eat" /// If the mob is being lazed by a sniper spotter #define TRAIT_SPOTTER_LAZED "t_spotter_lazed" /// If the mob has ear protection. Protects from external ear damage effects. Includes explosions, firing the RPG, screeching DEAFNESS only, and flashbangs. @@ -169,12 +173,18 @@ #define TRAIT_EMOTE_CD_EXEMPT "t_emote_cd_exempt" /// If the mob is holding a cane. #define TRAIT_HOLDS_CANE "t_holds_cane" +/// If the mob is buckled to a wheelchair. +#define TRAIT_USING_WHEELCHAIR "t_using_wheelchair" +/// If the mob will instantly go permadead upon death +#define TRAIT_HARDCORE "t_hardcore" // -- ability traits -- /// Xenos with this trait cannot have plasma transfered to them #define TRAIT_ABILITY_NO_PLASMA_TRANSFER "t_ability_no_plasma_transfer" /// Shows that the xeno queen is on ovi #define TRAIT_ABILITY_OVIPOSITOR "t_ability_ovipositor" +/// Used for burrowed mobs, prevent's SG/sentrys/claymores from autofiring +#define TRAIT_ABILITY_BURROWED "t_ability_burrowed" //-- item traits -- // TOOL TRAITS @@ -217,6 +227,8 @@ //ie. naming a regulation tape "example" will become regulation tape (example) #define TRAIT_ITEM_RENAME_SPECIAL "t_item_rename_special" +// This item can't be implanted into someone, regardless of the size of the item. +#define TRAIT_ITEM_NOT_IMPLANTABLE "t_item_not_implantable" //-- structure traits -- // TABLE TRAITS @@ -235,7 +247,8 @@ GLOBAL_LIST_INIT(mob_traits, list( TRAIT_TWOBORE_TRAINING, TRAIT_LEADERSHIP, TRAIT_DEXTROUS, - TRAIT_REAGENT_SCANNER + TRAIT_REAGENT_SCANNER, + TRAIT_ABILITY_BURROWED )) /* @@ -250,6 +263,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_FOREIGN_BIO" = TRAIT_FOREIGN_BIO, "TRAIT_INTENT_EYES" = TRAIT_INTENT_EYES, "TRAIT_INFILTRATOR_SYNTH" = TRAIT_INFILTRATOR_SYNTH, + "TRAIT_UNSTRIPPABLE" = TRAIT_UNSTRIPPABLE, "TRAIT_NESTED" = TRAIT_NESTED, "TRAIT_CRAWLER" = TRAIT_CRAWLER, "TRAIT_SIMPLE_DESC" = TRAIT_SIMPLE_DESC, @@ -265,6 +279,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BIMEX" = TRAIT_BIMEX, "TRAIT_EMOTE_CD_EXEMPT" = TRAIT_EMOTE_CD_EXEMPT, "TRAIT_LISPING" = TRAIT_LISPING, + "TRAIT_CANNOT_EAT" = TRAIT_CANNOT_EAT, ), /mob/living/carbon/xenomorph = list( "TRAIT_ABILITY_NO_PLASMA_TRANSFER" = TRAIT_ABILITY_NO_PLASMA_TRANSFER, diff --git a/code/__DEFINES/typecheck/humanoids.dm b/code/__DEFINES/typecheck/humanoids.dm index 58d245c486e4..7076cf67c95c 100644 --- a/code/__DEFINES/typecheck/humanoids.dm +++ b/code/__DEFINES/typecheck/humanoids.dm @@ -25,7 +25,7 @@ #define isspeciessynth(A) (A.species?.group == SPECIES_SYNTHETIC) //Size checks for carbon to use instead of typechecks. (Hellhounds are deprecated) -#define iscarbonsizexeno(A) (A.mob_size >= MOB_SIZE_XENO_SMALL) +#define iscarbonsizexeno(A) (A.mob_size >= MOB_SIZE_XENO_VERY_SMALL) #define iscarbonsizehuman(A) (A.mob_size <= MOB_SIZE_HUMAN) //job/role helpers diff --git a/code/__DEFINES/typecheck/mobs_generic.dm b/code/__DEFINES/typecheck/mobs_generic.dm index 49e4463435a6..1d848decda4e 100644 --- a/code/__DEFINES/typecheck/mobs_generic.dm +++ b/code/__DEFINES/typecheck/mobs_generic.dm @@ -1,4 +1,5 @@ #define isAI(A) (istype(A, /mob/living/silicon/ai)) +#define isARES(A) (istype(A, /mob/living/silicon/decoy/ship_ai)) #define isSilicon(A) (istype(A, /mob/living/silicon)) #define isRemoteControlling(M) (M && M.client && M.client.remote_control) #define isRemoteControllingOrAI(M) ((M && M.client && M.client.remote_control) || (istype(M, /mob/living/silicon/ai))) diff --git a/code/__DEFINES/typecheck/xenos.dm b/code/__DEFINES/typecheck/xenos.dm index 4d1b7819bdf1..34b70ac92f45 100644 --- a/code/__DEFINES/typecheck/xenos.dm +++ b/code/__DEFINES/typecheck/xenos.dm @@ -14,6 +14,7 @@ #define islarva(A) (istype(A, /mob/living/carbon/xenomorph/larva)) #define ispredalienlarva(A) (istype(A, /mob/living/carbon/xenomorph/larva/predalien)) #define isfacehugger(A) (istype(A, /mob/living/carbon/xenomorph/facehugger)) +#define islesserdrone(A) (istype(A, /mob/living/carbon/xenomorph/lesser_drone)) #define ispraetorian(A) (istype(A, /mob/living/carbon/xenomorph/praetorian)) #define isqueen(A) (istype(A, /mob/living/carbon/xenomorph/queen)) #define isravager(A) (istype(A, /mob/living/carbon/xenomorph/ravager)) @@ -36,6 +37,10 @@ if(!hive) return FALSE + if(hivenumber == XENO_HIVE_RENEGADE) + var/datum/hive_status/corrupted/renegade/renegade_hive = hive + return renegade_hive.iff_protection_check(src, attempt_harm_mob) + return hive.is_ally(attempt_harm_mob) // need this to set the data for walls/eggs/huggers when they are initialized diff --git a/code/__DEFINES/urls.dm b/code/__DEFINES/urls.dm index ee964745b056..4d9268220f2b 100644 --- a/code/__DEFINES/urls.dm +++ b/code/__DEFINES/urls.dm @@ -26,7 +26,7 @@ #define URL_WIKI_SO_GUIDE "https://cm-ss13.com/wiki/Staff_Officer" #define URL_WIKI_SEA_GUIDE "https://cm-ss13.com/wiki/Senior_Enlisted_Advisor" #define URL_WIKI_SL_GUIDE "https://cm-ss13.com/wiki/Squad_Leader" -#define URL_WIKI_RTO_GUIDE "https://cm-ss13.com/wiki/Squad_Radio_Telephone_Operator" // Squad Roles // +#define URL_WIKI_TL_GUIDE "https://cm-ss13.com/wiki/Squad_Radio_Telephone_Operator" // Squad Roles // #define URL_WIKI_SPEC_GUIDE "https://cm-ss13.com/wiki/Squad_Specialist" #define URL_WIKI_SG_GUIDE "https://cm-ss13.com/wiki/Squad_Smartgunner" #define URL_WIKI_MEDIC_GUIDE "https://cm-ss13.com/wiki/Squad_Hospital_Corpsman" @@ -34,7 +34,8 @@ #define URL_WIKI_CMP_GUIDE "https://cm-ss13.com/wiki/Chief_MP" // MP Roles // #define URL_WIKI_MW_GUIDE "https://cm-ss13.com/wiki/Warden" #define URL_WIKI_MP_GUIDE "https://cm-ss13.com/wiki/Military_Police" -#define URL_WIKI_PO_GUIDE "https://cm-ss13.com/wiki/Pilot_Officer" // Auxiliary Support +#define URL_WIKI_ASO_GUIDE "https://cm-ss13.com/wiki/Auxiliary_Support_Officer" // Auxiliary Support +#define URL_WIKI_PO_GUIDE "https://cm-ss13.com/wiki/Pilot_Officer" #define URL_WIKI_DCC_GUIDE "https://cm-ss13.com/wiki/Dropship_Crew_Chief" #define URL_WIKI_IO_GUIDE "https://cm-ss13.com/wiki/Intelligence_Officer" #define URL_WIKI_SYN_GUIDE "https://cm-ss13.com/wiki/Synthetic" @@ -50,6 +51,7 @@ #define URL_WIKI_MST_GUIDE "https://cm-ss13.com/wiki/Mess_Technician" #define URL_WIKI_CL_GUIDE "https://cm-ss13.com/wiki/Corporate_Liaison" // Misc // #define URL_WIKI_SURV_GUIDE "https://cm-ss13.com/wiki/Survivor" +#define URL_WIKI_WJ_GUIDE "https://cm-ss13.com/wiki/Seegson_Working_Joe_Manual" // ------ FORUM LINKS ------ // #define URL_FORUM "https://forum.cm-ss13.com/" diff --git a/code/__DEFINES/vendors.dm b/code/__DEFINES/vendors.dm index 1011bad11a58..04ee5ffef2b6 100644 --- a/code/__DEFINES/vendors.dm +++ b/code/__DEFINES/vendors.dm @@ -1,30 +1,26 @@ -#define MARINE_CAN_BUY_UNIFORM (1<<0) -#define MARINE_CAN_BUY_SHOES (1<<1) -#define MARINE_CAN_BUY_HELMET (1<<2) -#define MARINE_CAN_BUY_ARMOR (1<<3) -#define MARINE_CAN_BUY_GLOVES (1<<4) -#define MARINE_CAN_BUY_EAR (1<<5) -#define MARINE_CAN_BUY_BACKPACK (1<<6) -#define MARINE_CAN_BUY_R_POUCH (1<<7) -#define MARINE_CAN_BUY_L_POUCH (1<<8) -#define MARINE_CAN_BUY_BELT (1<<9) -#define MARINE_CAN_BUY_GLASSES (1<<10) -#define MARINE_CAN_BUY_MASK (1<<11) -#define MARINE_CAN_BUY_ESSENTIALS (1<<12) -#define MARINE_CAN_BUY_SECONDARY (1<<13) -#define MARINE_CAN_BUY_ATTACHMENT (1<<14) -#define MARINE_CAN_BUY_MRE (1<<15) -#define MARINE_CAN_BUY_ACCESSORY (1<<16) +#define MARINE_CAN_BUY_UNIFORM "uniform" +#define MARINE_CAN_BUY_SHOES "shoes" +#define MARINE_CAN_BUY_HELMET "helmet" +#define MARINE_CAN_BUY_ARMOR "armor" +#define MARINE_CAN_BUY_GLOVES "gloves" +#define MARINE_CAN_BUY_EAR "ear" +#define MARINE_CAN_BUY_BACKPACK "backpack" +#define MARINE_CAN_BUY_POUCH "pouch" +#define MARINE_CAN_BUY_BELT "belt" +#define MARINE_CAN_BUY_GLASSES "glasses" +#define MARINE_CAN_BUY_MASK "mask" +#define MARINE_CAN_BUY_ESSENTIALS "essentials" +#define MARINE_CAN_BUY_SECONDARY "secondary" +#define MARINE_CAN_BUY_ATTACHMENT "attachment" +#define MARINE_CAN_BUY_MRE "mre" +#define MARINE_CAN_BUY_ACCESSORY "accessory" +#define MARINE_CAN_BUY_COMBAT_SHOES "combat_shoes" +#define MARINE_CAN_BUY_COMBAT_HELMET "combat_helmet" +#define MARINE_CAN_BUY_COMBAT_ARMOR "combat_armor" +#define MARINE_CAN_BUY_KIT "kit" +#define MARINE_CAN_BUY_DRESS "dress" -#define MARINE_CAN_BUY_COMBAT_SHOES (1<<17) -#define MARINE_CAN_BUY_COMBAT_HELMET (1<<18) -#define MARINE_CAN_BUY_COMBAT_ARMOR (1<<19) -#define MARINE_CAN_BUY_COMBAT_R_POUCH (1<<20) -#define MARINE_CAN_BUY_COMBAT_L_POUCH (1<<21) - -#define MARINE_CAN_BUY_KIT (1<<22) - -#define MARINE_CAN_BUY_ALL ((1<<23) - 1) +#define MARINE_CAN_BUY_ALL list(MARINE_CAN_BUY_UNIFORM = 1, MARINE_CAN_BUY_SHOES = 1, MARINE_CAN_BUY_HELMET = 1, MARINE_CAN_BUY_ARMOR = 1, MARINE_CAN_BUY_GLOVES = 1, MARINE_CAN_BUY_EAR = 1, MARINE_CAN_BUY_BACKPACK = 1, MARINE_CAN_BUY_POUCH = 2, MARINE_CAN_BUY_BELT = 1, MARINE_CAN_BUY_GLASSES = 1, MARINE_CAN_BUY_MASK = 1, MARINE_CAN_BUY_ESSENTIALS = 1, MARINE_CAN_BUY_SECONDARY = 1, MARINE_CAN_BUY_ATTACHMENT = 1, MARINE_CAN_BUY_MRE = 1, MARINE_CAN_BUY_ACCESSORY = 1, MARINE_CAN_BUY_COMBAT_SHOES = 1, MARINE_CAN_BUY_COMBAT_HELMET = 1, MARINE_CAN_BUY_COMBAT_ARMOR = 1, MARINE_CAN_BUY_KIT = 1, MARINE_CAN_BUY_DRESS = 99) #define MARINE_TOTAL_BUY_POINTS 45 #define MARINE_TOTAL_SNOWFLAKE_POINTS 120 diff --git a/code/__DEFINES/weapon_stats.dm b/code/__DEFINES/weapon_stats.dm index 58dad90b0710..590223426a66 100644 --- a/code/__DEFINES/weapon_stats.dm +++ b/code/__DEFINES/weapon_stats.dm @@ -1,7 +1,7 @@ #define HUMAN_UNIVERSAL_DAMAGEMULT 1 #define RECOIL_BUILDUP_VIEWPUNCH_MULTIPLIER 0.1 - +#define BASE_VELOCITY_BONUS 0 #define PROJ_BASE_ACCURACY_MULT 0.01 #define PROJ_BASE_DAMAGE_MULT 0.01 @@ -136,19 +136,21 @@ As such, don't expect any values assigned to common firearms to even consider ho //How many ticks you have to wait between firing. Burst delay uses the same variable! */ -#define FIRE_DELAY_TIER_1 10 -#define FIRE_DELAY_TIER_2 9 -#define FIRE_DELAY_TIER_3 8 -#define FIRE_DELAY_TIER_4 7 -#define FIRE_DELAY_TIER_5 6 -#define FIRE_DELAY_TIER_6 5 -#define FIRE_DELAY_TIER_7 4 -#define FIRE_DELAY_TIER_8 3 -#define FIRE_DELAY_TIER_9 2 -#define FIRE_DELAY_TIER_LMG 1.5 -#define FIRE_DELAY_TIER_SG 1.5 -#define FIRE_DELAY_TIER_SMG 1.3 -#define FIRE_DELAY_TIER_10 1 +#define FIRE_DELAY_TIER_1 12 +#define FIRE_DELAY_TIER_2 10 +#define FIRE_DELAY_TIER_3 9 +#define FIRE_DELAY_TIER_4 8 +#define FIRE_DELAY_TIER_5 7 +#define FIRE_DELAY_TIER_6 6 +#define FIRE_DELAY_TIER_7 5 +#define FIRE_DELAY_TIER_8 4 +#define FIRE_DELAY_TIER_9 3.5 +#define FIRE_DELAY_TIER_10 3 +#define FIRE_DELAY_TIER_11 2.5 +#define FIRE_DELAY_TIER_LMG 2 +#define FIRE_DELAY_TIER_SG 2 +#define FIRE_DELAY_TIER_SMG 1.5 +#define FIRE_DELAY_TIER_12 1 /* ////RANGE RELATED//// diff --git a/code/__DEFINES/weather.dm b/code/__DEFINES/weather.dm index 16ee8154241f..c67575f80720 100644 --- a/code/__DEFINES/weather.dm +++ b/code/__DEFINES/weather.dm @@ -5,6 +5,7 @@ #define PROB_WEATHER_SOROKYNE 100 //Map specific defines go here. #define PROB_WEATHER_BIG_RED 30 #define PROB_WEATHER_LV624 30 +#define PROB_WEATHER_NEW_VARADERO 100 #define WEATHER_TYPE_NO_WEATHER 0 #define WEATHER_TYPE_SNOW 1 diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm index e73aa5093855..0f822385ad13 100644 --- a/code/__DEFINES/xeno.dm +++ b/code/__DEFINES/xeno.dm @@ -8,6 +8,9 @@ #define TUNNEL_ENTER_BIG_XENO_DELAY 120 #define TUNNEL_ENTER_LARVA_DELAY 10 +/// The duration it takes a player controlled facehugger to leap or hug adjacently +#define FACEHUGGER_WINDUP_DURATION 1 SECONDS + // Defines for action types and click delays used by xenomorph/unarmedattack() and attack_alien(). /// Full attack delay. @@ -70,6 +73,7 @@ #define HUD_ARMOR_STATES_XENO 10 /// Multiplier for time taken for a xeno to place down a resin structure +#define BUILD_TIME_MULT_LESSER_DRONE 2 #define BUILD_TIME_MULT_XENO 1 #define BUILD_TIME_MULT_BUILDER 1 #define BUILD_TIME_MULT_HIVELORD 0.5 @@ -132,6 +136,7 @@ // Weed defines #define WEED_LEVEL_WEAK 0 #define WEED_LEVEL_STANDARD 1.5 +#define WEED_LEVEL_HARDY 1.6 #define WEED_LEVEL_HIVE 4 #define WEED_RANGE_STANDARD 3 @@ -154,6 +159,30 @@ #define WEED_BASE_GROW_SPEED (5 SECONDS) #define WEED_BASE_DECAY_SPEED (10 SECONDS) +/// The time you must be dead to join as a xeno larva +#define XENO_JOIN_DEAD_LARVA_TIME (2.5 MINUTES) +/// The time you must be dead to join as xeno (not larva) +#define XENO_JOIN_DEAD_TIME (5 MINUTES) +/// The time of inactivity you cannot exceed to join as a xeno +#define XENO_JOIN_AFK_TIME_LIMIT (5 MINUTES) +/// The amount of time after round start before buried larva spawns are disallowed +#define XENO_BURIED_LARVA_TIME_LIMIT (30 MINUTES) + +/// The time when xenos can start taking over comm towers +#define XENO_COMM_ACQUISITION_TIME (90 MINUTES) + +/// The time it takes for a pylon to give one larva while activated +#define XENO_PYLON_ACTIVATION_COOLDOWN (5 MINUTES) + +/// The time against away_timer when an AFK xeno larva can be replaced +#define XENO_LEAVE_TIMER_LARVA 80 //80 seconds +/// The time against away_timer when an AFK xeno (not larva) can be replaced +#define XENO_LEAVE_TIMER 300 //300 seconds +/// The time against away_timer when an AFK facehugger converts to a npc +#define XENO_FACEHUGGER_LEAVE_TIMER 420 //420 seconds +/// The time against away_timer when an AFK xeno gets listed in the available list so ghosts can get ready +#define XENO_AVAILABLE_TIMER 60 //60 seconds + /// Between 2% to 10% of explosion severity #define WEED_EXPLOSION_DAMAGEMULT rand(2, 10)*0.01 @@ -187,6 +216,7 @@ // Health bands #define XENO_HEALTH_LARVA 35 * XENO_UNIVERSAL_HPMULT +#define XENO_HEALTH_LESSER_DRONE 160 * XENO_UNIVERSAL_HPMULT #define XENO_HEALTH_RUNNER 230 * XENO_UNIVERSAL_HPMULT // Killed by 1 PB #define XENO_HEALTH_TIER_1 250 * XENO_UNIVERSAL_HPMULT #define XENO_HEALTH_TIER_2 300 * XENO_UNIVERSAL_HPMULT @@ -329,41 +359,41 @@ ///////////////////////////////////////////////////////////////////////////////////// // Damage - this is applied as a flat nerf/buff to the xeno's average damage -#define XENO_DAMAGE_MOD_VERYSMALL 5 +#define XENO_DAMAGE_MOD_VERY_SMALL 5 #define XENO_DAMAGE_MOD_SMALL 10 #define XENO_DAMAGE_MOD_MED 15 #define XENO_DAMAGE_MOD_LARGE 20 -#define XENO_DAMAGE_MOD_VERYLARGE 25 +#define XENO_DAMAGE_MOD_VERY_LARGE 25 // Overall health pool -#define XENO_HEALTH_MOD_VERYSMALL 20 +#define XENO_HEALTH_MOD_VERY_SMALL 20 #define XENO_HEALTH_MOD_SMALL 40 #define XENO_HEALTH_MOD_MED 60 #define XENO_HEALTH_MOD_LARGE 80 -#define XENO_HEALTH_MOD_VERYLARGE 100 +#define XENO_HEALTH_MOD_VERY_LARGE 100 #define XENO_HEALTH_MOD_ACIDER 115 // Armor mods. Use the above defines for some guidance // In general, +20 armor should be a little more than +20% effective HP, however, // the higher the Xeno's base armor, the greater the effect. -#define XENO_ARMOR_MOD_VERYSMALL 5 +#define XENO_ARMOR_MOD_VERY_SMALL 5 #define XENO_ARMOR_MOD_SMALL 10 #define XENO_ARMOR_MOD_MED 15 #define XENO_ARMOR_MOD_LARGE 20 -#define XENO_ARMOR_MOD_VERYLARGE 25 +#define XENO_ARMOR_MOD_VERY_LARGE 25 -#define XENO_EXPOSIVEARMOR_MOD_VERYSMALL 10 +#define XENO_EXPOSIVEARMOR_MOD_VERY_SMALL 10 #define XENO_EXPOSIVEARMOR_MOD_SMALL 20 #define XENO_EXPOSIVEARMOR_MOD_MED 30 #define XENO_EXPOSIVEARMOR_MOD_LARGE 40 -#define XENO_EXPOSIVEARMOR_MOD_VERYLARGE 50 +#define XENO_EXPOSIVEARMOR_MOD_VERY_LARGE 50 // Plasma -#define XENO_PLASMAPOOL_MOD_VERYSMALL 20 +#define XENO_PLASMAPOOL_MOD_VERY_SMALL 20 #define XENO_PLASMAPOOL_MOD_SMALL 40 #define XENO_PLASMAPOOL_MOD_MED 60 #define XENO_PLASMAPOOL_MOD_LARGE 80 -#define XENO_PLASMAPOOL_MOD_VERYLARGE 100 +#define XENO_PLASMAPOOL_MOD_VERY_LARGE 100 // Plasma regen #define XENO_PLASMAGAIN_MOD_SMALL 0.1 @@ -403,26 +433,26 @@ #define XENO_NEURO_TIER_5 2 // Pheremone strength modifiers -#define XENO_PHERO_MOD_VERYSMALL 0.25 +#define XENO_PHERO_MOD_VERY_SMALL 0.25 #define XENO_PHERO_MOD_SMALL 0.5 #define XENO_PHERO_MOD_MED 0.75 #define XENO_PHERO_MOD_LARGE 1 -#define XENO_PHERO_MOD_VERYLARGE 1.25 +#define XENO_PHERO_MOD_VERY_LARGE 1.25 // Evasion modifiers -#define XENO_EVASION_MOD_VERYSMALL 3 +#define XENO_EVASION_MOD_VERY_SMALL 3 #define XENO_EVASION_MOD_SMALL 6 #define XENO_EVASION_MOD_MED 9 #define XENO_EVASION_MOD_LARGE 12 -#define XENO_EVASION_MOD_VERYLARGE 15 +#define XENO_EVASION_MOD_VERY_LARGE 15 #define XENO_EVASION_MOD_ULTRA 25 // Armor factor modifiers -#define XENO_ARMORFACTOR_MOD_VERYSMALL 5 +#define XENO_ARMORFACTOR_MOD_VERY_SMALL 5 #define XENO_ARMORFACTOR_MOD_SMALL 10 #define XENO_ARMORFACTOR_MOD_MED 15 #define XENO_ARMORFACTOR_MOD_LARGE 20 -#define XENO_ARMORFACTOR_MOD_VERYLARGE 25 +#define XENO_ARMORFACTOR_MOD_VERY_LARGE 25 // Acid boost (I guess, this is used literally nowhere) // Feel free to add more defines here if it ever becomes relevant @@ -584,7 +614,8 @@ #define XENO_CASTE_LARVA "Bloody Larva" #define XENO_CASTE_PREDALIEN_LARVA "Predalien Larva" #define XENO_CASTE_FACEHUGGER "Facehugger" -#define XENO_T0_CASTES list(XENO_CASTE_LARVA, XENO_CASTE_PREDALIEN_LARVA, XENO_CASTE_FACEHUGGER) +#define XENO_CASTE_LESSER_DRONE "Lesser Drone" +#define XENO_T0_CASTES list(XENO_CASTE_LARVA, XENO_CASTE_PREDALIEN_LARVA, XENO_CASTE_FACEHUGGER, XENO_CASTE_LESSER_DRONE) //t1 #define XENO_CASTE_DRONE "Drone" @@ -612,7 +643,7 @@ #define XENO_CASTE_HELLHOUND "Hellhound" #define XENO_SPECIAL_CASTES list(XENO_CASTE_QUEEN, XENO_CASTE_PREDALIEN, XENO_CASTE_HELLHOUND) -#define ALL_XENO_CASTES list(XENO_CASTE_LARVA, XENO_CASTE_PREDALIEN_LARVA, XENO_CASTE_FACEHUGGER, XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_SENTINEL, XENO_CASTE_DEFENDER, XENO_CASTE_BURROWER, XENO_CASTE_CARRIER, XENO_CASTE_HIVELORD, XENO_CASTE_LURKER, XENO_CASTE_WARRIOR, XENO_CASTE_SPITTER, XENO_CASTE_BOILER, XENO_CASTE_PRAETORIAN, XENO_CASTE_CRUSHER, XENO_CASTE_RAVAGER, XENO_CASTE_QUEEN, XENO_CASTE_PREDALIEN, XENO_CASTE_HELLHOUND) +#define ALL_XENO_CASTES list(XENO_CASTE_LARVA, XENO_CASTE_PREDALIEN_LARVA, XENO_CASTE_FACEHUGGER, XENO_CASTE_LESSER_DRONE, XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_SENTINEL, XENO_CASTE_DEFENDER, XENO_CASTE_BURROWER, XENO_CASTE_CARRIER, XENO_CASTE_HIVELORD, XENO_CASTE_LURKER, XENO_CASTE_WARRIOR, XENO_CASTE_SPITTER, XENO_CASTE_BOILER, XENO_CASTE_PRAETORIAN, XENO_CASTE_CRUSHER, XENO_CASTE_RAVAGER, XENO_CASTE_QUEEN, XENO_CASTE_PREDALIEN, XENO_CASTE_HELLHOUND) // Checks if two hives are allied to each other. // PARAMETERS: @@ -628,7 +659,12 @@ #define FIRE_IMMUNITY_XENO_FRENZY (1<<2) #define FIRE_VULNERABILITY (1<<3) -#define FIRE_VULNERABILITY_MULTIPLIER 1.5 +#define FIRE_MULTIPLIER_BASE 1 +#define FIRE_MULTIPLIER_LOW 1.25 +#define FIRE_MULTIPLIER_MEDIUM 1.5 +#define FIRE_MULTIPLIER_HIGH 1.75 // Really starts chunking HP +#define FIRE_MULTIPLIER_EXTREME 2 +#define FIRE_MULTIPLIER_DEADLY 3 #define TRAPPER_VIEWRANGE 13 @@ -671,3 +707,6 @@ #define TAILSTAB_AIRLOCK_DAMAGE_MULTIPLIER 2 #define FRENZY_DAMAGE_MULTIPLIER 2 + +#define JOIN_AS_FACEHUGGER_DELAY (3 MINUTES) +#define JOIN_AS_LESSER_DRONE_DELAY (30 SECONDS) diff --git a/code/__HELPERS/BSQL/LICENSE b/code/__HELPERS/BSQL/LICENSE deleted file mode 100644 index 2bee2909144b..000000000000 --- a/code/__HELPERS/BSQL/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2018 Jordan Brown - -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. \ No newline at end of file diff --git a/code/__HELPERS/BSQL/core/connection.dm b/code/__HELPERS/BSQL/core/connection.dm deleted file mode 100644 index fb8f729390ac..000000000000 --- a/code/__HELPERS/BSQL/core/connection.dm +++ /dev/null @@ -1,68 +0,0 @@ -/datum/BSQL_Connection - var/id - var/connection_type - -BSQL_PROTECT_DATUM(/datum/BSQL_Connection) - -/datum/BSQL_Connection/New(connection_type, asyncTimeout, blockingTimeout, threadLimit) - if(asyncTimeout == null) - asyncTimeout = BSQL_DEFAULT_TIMEOUT - if(blockingTimeout == null) - blockingTimeout = asyncTimeout - if(threadLimit == null) - threadLimit = BSQL_DEFAULT_THREAD_LIMIT - - src.connection_type = connection_type - - world._BSQL_InitCheck(src) - - var/error = world._BSQL_Internal_Call("CreateConnection", connection_type, "[asyncTimeout]", "[blockingTimeout]", "[threadLimit]") - if(error) - BSQL_ERROR(error) - return - - id = world._BSQL_Internal_Call("GetConnection") - if(!id) - BSQL_ERROR("BSQL library failed to provide connect operation for connection id [id]([connection_type])!") - -BSQL_DEL_PROC(/datum/BSQL_Connection) - var/error - if(id) - error = world._BSQL_Internal_Call("ReleaseConnection", id) - . = ..() - if(error) - BSQL_ERROR(error) - -/datum/BSQL_Connection/BeginConnect(ipaddress, port, username, password, database) - var/error = world._BSQL_Internal_Call("OpenConnection", id, ipaddress, "[port]", username, password, database) - if(error) - BSQL_ERROR(error) - return - - var/op_id = world._BSQL_Internal_Call("GetOperation") - if(!op_id) - BSQL_ERROR("Library failed to provide connect operation for connection id [id]([connection_type])!") - return - - return new /datum/BSQL_Operation(src, op_id) - - -/datum/BSQL_Connection/BeginQuery(query) - var/error = world._BSQL_Internal_Call("NewQuery", id, query) - if(error) - BSQL_ERROR(error) - return - - var/op_id = world._BSQL_Internal_Call("GetOperation") - if(!op_id) - BSQL_ERROR("Library failed to provide query operation for connection id [id]([connection_type])!") - return - - return new /datum/BSQL_Operation/Query(src, op_id) - -/datum/BSQL_Connection/Quote(str) - if(!str) - return null; - . = world._BSQL_Internal_Call("QuoteString", id, "[str]") - if(!.) - BSQL_ERROR("Library failed to provide quote for [str]!") diff --git a/code/__HELPERS/BSQL/core/library.dm b/code/__HELPERS/BSQL/core/library.dm deleted file mode 100644 index 615820c138ca..000000000000 --- a/code/__HELPERS/BSQL/core/library.dm +++ /dev/null @@ -1,43 +0,0 @@ -/world/proc/_BSQL_Internal_Call(func, ...) - var/list/call_args = args.Copy(2) - BSQL_Debug("_BSQL_Internal_Call: [args[1]]([call_args.Join(", ")])") - . = LIBCALL(_BSQL_Library_Path(), func)(arglist(call_args)) - BSQL_Debug("Result: [. == null ? "NULL" : "\"[.]\""]") - -/world/proc/_BSQL_Library_Path() - return system_type == MS_WINDOWS ? "BSQL.dll" : "libBSQL.so" - -/world/proc/_BSQL_InitCheck(datum/BSQL_Connection/caller) - var/static/library_initialized = FALSE - if(_BSQL_Initialized()) - return - var/libPath = _BSQL_Library_Path() - if(!fexists(libPath)) - BSQL_DEL_CALL(caller) - BSQL_ERROR("Could not find [libPath]!") - return - - var/version = _BSQL_Internal_Call("Version") - if(version != BSQL_VERSION) - BSQL_DEL_CALL(caller) - BSQL_ERROR("BSQL DMAPI version mismatch! Expected [BSQL_VERSION], got [version == null ? "NULL" : version]!") - return - - var/result = _BSQL_Internal_Call("Initialize") - if(result) - BSQL_DEL_CALL(caller) - BSQL_ERROR(result) - return - _BSQL_Initialized(TRUE) - -/world/proc/_BSQL_Initialized(new_val) - var/static/bsql_library_initialized = FALSE - if(new_val != null) - bsql_library_initialized = new_val - return bsql_library_initialized - -/world/BSQL_Shutdown() - if(!_BSQL_Initialized()) - return - _BSQL_Internal_Call("Shutdown") - _BSQL_Initialized(FALSE) diff --git a/code/__HELPERS/BSQL/core/operation.dm b/code/__HELPERS/BSQL/core/operation.dm deleted file mode 100644 index e583f4264ab5..000000000000 --- a/code/__HELPERS/BSQL/core/operation.dm +++ /dev/null @@ -1,47 +0,0 @@ -/datum/BSQL_Operation - var/datum/BSQL_Connection/connection - var/id - -BSQL_PROTECT_DATUM(/datum/BSQL_Operation) - -/datum/BSQL_Operation/New(datum/BSQL_Connection/connection, id) - src.connection = connection - src.id = id - -BSQL_DEL_PROC(/datum/BSQL_Operation) - var/error - if(!BSQL_IS_DELETED(connection)) - error = world._BSQL_Internal_Call("ReleaseOperation", connection.id, id) - . = ..() - if(error) - BSQL_ERROR(error) - -/datum/BSQL_Operation/IsComplete() - if(BSQL_IS_DELETED(connection)) - return TRUE - var/result = world._BSQL_Internal_Call("OpComplete", connection.id, id) - if(!result) - BSQL_ERROR("Error fetching operation [id] for connection [connection.id]!") - return - return result == "DONE" - -/datum/BSQL_Operation/GetError() - if(BSQL_IS_DELETED(connection)) - return "Connection deleted!" - return world._BSQL_Internal_Call("GetError", connection.id, id) - -/datum/BSQL_Operation/GetErrorCode() - if(BSQL_IS_DELETED(connection)) - return -2 - return text2num(world._BSQL_Internal_Call("GetErrorCode", connection.id, id)) - -/datum/BSQL_Operation/WaitForCompletion() - if(BSQL_IS_DELETED(connection)) - return - var/error = world._BSQL_Internal_Call("BlockOnOperation", connection.id, id) - if(error) - if(error == "Operation timed out!") //match this with the implementation - return FALSE - BSQL_ERROR("Error waiting for operation [id] for connection [connection.id]! [error]") - return - return TRUE diff --git a/code/__HELPERS/BSQL/core/query.dm b/code/__HELPERS/BSQL/core/query.dm deleted file mode 100644 index fc09fb06b0be..000000000000 --- a/code/__HELPERS/BSQL/core/query.dm +++ /dev/null @@ -1,35 +0,0 @@ -/datum/BSQL_Operation/Query - var/last_result_json - var/list/last_result - -BSQL_PROTECT_DATUM(/datum/BSQL_Operation/Query) - -/datum/BSQL_Operation/Query/CurrentRow() - return last_result - -/datum/BSQL_Operation/Query/IsComplete() - //whole different ballgame here - if(BSQL_IS_DELETED(connection)) - return TRUE - var/result = world._BSQL_Internal_Call("ReadyRow", connection.id, id) - switch(result) - if("DONE") - //load the data - LoadQueryResult() - return TRUE - if("NOTDONE") - return FALSE - else - BSQL_ERROR(result) - -/datum/BSQL_Operation/Query/WaitForCompletion() - . = ..() - if(.) - LoadQueryResult() - -/datum/BSQL_Operation/Query/proc/LoadQueryResult() - last_result_json = world._BSQL_Internal_Call("GetRow", connection.id, id) - if(last_result_json) - last_result = json_decode(last_result_json) - else - last_result = null diff --git a/code/__HELPERS/BSQL/includes.dm b/code/__HELPERS/BSQL/includes.dm deleted file mode 100644 index 890977cb909e..000000000000 --- a/code/__HELPERS/BSQL/includes.dm +++ /dev/null @@ -1,4 +0,0 @@ -#include "core\query.dm" -#include "core\connection.dm" -#include "core\library.dm" -#include "core\operation.dm" diff --git a/code/__HELPERS/_time.dm b/code/__HELPERS/_time.dm index 85acafa0e2f6..b929ae8636b3 100644 --- a/code/__HELPERS/_time.dm +++ b/code/__HELPERS/_time.dm @@ -15,10 +15,6 @@ #define DECISECONDS_TO_HOURS /36000 -#define XENO_LEAVE_TIMER_LARVA 80 //80 seconds -#define XENO_LEAVE_TIMER 300 //300 seconds -#define XENO_AVAILABLE_TIMER 60 //60 seconds, when to add a xeno to the avaliable list so ghosts can get ready - var/midnight_rollovers = 0 var/rollovercheck_last_timeofday = 0 diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 4ca0edcf43d0..ff8e31ad3e8a 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -57,3 +57,12 @@ var/atom/cmp_dist_origin=null /proc/cmp_typepaths_asc(A, B) return sorttext("[B]","[A]") + +/// Compares mobs based on their timeofdeath value in ascending order +/proc/cmp_mob_deathtime_asc(mob/A, mob/B) + return A.timeofdeath - B.timeofdeath + +/// Compares observers based on their larva_queue_time value in ascending order +/// Assumes the client on the observer is not null +/proc/cmp_obs_larvaqueuetime_asc(mob/dead/observer/A, mob/dead/observer/B) + return A.client.player_details.larva_queue_time - B.client.player_details.larva_queue_time diff --git a/code/__HELPERS/files.dm b/code/__HELPERS/files.dm index 717a2ed5347b..f88fe7168f8d 100644 --- a/code/__HELPERS/files.dm +++ b/code/__HELPERS/files.dm @@ -12,11 +12,6 @@ return text -//Sends resource files to client cache -/client/proc/getFiles() - for(var/file in args) - src << browse_rsc(file) - /client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm")) var/path = root diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index a0bb9dd98423..c05795c32b10 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -241,35 +241,80 @@ else return get_step(start, EAST) -// Same as above but for alien candidates. -/proc/get_alien_candidates() +/** + * Get a list of observers that can be alien candidates. + * + * Arguments: + * * hive - The hive we're filling a slot for to check if the player is banished + * * sorted - Whether to sort by larva_queue_time (default TRUE) or leave unsorted + */ +/proc/get_alien_candidates(datum/hive_status/hive = null, sorted = TRUE) var/list/candidates = list() - for(var/i in GLOB.observer_list) - var/mob/dead/observer/O = i + for(var/mob/dead/observer/cur_obs as anything in GLOB.observer_list) + // Preference check + if(!cur_obs.client || !cur_obs.client.prefs || !(cur_obs.client.prefs.be_special & BE_ALIEN_AFTER_DEATH)) + continue + // Jobban check - if(!O.client || !O.client.prefs || !(O.client.prefs.be_special & BE_ALIEN_AFTER_DEATH) || jobban_isbanned(O, JOB_XENOMORPH)) + if(jobban_isbanned(cur_obs, JOB_XENOMORPH)) continue //players that can still be revived are skipped - if(O.mind && O.mind.original && ishuman(O.mind.original)) - var/mob/living/carbon/human/H = O.mind.original - if (H.check_tod() && H.is_revivable()) + if(cur_obs.mind && cur_obs.mind.original && ishuman(cur_obs.mind.original)) + var/mob/living/carbon/human/cur_human = cur_obs.mind.original + if(cur_human.check_tod() && cur_human.is_revivable()) continue // copied from join as xeno - var/deathtime = world.time - O.timeofdeath - if(deathtime < 3000 && ( !O.client.admin_holder || !(O.client.admin_holder.rights & R_ADMIN)) ) + var/deathtime = world.time - cur_obs.timeofdeath + if(deathtime < XENO_JOIN_DEAD_TIME && ( !cur_obs.client.admin_holder || !(cur_obs.client.admin_holder.rights & R_ADMIN) || !cur_obs.bypass_time_of_death_checks)) + continue + + // AFK players cannot be drafted + if(cur_obs.client.inactivity > XENO_JOIN_AFK_TIME_LIMIT) continue - // Admins and AFK players cannot be drafted - if(O.client.inactivity / 600 > ALIEN_SELECT_AFK_BUFFER + 5 || (O.client.admin_holder && (O.client.admin_holder.rights & R_MOD)) && O.adminlarva == 0) + // Mods with larva protection cannot be drafted + if((cur_obs.client.admin_holder && (cur_obs.client.admin_holder.rights & R_MOD)) && !cur_obs.adminlarva) continue - candidates += O + if(hive) + var/banished = FALSE + for(var/mob_name in hive.banished_ckeys) + if(hive.banished_ckeys[mob_name] == cur_obs.ckey) + banished = TRUE + break + if(banished) + continue + + candidates += cur_obs + + // Optionally sort by larva_queue_time + if(sorted && length(candidates)) + candidates = sort_list(candidates, GLOBAL_PROC_REF(cmp_obs_larvaqueuetime_asc)) return candidates +/** + * Messages observers that are currently candidates an update on the queue. + * + * Arguments: + * * candidates - The list of observers from get_alien_candidates() + * * dequeued - How many candidates to skip messaging because they were dequeued + * * cache_only - Whether to not actually send a to_chat message and instead only update larva_queue_cached_message + */ +/proc/message_alien_candidates(list/candidates, dequeued, cache_only = FALSE) + for(var/i in (1 + dequeued) to candidates.len) + var/mob/dead/observer/cur_obs = candidates[i] + + // Generate the messages + var/cached_message = SPAN_XENONOTICE("You are currently [i-dequeued]\th in the larva queue.") + cur_obs.larva_queue_cached_message = cached_message + if(!cache_only) + var/chat_message = dequeued ? replacetext(cached_message, "currently", "now") : cached_message + to_chat(candidates[i], chat_message) + /proc/convert_k2c(temp) return ((temp - T0C)) diff --git a/code/__HELPERS/guid.dm b/code/__HELPERS/guid.dm new file mode 100644 index 000000000000..49903cceb3c3 --- /dev/null +++ b/code/__HELPERS/guid.dm @@ -0,0 +1,19 @@ +/** + * returns a GUID like identifier (using a mostly made up record format) + * guids are not on their own suitable for access or security tokens, as most of their bits are predictable. + * (But may make a nice salt to one) +**/ +/proc/GUID() + var/const/GUID_VERSION = "b" + var/const/GUID_VARIANT = "d" + var/node_id = copytext_char(md5("[rand()*rand(1,9999999)][world.name][world.hub][world.hub_password][world.internet_address][world.address][world.contents.len][world.status][world.port][rand()*rand(1,9999999)]"), 1, 13) + + var/time_high = "[num2hex(text2num(time2text(world.realtime,"YYYY")), 2)][num2hex(world.realtime, 6)]" + + var/time_mid = num2hex(world.timeofday, 4) + + var/time_low = num2hex(world.time, 3) + + var/time_clock = num2hex(TICK_DELTA_TO_MS(world.tick_usage), 3) + + return "{[time_high]-[time_mid]-[GUID_VERSION][time_low]-[GUID_VARIANT][time_clock]-[node_id]}" diff --git a/code/__HELPERS/job.dm b/code/__HELPERS/job.dm index 38a92fe5b113..43902b07cfd9 100644 --- a/code/__HELPERS/job.dm +++ b/code/__HELPERS/job.dm @@ -73,7 +73,7 @@ JOB_SQUAD_ENGI, JOB_SQUAD_MEDIC, JOB_SQUAD_SPECIALIST, - JOB_SQUAD_RTO, + JOB_SQUAD_TEAM_LEADER, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MARINE, JOB_CMO, diff --git a/code/__HELPERS/logging.dm b/code/__HELPERS/logging.dm index b3d66c04db84..5ecbff108725 100644 --- a/code/__HELPERS/logging.dm +++ b/code/__HELPERS/logging.dm @@ -1,3 +1,24 @@ +#define LOGSRC_CKEY "Ckey" +#define LOGSRC_MOB "Mob" + +// Log header keys +#define LOG_HEADER_CATEGORY "category" +#define LOG_HEADER_INIT_TIMESTAMP "timestamp" +#define LOG_HEADER_ROUND_ID "round_id" + +// Log data keys +#define LOG_ENTRY_MESSAGE "message" +#define LOG_ENTRY_TIMESTAMP "timestamp" +#define LOG_ENTRY_DATA "data" + +// Log json keys +#define LOG_JSON_CATEGORY "category" +#define LOG_JSON_ENTRIES "entries" +#define LOG_JSON_LOGGING_START "log_start" + +// Log categories +#define LOG_CATEGORY_NOT_FOUND "invalid_category" + #define DIRECT_OUTPUT(A, B) A << B #define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text) #define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound) @@ -33,21 +54,25 @@ GLOB.STUI.processing |= STUI_LOG_DEBUG /proc/log_admin(text) + var/time = time_stamp() admin_log.Add(text) if (CONFIG_GET(flag/log_admin)) - diary << "\[[time_stamp()]]ADMIN: [text][log_end]" - GLOB.STUI.admin.Add("\[[time_stamp()]]ADMIN: [text]") + WRITE_LOG(GLOB.world_game_log, "ADMIN: [text]") + LOG_REDIS("admin", "\[[time]\] [text]") + GLOB.STUI.admin.Add("\[[time]]ADMIN: [text]") GLOB.STUI.processing |= STUI_LOG_ADMIN /proc/log_asset(text) asset_log.Add(text) if (CONFIG_GET(flag/log_asset)) - diary << "\[[time_stamp()]]ADMIN: [text][log_end]" + var/time = time_stamp() + WRITE_LOG(GLOB.world_game_log, "ASSET: [text]") + LOG_REDIS("asset", "\[[time]\] [text]") /proc/log_adminpm(text) admin_log.Add(text) if (CONFIG_GET(flag/log_admin)) - diary << "\[[time_stamp()]]ADMIN: [text][log_end]" + WRITE_LOG(GLOB.world_game_log, "ADMIN: [text]") GLOB.STUI.staff.Add("\[[time_stamp()]]ADMIN: [text]") GLOB.STUI.processing |= STUI_LOG_STAFF_CHAT @@ -55,13 +80,15 @@ SEND_TEXT(world.log, text) /proc/log_debug(text, diary_only=FALSE) + var/time = time_stamp() if (CONFIG_GET(flag/log_debug)) - diary << "\[[time_stamp()]]DEBUG: [text][log_end]" + WRITE_LOG(GLOB.world_game_log, "DEBUG: [text]") + LOG_REDIS("debug", "\[[time]\] [text]") if(diary_only) return - GLOB.STUI?.debug.Add("\[[time_stamp()]]DEBUG: [text]") + GLOB.STUI?.debug.Add("\[[time]]DEBUG: [text]") GLOB.STUI?.processing |= STUI_LOG_DEBUG for(var/client/C in GLOB.admins) if(C.prefs.toggles_chat & CHAT_DEBUGLOGS) @@ -69,106 +96,150 @@ /proc/log_game(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_game)) - diary << html_decode("\[[time_stamp()]]GAME: [text][log_end]") - GLOB.STUI.admin.Add("\[[time_stamp()]]GAME: [text]") + WRITE_LOG(GLOB.world_game_log, "GAME: [text]") + LOG_REDIS("game", "\[[time]\] [text]") + GLOB.STUI.admin.Add("\[[time]]GAME: [text]") GLOB.STUI.processing |= STUI_LOG_ADMIN /proc/log_interact(mob/living/carbon/origin, mob/living/carbon/target, msg) + var/time = time_stamp() if (CONFIG_GET(flag/log_interact)) - diary << html_decode("\[[time_stamp()]]INTERACT: [msg][log_end]") - origin.attack_log += "\[[time_stamp()]\] [msg] " - target.attack_log += "\[[time_stamp()]\] [msg] " - - GLOB.STUI.attack.Add("\[[time_stamp()]]INTERACT: [msg]") + WRITE_LOG(GLOB.world_game_log, "INTERACT: [msg]") + LOG_REDIS("interact", "\[[time]\] [msg]") + if(origin) + origin.attack_log += "\[[time]\] [msg] " + if(target) + target.attack_log += "\[[time]\] [msg] " + + GLOB.STUI.attack.Add("\[[time]]INTERACT: [msg]") GLOB.STUI.processing |= STUI_LOG_ATTACK /proc/log_overwatch(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_overwatch)) - diary << html_decode("\[[time_stamp()]]OVERWATCH: [text][log_end]") - GLOB.STUI.admin.Add("\[[time_stamp()]]OVERWATCH: [text]") + WRITE_LOG(GLOB.world_game_log, "OVERWATCH: [text]") + LOG_REDIS("overwatch", "\[[time]\] [text]") + GLOB.STUI.admin.Add("\[[time]]OVERWATCH: [text]") GLOB.STUI.processing |= STUI_LOG_ADMIN /proc/log_idmod(obj/item/card/id/target_id, msg) + var/time = time_stamp() if (CONFIG_GET(flag/log_idmod)) - diary << html_decode("\[[time_stamp()]]ID MOD: [msg][log_end]") - target_id.modification_log += "\[[time_stamp()]]: [msg]" + WRITE_LOG(GLOB.world_game_log, "ID MOD: [msg]") + LOG_REDIS("idmod", "\[[time]\] [msg]") + target_id.modification_log += "\[[time]]: [msg]" /proc/log_vote(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_vote)) - diary << html_decode("\[[time_stamp()]]VOTE: [text][log_end]") + WRITE_LOG(GLOB.world_game_log, "VOTE: [text]") + LOG_REDIS("vote", "\[[time]\] [text]") + /proc/log_access(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_access)) - diary << html_decode("\[[time_stamp()]]ACCESS: [text][log_end]") - GLOB.STUI.debug.Add("\[[time_stamp()]]ACCESS: [text]") + WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]") + LOG_REDIS("access", "\[[time]\] [text]") + GLOB.STUI.debug.Add("\[[time]]ACCESS: [text]") GLOB.STUI.processing |= STUI_LOG_DEBUG /proc/log_say(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_say)) - diary << html_decode("\[[time_stamp()]]SAY: [text][log_end]") - GLOB.STUI.game.Add("\[[time_stamp()]]SAY: [text]") + WRITE_LOG(GLOB.world_game_log, "SAY: [text]") + LOG_REDIS("say", "\[[time]\] [text]") + GLOB.STUI.game.Add("\[[time]]SAY: [text]") GLOB.STUI.processing |= STUI_LOG_GAME_CHAT /proc/log_hivemind(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_hivemind)) - diary << html_decode("\[[time_stamp()]]HIVEMIND: [text][log_end]") - GLOB.STUI.game.Add("\[[time_stamp()]]HIVEMIND: [text]") + WRITE_LOG(GLOB.world_game_log, "HIVEMIND: [text]") + LOG_REDIS("hivemind", "\[[time]\] [text]") + GLOB.STUI.game.Add("\[[time]]HIVEMIND: [text]") GLOB.STUI.processing |= STUI_LOG_GAME_CHAT /proc/log_ooc(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_ooc)) - diary << html_decode("\[[time_stamp()]]OOC: [text][log_end]") + LOG_REDIS("ooc", "\[[time]\] [text]") + WRITE_LOG(GLOB.world_game_log, "OOC: [text]") /proc/log_whisper(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_whisper)) - diary << html_decode("\[[time_stamp()]]WHISPER: [text][log_end]") - GLOB.STUI.game.Add("\[[time_stamp()]]WHISPER: [text]") + LOG_REDIS("whisper", "\[[time]\] [text]") + WRITE_LOG(GLOB.world_game_log, "WHISPER: [text]") + GLOB.STUI.game.Add("\[[time]]WHISPER: [text]") GLOB.STUI.processing |= STUI_LOG_GAME_CHAT /proc/log_emote(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_emote)) - diary << html_decode("\[[time_stamp()]]EMOTE: [text][log_end]") - GLOB.STUI.game.Add("\[[time_stamp()]]EMOTE: [text]") + LOG_REDIS("emote", "\[[time]\] [text]") + WRITE_LOG(GLOB.world_game_log, "EMOTE: [text]") + GLOB.STUI.game.Add("\[[time]]EMOTE: [text]") GLOB.STUI.processing |= STUI_LOG_GAME_CHAT /proc/log_attack(text) + var/time = time_stamp() if (CONFIG_GET(flag/log_attack)) - diary << html_decode("\[[time_stamp()]]ATTACK: [text][log_end]") - GLOB.STUI.attack.Add("\[[time_stamp()]]ATTACK: [text]") + LOG_REDIS("attack", "\[[time]\] [text]") + WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]") + GLOB.STUI.attack.Add("\[[time]]ATTACK: [text]") GLOB.STUI.processing |= STUI_LOG_ATTACK /proc/log_adminsay(text) if (CONFIG_GET(flag/log_adminchat)) - diary << html_decode("\[[time_stamp()]]ADMINSAY: [text][log_end]") + WRITE_LOG(GLOB.world_game_log, "ADMINSAY: [text]") /proc/log_adminwarn(text) if (CONFIG_GET(flag/log_adminwarn)) - diary << html_decode("\[[time_stamp()]]ADMINWARN: [text][log_end]") + WRITE_LOG(GLOB.world_game_log, "ADMINWARN: [text]") GLOB.STUI.admin.Add("\[[time_stamp()]]ADMIN: [text]") GLOB.STUI.processing |= STUI_LOG_ADMIN /proc/log_misc(text) - diary << html_decode("\[[time_stamp()]]MISC: [text][log_end]") - GLOB.STUI?.debug.Add("\[[time_stamp()]]MISC: [text]") + var/time = time_stamp() + LOG_REDIS("misc", "\[[time]\] [text]") + WRITE_LOG(GLOB.world_game_log, "MISC: [text]") + GLOB.STUI?.debug.Add("\[[time]]MISC: [text]") /proc/log_mutator(text) - if(!mutator_logs) + if(!GLOB.mutator_logs) return - mutator_logs << text + "[log_end]" + WRITE_LOG(GLOB.mutator_logs, "[text]") /proc/log_hiveorder(text) - diary << html_decode("\[[time_stamp()]]HIVE ORDER: [text][log_end]") - GLOB.STUI.debug.Add("\[[time_stamp()]]HIVE ORDER: [text]") + var/time = time_stamp() + LOG_REDIS("hiveorder", "\[[time]\] [text]") + WRITE_LOG(GLOB.world_game_log, "HIVE ORDER: [text]") + GLOB.STUI.debug.Add("\[[time]]HIVE ORDER: [text]") /proc/log_announcement(text) - diary << html_decode("\[[time_stamp()]]ANNOUNCEMENT: [text][log_end]") - GLOB.STUI.admin.Add("\[[time_stamp()]]ANNOUNCEMENT: [text]") + var/time = time_stamp() + LOG_REDIS("announcement", "\[[time]\] [text]") + WRITE_LOG(GLOB.world_game_log, "ANNOUNCEMENT: [text]") + GLOB.STUI.admin.Add("\[[time]]ANNOUNCEMENT: [text]") /proc/log_mhelp(text) - diary << html_decode("\[[time_stamp()]]MENTORHELP: [text][log_end]") - GLOB.STUI.admin.Add("\[[time_stamp()]]MENTORHELP: [text]") + var/time = time_stamp() + LOG_REDIS("mhelp", "\[[time]\] [text]") + WRITE_LOG(GLOB.world_game_log, "MENTORHELP: [text]") + GLOB.STUI.admin.Add("\[[time]]MENTORHELP: [text]") + +/// Logging for game performance +/proc/log_perf(list/perf_info) + . = "[perf_info.Join(",")]\n" + WRITE_LOG_NO_FORMAT(GLOB.perf_log, .) + +/* Log to the logfile only. */ +/proc/log_runtime(text) + WRITE_LOG(GLOB.world_runtime_log, text) /** * Appends a tgui-related log entry. All arguments are optional. @@ -200,10 +271,13 @@ // Insert message if(message) entry += "\n[message]" - tgui_diary << html_decode("\[[time_stamp()]]TGUI: [entry][log_end]") + WRITE_LOG(GLOB.tgui_log, entry) GLOB.STUI.tgui.Add("\[[time_stamp()]]TGUI: [entry]") GLOB.STUI.processing |= STUI_LOG_TGUI +/proc/log_topic(text) + WRITE_LOG(GLOB.world_game_log, "TOPIC: [text]") + GLOBAL_VAR(config_error_log) GLOBAL_PROTECT(config_error_log) @@ -233,3 +307,10 @@ GLOBAL_PROTECT(config_error_log) #else //Not tracking at all #define log_reftracker(msg) #endif + +/proc/start_log(log) + WRITE_LOG(log, "Starting up round ID [GLOB.round_id]\n-------------------------)") + +/proc/shutdown_logging() + rustg_log_close_all() + GLOB.logger.shutdown_logging() diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 1bf910e9ac8d..9aa1bdc3ea2f 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -102,11 +102,11 @@ /*Changing/updating a mob's client color matrices. These render over the map window and affect most things the player sees, except things like inventory, text popups, HUD, and some fullscreens. Code based on atom filter code, since these have similar issues with application order - for ex. if you have -a desaturation and a recolour matrix, you'll get very different results if you desaturate before recolouring, or recolour before desaturating. +a desaturation and a recolor matrix, you'll get very different results if you desaturate before recoloring, or recolor before desaturating. See matrices.dm for the matrix procs. -If you want to recolour a specific atom, you should probably do it as a color matrix filter instead since that code already exists. +If you want to recolor a specific atom, you should probably do it as a color matrix filter instead since that code already exists. Apparently color matrices are not the same sort of matrix used by matrix datums and can't be worked with using normal matrix procs.*/ diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 83da41b515a6..d4d9eb320633 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -164,6 +164,11 @@ t = "0[t]" return t +/proc/pad_trailing(text, padding, size) + while (length(text) < size) + text = "[text][padding]" + return text + //Adds 'u' number of spaces ahead of the text 't' /proc/add_lspace(t, u) while(length(t) < u) diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index d6356ce3a706..4e4a1b3ff31c 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -226,7 +226,6 @@ 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_COLOR) . += "[seperator]+COLOR" if(rights & R_VAREDIT) . += "[seperator]+VAREDIT" if(rights & R_SOUNDS) . += "[seperator]+SOUND" @@ -313,3 +312,22 @@ for(var/A in value) if(var_source.vars.Find(A)) . += A + +/// Formats a larger number to correct textual representation without losing data +/proc/big_number_to_text(number) + return num2text(number, INFINITY) + +/proc/text2list(text, delimiter="\n") + var/delim_len = length(delimiter) + if (delim_len < 1) + return list(text) + + . = list() + var/last_found = 1 + var/found + + do + found = findtext(text, delimiter, last_found, 0) + . += copytext(text, last_found, found) + last_found = found + delim_len + while (found) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 5d25df2150c0..2e48c9f80cd3 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1139,7 +1139,7 @@ var/global/image/action_purple_power_up break if(user_flags & INTERRUPT_NEEDHAND) if(user_holding) - if(!user_holding.loc || busy_user.get_active_hand() != user_holding) //no longer holding the required item + if(!user_holding.loc || busy_user.get_active_hand() != user_holding) //no longer holding the required item in active hand . = FALSE break else if(busy_user.get_active_hand()) //something in active hand when we need it to stay empty @@ -1153,6 +1153,11 @@ var/global/image/action_purple_power_up else if(T.get_active_hand()) . = FALSE break + if(user_flags & INTERRUPT_NO_NEEDHAND) + if(user_holding) + if(!user_holding.loc || (busy_user.l_hand != user_holding && busy_user.r_hand != user_holding)) //no longer holding the required item in either hand + . = FALSE + break if(user_flags & INTERRUPT_RESIST && busy_user.resisting || \ target_is_mob && (target_flags & INTERRUPT_RESIST && T.resisting) ) @@ -1781,14 +1786,30 @@ var/list/WALLITEMS = list( user.face_atom(src) return TRUE +#define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___callbackvarset), ##target, ##var_name, ##var_value) +//dupe code because dm can't handle 3 level deep macros #define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___callbackvarset), ##datum, NAMEOF(##datum, ##var), ##var_value) +/// Same as VARSET_CALLBACK, but uses a weakref to the datum. +/// Use this if the timer is exceptionally long. +#define VARSET_WEAK_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___callbackvarset), WEAKREF(##datum), NAMEOF(##datum, ##var), ##var_value) /proc/___callbackvarset(list_or_datum, var_name, var_value) if(length(list_or_datum)) list_or_datum[var_name] = var_value return - var/datum/D = list_or_datum - D.vars[var_name] = var_value + + var/datum/datum = list_or_datum + + if (isweakref(datum)) + var/datum/weakref/datum_weakref = datum + datum = datum_weakref.resolve() + if (isnull(datum)) + return + + if(IsAdminAdvancedProcCall()) + datum.vv_edit_var(var_name, var_value) //same result generally, unless badmemes + else + datum.vars[var_name] = var_value //don't question just accept /proc/pass(...) diff --git a/code/__HELPERS/verb_helpers.dm b/code/__HELPERS/verb_helpers.dm index d042929f1184..4bc3ae584cd6 100644 --- a/code/__HELPERS/verb_helpers.dm +++ b/code/__HELPERS/verb_helpers.dm @@ -10,7 +10,7 @@ if(!target) CRASH("add_verb called without a target") if(IsAdminAdvancedProcCall()) - return + return PROC_BLOCKED var/mob/mob_target = null if(ismob(target)) @@ -56,7 +56,7 @@ */ /proc/remove_verb(client/target, verb_or_list_to_remove) if(IsAdminAdvancedProcCall()) - return + return PROC_BLOCKED var/mob/mob_target = null if(ismob(target)) diff --git a/code/_byond_version_compat.dm b/code/_byond_version_compat.dm index b5379a3b6d5c..719d85654b5f 100644 --- a/code/_byond_version_compat.dm +++ b/code/_byond_version_compat.dm @@ -31,19 +31,49 @@ #define LIBCALL call_ext #endif -// So we want to have compile time guarantees these procs exist on local type, unfortunately 515 killed the .proc/procname syntax so we have to use nameof() +// 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. + #if DM_VERSION < 515 -/// Call by name proc reference, checks if the proc exists on this type or as a global proc + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. #define PROC_REF(X) (.proc/##X) -/// Call by name proc reference, checks if the proc exists on given type or as a global proc +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (.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) (##TYPE.proc/##X) -/// Call by name proc reference, checks if the proc is existing global proc +/// 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) (##TYPE.verb/##X) + +/// Call by name proc reference, checks if the proc is an existing global proc #define GLOBAL_PROC_REF(X) (/proc/##X) + #else -/// Call by name proc reference, checks if the proc exists on this type or as a global proc + +/// 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 proc reference, checks if the proc exists on given type or as a global proc +/// 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 proc reference, checks if the proc is existing global proc +/// 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) + +#endif + +#if (DM_VERSION == 515) +/// fcopy will crash on 515 linux if given a non-existant file, instead of returning 0 like on 514 linux or 515 windows +/// var case matches documentation for fcopy. +/world/proc/__fcopy(Src, Dst) + if (istext(Src) && !fexists(Src)) + return 0 + return fcopy(Src, Dst) + +#define fcopy(Src, Dst) world.__fcopy(Src, Dst) + #endif diff --git a/code/_experiments.dm b/code/_experiments.dm new file mode 100644 index 000000000000..6e5addb5f992 --- /dev/null +++ b/code/_experiments.dm @@ -0,0 +1,34 @@ +// This file contains experimental flags that may not be production ready yet, +// but that we want to be able to easily flip as well as run on CI. +// Any flag you see here can be flipped with the `-D` CLI argument. +// For example, if you want to enable EXPERIMENT_MY_COOL_FEATURE, compile with -DEXPERIMENT_MY_COOL_FEATURE + +// EXPERIMENT_515_QDEL_HARD_REFERENCE +// - Hold a hard reference for qdeleted items, and check ref_count, rather than using refs. Requires 515+. + +// EXPERIMENT_515_DONT_CACHE_REF +// - Avoids `text_ref` caching, aided by improvements to ref() speed in 515. + +#if DM_VERSION < 515 + +// You can't X-macro custom names :( +#ifdef EXPERIMENT_515_QDEL_HARD_REFERENCE +#warn EXPERIMENT_515_QDEL_HARD_REFERENCE is only available on 515+ +#undef EXPERIMENT_515_QDEL_HARD_REFERENCE +#endif + +#ifdef EXPERIMENT_515_DONT_CACHE_REF +#warn EXPERIMENT_515_DONT_CACHE_REF is only available on 515+ +#undef EXPERIMENT_515_DONT_CACHE_REF +#endif + +#elif defined(UNIT_TESTS) + +//#define EXPERIMENT_515_QDEL_HARD_REFERENCE +#define EXPERIMENT_515_DONT_CACHE_REF + +#endif + +#if DM_VERSION >= 516 +#error "Remove all 515 experiments" +#endif diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 4148f1970673..d71125c318f6 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -25,7 +25,6 @@ DEFINE_BITFIELD(rights, list( "POSSESS" = R_POSSESS, "PERMISSIONS" = R_PERMISSIONS, "STEALTH" = R_STEALTH, - "REJUVENATE" = R_REJUVINATE, "COLOR" = R_COLOR, "VAREDIT" = R_VAREDIT, "SOUNDS" = R_SOUNDS, @@ -71,6 +70,7 @@ DEFINE_BITFIELD(chem_effect_flags, list( "CHEM_EFFECT_RESIST_NEURO" = CHEM_EFFECT_RESIST_NEURO, "CHEM_EFFECT_HYPER_THROTTLE" = CHEM_EFFECT_HYPER_THROTTLE, "CHEM_EFFECT_ORGAN_STASIS" = CHEM_EFFECT_ORGAN_STASIS, + "CHEM_EFFECT_NO_BLEEDING" = CHEM_EFFECT_NO_BLEEDING, )) DEFINE_BITFIELD(flags_ammo_behaviour, list( @@ -108,24 +108,18 @@ DEFINE_BITFIELD(flags_gun_features, list( "GUN_TRIGGER_SAFETY" = GUN_TRIGGER_SAFETY, "GUN_UNUSUAL_DESIGN" = GUN_UNUSUAL_DESIGN, "GUN_SILENCED" = GUN_SILENCED, - "GUN_AUTOMATIC" = GUN_AUTOMATIC, "GUN_INTERNAL_MAG" = GUN_INTERNAL_MAG, "GUN_AUTO_EJECTOR" = GUN_AUTO_EJECTOR, "GUN_AMMO_COUNTER" = GUN_AMMO_COUNTER, - "GUN_BURST_ON" = GUN_BURST_ON, "GUN_BURST_FIRING" = GUN_BURST_FIRING, "GUN_FLASHLIGHT_ON" = GUN_FLASHLIGHT_ON, "GUN_WY_RESTRICTED" = GUN_WY_RESTRICTED, "GUN_SPECIALIST" = GUN_SPECIALIST, "GUN_WIELDED_FIRING_ONLY" = GUN_WIELDED_FIRING_ONLY, - "GUN_HAS_FULL_AUTO" = GUN_HAS_FULL_AUTO, - "GUN_FULL_AUTO_ON" = GUN_FULL_AUTO_ON, "GUN_ONE_HAND_WIELDED" = GUN_ONE_HAND_WIELDED, "GUN_ANTIQUE" = GUN_ANTIQUE, "GUN_RECOIL_BUILDUP" = GUN_RECOIL_BUILDUP, "GUN_SUPPORT_PLATFORM" = GUN_SUPPORT_PLATFORM, - "GUN_BURST_ONLY" = GUN_BURST_ONLY, - "GUN_FULL_AUTO_ONLY" = GUN_FULL_AUTO_ONLY, )) DEFINE_BITFIELD(flags_magazine, list( @@ -134,6 +128,7 @@ DEFINE_BITFIELD(flags_magazine, list( "AMMUNITION_HANDFUL_BOX" = AMMUNITION_HANDFUL_BOX, "AMMUNITION_HIDE_AMMO" = AMMUNITION_HIDE_AMMO, "AMMUNITION_CANNOT_REMOVE_BULLETS" = AMMUNITION_CANNOT_REMOVE_BULLETS, + "AMMUNITION_SLAP_TRANSFER" = AMMUNITION_SLAP_TRANSFER, )) DEFINE_BITFIELD(flags_atom, list( @@ -327,6 +322,7 @@ DEFINE_BITFIELD(flags_area, list( "AREA_NOTUNNEL" = AREA_NOTUNNEL, "AREA_ALLOW_XENO_JOIN" = AREA_ALLOW_XENO_JOIN, "AREA_CONTAINMENT" = AREA_CONTAINMENT, + "ARES_UNWEEDABLE" = AREA_UNWEEDABLE, )) DEFINE_BITFIELD(disabilities, list( @@ -420,6 +416,7 @@ DEFINE_BITFIELD(toggleable_flags, list( "MODE_NO_COMBAT_CAS" = MODE_NO_COMBAT_CAS, "MODE_LZ_PROTECTION" = MODE_LZ_PROTECTION, "MODE_SHIPSIDE_SD" = MODE_SHIPSIDE_SD, + "MODE_DISPOSABLE_MOBS" = MODE_DISPOSABLE_MOBS, )) DEFINE_BITFIELD(state, list( diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index 50c7fbeb989a..95db85564dc7 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -10,6 +10,7 @@ GLOBAL_LIST_EMPTY(GeneralFaxes) //Inter-machine faxes GLOBAL_LIST_EMPTY(fax_contents) //List of fax contents to maintain it even if source paper is deleted GLOBAL_LIST_EMPTY(failed_fultons) //A list of fultoned items which weren't collected and fell back down +GLOBAL_LIST_EMPTY(larva_burst_by_hive) GLOBAL_LIST_INIT_TYPED(custom_huds_list, /datum/custom_hud, setup_all_huds()) GLOBAL_LIST_INIT_TYPED(custom_human_huds, /datum/custom_hud, setup_human_huds()) @@ -49,11 +50,16 @@ GLOBAL_LIST_EMPTY(mainship_pipes) // Resin constructions parameters GLOBAL_LIST_INIT_TYPED(resin_constructions_list, /datum/resin_construction, setup_resin_constructions()) +GLOBAL_LIST_INIT(resin_build_order_lesser_drone, list( + /datum/resin_construction/resin_turf/wall, + /datum/resin_construction/resin_turf/membrane, + /datum/resin_construction/resin_obj/door, +)) + GLOBAL_LIST_INIT(resin_build_order_drone, list( /datum/resin_construction/resin_turf/wall, /datum/resin_construction/resin_turf/membrane, /datum/resin_construction/resin_obj/door, - /datum/resin_construction/resin_obj/nest, /datum/resin_construction/resin_obj/sticky_resin, /datum/resin_construction/resin_obj/fast_resin, /datum/resin_construction/resin_obj/resin_spike @@ -64,19 +70,27 @@ GLOBAL_LIST_INIT(resin_build_order_hivelord, list( /datum/resin_construction/resin_turf/wall/reflective, /datum/resin_construction/resin_turf/membrane/thick, /datum/resin_construction/resin_obj/door/thick, - /datum/resin_construction/resin_obj/nest, /datum/resin_construction/resin_obj/acid_pillar, /datum/resin_construction/resin_obj/sticky_resin, /datum/resin_construction/resin_obj/fast_resin, /datum/resin_construction/resin_obj/resin_spike )) +GLOBAL_LIST_INIT(resin_build_order_hivelord_whisperer, list( + /datum/resin_construction/resin_turf/wall, + /datum/resin_construction/resin_turf/membrane, + /datum/resin_construction/resin_obj/door, + /datum/resin_construction/resin_obj/sticky_resin, + /datum/resin_construction/resin_obj/fast_resin, + /datum/resin_construction/resin_obj/resin_spike, + /datum/resin_construction/resin_obj/resin_node +)) + GLOBAL_LIST_INIT(resin_build_order_ovipositor, list( /datum/resin_construction/resin_turf/wall/queen, /datum/resin_construction/resin_turf/wall/reflective, /datum/resin_construction/resin_turf/membrane/queen, /datum/resin_construction/resin_obj/door/queen, - /datum/resin_construction/resin_obj/nest, /datum/resin_construction/resin_obj/acid_pillar, /datum/resin_construction/resin_obj/sticky_resin, /datum/resin_construction/resin_obj/fast_resin, @@ -163,7 +177,8 @@ GLOBAL_LIST_INIT_TYPED(hive_datum, /datum/hive_status, list( XENO_HIVE_TAMED = new /datum/hive_status/corrupted/tamed(), XENO_HIVE_MUTATED = new /datum/hive_status/mutated(), XENO_HIVE_FORSAKEN = new /datum/hive_status/forsaken(), - XENO_HIVE_YAUTJA = new /datum/hive_status/yautja() + XENO_HIVE_YAUTJA = new /datum/hive_status/yautja(), + XENO_HIVE_RENEGADE = new /datum/hive_status/corrupted/renegade(), )) GLOBAL_DATUM_INIT(xeno_round_traits, /datum/xeno_round_traits, new()) @@ -192,6 +207,9 @@ GLOBAL_REFERENCE_LIST_INDEXED(yautja_hair_styles_list, /datum/sprite_accessory/y //Backpacks var/global/list/backbaglist = list("Backpack", "Satchel") + //Armor styles +GLOBAL_LIST_INIT(armor_style_list, list("Padded" = 1, "Padless" = 2, "Ridged" = 3, "Carrier" = 4, "Skull" = 5, "Smooth" = 6, "Random")) + // var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg) var/global/round_should_check_for_win = TRUE @@ -495,3 +513,9 @@ var/global/list/available_specialist_kit_boxes = list( .[E.key_third_person] = list(E) else .[E.key_third_person] |= E + +GLOBAL_LIST_EMPTY(topic_tokens) +GLOBAL_PROTECT(topic_tokens) + +GLOBAL_LIST_EMPTY(topic_commands) +GLOBAL_PROTECT(topic_commands) diff --git a/code/_globalvars/lists/mapping_globals.dm b/code/_globalvars/lists/mapping_globals.dm index ca12912dce0b..47cc22dae5e1 100644 --- a/code/_globalvars/lists/mapping_globals.dm +++ b/code/_globalvars/lists/mapping_globals.dm @@ -27,14 +27,13 @@ GLOBAL_LIST_EMPTY(latewhiskey) GLOBAL_LIST_EMPTY(latejoin) GLOBAL_LIST_EMPTY(latejoin_by_squad) +GLOBAL_LIST_EMPTY(latejoin_by_job) GLOBAL_LIST_EMPTY(zombie_landmarks) GLOBAL_LIST_EMPTY(newplayer_start) GLOBAL_LIST_EMPTY_TYPED(observer_starts, /obj/effect/landmark/observer_start) -GLOBAL_LIST_EMPTY(fog_blockers) - GLOBAL_LIST_EMPTY(map_items) GLOBAL_LIST_EMPTY(xeno_tunnels) GLOBAL_LIST_EMPTY(crap_items) @@ -55,6 +54,8 @@ GLOBAL_LIST_EMPTY(teleporter_landmarks) GLOBAL_LIST_INIT(cardinals, list(NORTH, SOUTH, EAST, WEST)) GLOBAL_LIST_EMPTY(nightmare_landmarks) +GLOBAL_LIST_EMPTY(ship_areas) + // Objective landmarks. Value is TRUE if it contains documents GLOBAL_LIST_EMPTY_TYPED(objective_landmarks_close, /obj/effect/landmark/objective_landmark/close) GLOBAL_LIST_EMPTY_TYPED(objective_landmarks_medium, /obj/effect/landmark/objective_landmark/medium) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 187f179094b2..e2203aadce0c 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY_TYPED(alive_human_list, /mob/living/carbon/human) // list of a GLOBAL_LIST_EMPTY_TYPED(xeno_mob_list, /mob/living/carbon/xenomorph) GLOBAL_LIST_EMPTY_TYPED(living_xeno_list, /mob/living/carbon/xenomorph) GLOBAL_LIST_EMPTY_TYPED(xeno_cultists, /mob/living/carbon/human) +GLOBAL_LIST_EMPTY_TYPED(player_embryo_list, /obj/item/alien_embryo) GLOBAL_LIST_EMPTY_TYPED(hellhound_list, /mob/living/carbon/xenomorph/hellhound) GLOBAL_LIST_EMPTY_TYPED(zombie_list, /mob/living/carbon/human) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 0e574e1f610b..df7dd48a1dd1 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -71,7 +71,9 @@ return // Click handled elsewhere. (These clicks are not affected by the next_move cooldown) - if (click(A, mods) | A.clicked(src, mods, location, params)) + if(click(A, mods)) + return + if(A.clicked(src, mods, location, params)) return // Default click functions from here on. @@ -80,7 +82,8 @@ return face_atom(A) - + if(mods["middle"]) + return // Special type of click. if (is_mob_restrained()) RestrainedClickOn(A) @@ -88,13 +91,17 @@ // Throwing stuff, can't throw on inventory items nor screen objects nor items inside storages. if (throw_mode && A.loc != src && !isstorage(A.loc) && !istype(A, /atom/movable/screen)) - throw_item(A) + //if we're past the throw delay just throw, add the new delay time, and reset the buffer + if(COOLDOWN_FINISHED(src, throw_delay)) + throw_item(A) + COOLDOWN_START(src, throw_delay, THROW_DELAY) + throw_buffer = 0 + //if we're still in the throw delay we check if the buffer is already used, if not then we throw the item and set the buffer as used + else if(!throw_buffer) + throw_item(A) + throw_buffer++ return - // Last thing clicked is tracked for something somewhere. - if(!isgun(A) && !isturf(A) && !istype(A,/atom/movable/screen)) - last_target_click = world.time - var/obj/item/W = get_active_hand() // Special gun mode stuff. @@ -324,8 +331,28 @@ apply_clickcatcher() mob.reload_fullscreens() + if(prefs.adaptive_zoom) + INVOKE_ASYNC(src, PROC_REF(adaptive_zoom)) + else if(prefs.auto_fit_viewport) + INVOKE_ASYNC(src, VERB_REF(fit_viewport)) + +/client/proc/get_adaptive_zoom_factor() + if(!prefs.adaptive_zoom) + return 0 + var/zoom = prefs.adaptive_zoom + if(view <= 8) + return zoom * 2 + else if(view <= 15) + return zoom * 1 + else + return 0 + +/// Attempts to scale client zoom automatically to fill 1080p multiples. Best used with auto fit viewport. +/client/proc/adaptive_zoom() + var/icon_size = world.icon_size * get_adaptive_zoom_factor() + winset(src, "mapwindow.map", "icon-size=[icon_size]") if(prefs.auto_fit_viewport) - INVOKE_ASYNC(src, .verb/fit_viewport) + fit_viewport() /client/proc/create_clickcatcher() if(!void) diff --git a/code/_onclick/click_hold.dm b/code/_onclick/click_hold.dm index c68beb52fc9e..f65dd33c2eea 100644 --- a/code/_onclick/click_hold.dm +++ b/code/_onclick/click_hold.dm @@ -30,6 +30,9 @@ mouse_trace_history = null LAZYADD(mouse_trace_history, A) + if(SEND_SIGNAL(mob, COMSIG_MOB_MOUSEDOWN, A, T, skin_ctl, params) & COMSIG_MOB_CLICK_CANCELED) + return + var/list/mods = params2list(params) if(mods["left"]) SEND_SIGNAL(src, COMSIG_CLIENT_LMB_DOWN, A, mods) @@ -62,6 +65,9 @@ params += ";click_catcher=1" holding_click = FALSE + if(SEND_SIGNAL(mob, COMSIG_MOB_MOUSEUP, A, T, skin_ctl, params) & COMSIG_MOB_CLICK_CANCELED) + return + var/list/mods = params2list(params) if(mods["left"]) SEND_SIGNAL(src, COMSIG_CLIENT_LMB_UP, A, params) @@ -75,6 +81,9 @@ if(click_catcher_click) params += ";click_catcher=1" + if(SEND_SIGNAL(mob, COMSIG_MOB_MOUSEDRAG, src_obj, over_obj, src_loc, over_loc, src_ctl, over_ctl, params) & COMSIG_MOB_CLICK_CANCELED) + return + var/list/mods = params2list(params) if(mods["left"]) SEND_SIGNAL(src, COMSIG_CLIENT_LMB_DRAG, src_obj, over_obj, params) diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm index 2ce081bc47f2..a53e82730732 100644 --- a/code/_onclick/hud/alien.dm +++ b/code/_onclick/hud/alien.dm @@ -17,20 +17,20 @@ draw_throw(ui_alien_datum) draw_zone_sel(ui_alien_datum) draw_healths(ui_alien_datum) - draw_nightvision(ui_alien_datum) - draw_plasma_display(ui_alien_datum) - draw_armor_display(ui_alien_datum) - draw_locate_queen(ui_alien_datum) - draw_locate_mark(ui_alien_datum) + draw_alien_nightvision(ui_alien_datum) + draw_alien_plasma_display(ui_alien_datum) + draw_alien_armor_display(ui_alien_datum) + draw_alien_locate_queen(ui_alien_datum) + draw_alien_locate_mark(ui_alien_datum) -/datum/hud/alien/proc/draw_nightvision(datum/custom_hud/alien/ui_alien_datum) +/datum/hud/proc/draw_alien_nightvision(datum/custom_hud/alien/ui_alien_datum) var/atom/movable/screen/using = new /atom/movable/screen/xenonightvision() using.icon = ui_alien_datum.ui_style_icon using.screen_loc = ui_alien_datum.ui_alien_nightvision infodisplay += using add_verb(mymob, /datum/action/xeno_action/verb/verb_night_vision) -/datum/hud/alien/proc/draw_plasma_display(datum/custom_hud/alien/ui_alien_datum) +/datum/hud/proc/draw_alien_plasma_display(datum/custom_hud/alien/ui_alien_datum) alien_plasma_display = new /atom/movable/screen() alien_plasma_display.icon = ui_alien_datum.ui_style_icon alien_plasma_display.icon_state = "power_display2" @@ -38,7 +38,7 @@ alien_plasma_display.screen_loc = ui_alien_datum.ui_alienplasmadisplay infodisplay += alien_plasma_display -/datum/hud/alien/proc/draw_armor_display(datum/custom_hud/alien/ui_alien_datum) +/datum/hud/proc/draw_alien_armor_display(datum/custom_hud/alien/ui_alien_datum) alien_armor_display = new /atom/movable/screen() alien_armor_display.icon = ui_alien_datum.ui_style_icon alien_armor_display.icon_state = "armor_100" @@ -46,13 +46,13 @@ alien_armor_display.screen_loc = ui_alien_datum.ui_alienarmordisplay infodisplay += alien_armor_display -/datum/hud/alien/proc/draw_locate_queen(datum/custom_hud/alien/ui_alien_datum) +/datum/hud/proc/draw_alien_locate_queen(datum/custom_hud/alien/ui_alien_datum) locate_leader = new /atom/movable/screen/queen_locator() locate_leader.icon = ui_alien_datum.ui_style_icon locate_leader.screen_loc = ui_alien_datum.ui_queen_locator infodisplay += locate_leader -/datum/hud/alien/proc/draw_locate_mark(datum/custom_hud/alien/ui_alien_datum) +/datum/hud/proc/draw_alien_locate_mark(datum/custom_hud/alien/ui_alien_datum) locate_marker = new /atom/movable/screen/mark_locator() locate_marker.icon = ui_alien_datum.ui_style_icon locate_marker.screen_loc = ui_alien_datum.ui_mark_locator @@ -87,17 +87,9 @@ draw_mov_intent(ui_alien_datum) draw_healths(ui_alien_datum) - - var/atom/movable/screen/using = new /atom/movable/screen/xenonightvision() - using.icon = ui_alien_datum.ui_style_icon - using.screen_loc = ui_alien_datum.ui_alien_nightvision - infodisplay += using - - locate_leader = new /atom/movable/screen/queen_locator() - locate_leader.icon = ui_alien_datum.ui_style_icon - locate_leader.screen_loc = ui_alien_datum.ui_queen_locator - infodisplay += locate_leader - + draw_alien_nightvision(ui_alien_datum) + draw_alien_locate_queen(ui_alien_datum) + draw_alien_locate_mark(ui_alien_datum) /mob/living/carbon/xenomorph/larva/create_hud() if(!hud_used) diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index bfcb97613f9c..8a3f7d9d6a31 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -80,7 +80,8 @@ if(!.) return var/mob/screenmob = viewmob || mymob -/* if(!screenmob.client.prefs.ghost_hud) + + if(!hud_shown) screenmob.client.screen -= static_inventory - else*/ - screenmob.client.screen += static_inventory + else + screenmob.client.screen += static_inventory diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 16adcda78d85..7f9ad85e154e 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -31,6 +31,7 @@ var/atom/movable/screen/slowed_icon var/atom/movable/screen/bleeding_icon + var/atom/movable/screen/transfusion_icon var/atom/movable/screen/shrapnel_icon var/atom/movable/screen/tethering_icon var/atom/movable/screen/tethered_icon @@ -107,6 +108,7 @@ qdel(thing) infodisplay.Cut() + mymob = null qdel(hide_actions_toggle) hide_actions_toggle = null @@ -128,6 +130,7 @@ slowed_icon = null shrapnel_icon = null bleeding_icon = null + transfusion_icon = null tethering_icon = null tethered_icon = null diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 79edbb5d06e2..6cf43dc343b7 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -332,31 +332,6 @@ unique_action.screen_loc = ui_datum.ui_gun_unique static_inventory += unique_action - //Handle the gun settings buttons - gun_setting_icon = new /atom/movable/screen/gun/mode() - gun_setting_icon.alpha = ui_alpha - gun_setting_icon.screen_loc = ui_datum.ui_gun_select - gun_setting_icon.update_icon(mymob) - static_inventory += gun_setting_icon - - gun_item_use_icon = new /atom/movable/screen/gun/item() - gun_item_use_icon.alpha = ui_alpha - gun_item_use_icon.screen_loc = ui_datum.ui_gun1 - gun_item_use_icon.update_icon(mymob) - static_inventory += gun_item_use_icon - - gun_move_icon = new /atom/movable/screen/gun/move() - gun_move_icon.alpha = ui_alpha - gun_move_icon.screen_loc = ui_datum.ui_gun2 - gun_move_icon.update_icon(mymob) - static_inventory += gun_move_icon - - gun_run_icon = new /atom/movable/screen/gun/run() - gun_run_icon.alpha = ui_alpha - gun_run_icon.screen_loc = ui_datum.ui_gun3 - gun_run_icon.update_icon(mymob) - static_inventory += gun_run_icon - /datum/hud/human/proc/draw_status_effects(datum/custom_hud/ui_datum) slowed_icon = new /atom/movable/screen() slowed_icon.icon = ui_datum.ui_style_icon @@ -383,6 +358,10 @@ tethered_icon.icon_state = "status_0" infodisplay += tethered_icon + transfusion_icon = new /atom/movable/screen() + transfusion_icon.icon = ui_datum.ui_style_icon + transfusion_icon.icon_state = "status_0" + infodisplay += transfusion_icon /mob/living/carbon/human/create_hud() if(client && client.prefs && !hud_used) diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm index 21d9a9414bbc..b5ee41e6d54c 100644 --- a/code/_onclick/hud/map_popups.dm +++ b/code/_onclick/hud/map_popups.dm @@ -41,6 +41,11 @@ /// If FALSE, this will not be cleared when calling /client/clear_screen() var/clear_with_screen = TRUE +/atom/movable/screen/Destroy() + master = null + hud = null // Not currently ever used + return ..() + /** * A screen object, which acts as a container for turfs and other things * you want to show on the map, which you usually attach to "vis_contents". diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/plane_master.dm index 9e6ff21aac18..d29228f4c16e 100644 --- a/code/_onclick/hud/rendering/plane_master.dm +++ b/code/_onclick/hud/rendering/plane_master.dm @@ -56,6 +56,13 @@ blend_mode = BLEND_OVERLAY render_relay_plane = RENDER_PLANE_NON_GAME +/// Plane master handling display of building roofs. They're meant to become invisible when inside a building. +/atom/movable/screen/plane_master/roof + name = "roof plane master" + plane = ROOF_PLANE + appearance_flags = PLANE_MASTER + blend_mode = BLEND_OVERLAY + /** * Plane master handling byond internal blackness * vars are set as to replicate behavior when rendering to other planes diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 394cff7271bb..565a23d1bbeb 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -121,29 +121,6 @@ zone_sel.update_icon(owner) static_inventory += zone_sel - //Handle the gun settings buttons - gun_setting_icon = new /atom/movable/screen/gun/mode() - gun_setting_icon.screen_loc = ui_robot_datum.ui_gun_select - gun_setting_icon.update_icon(owner) - static_inventory += gun_setting_icon - - gun_item_use_icon = new /atom/movable/screen/gun/item() - gun_item_use_icon.screen_loc = ui_robot_datum.ui_gun1 - gun_item_use_icon.update_icon(owner) - static_inventory += gun_item_use_icon - - gun_move_icon = new /atom/movable/screen/gun/move() - gun_move_icon.screen_loc = ui_robot_datum.ui_gun2 - gun_move_icon.update_icon(owner) - static_inventory += gun_move_icon - - gun_run_icon = new /atom/movable/screen/gun/run() - gun_run_icon.screen_loc = ui_robot_datum.ui_gun3 - gun_run_icon.update_icon(owner) - static_inventory += gun_run_icon - - - /mob/living/silicon/robot/create_hud() if(!hud_used) hud_used = new /datum/hud/robot(src) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 22e087f96b5f..9643d0f652ae 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -132,121 +132,6 @@ else color = null - - -/atom/movable/screen/gun - name = "gun" - dir = SOUTH - var/gun_click_time = -100 - -/atom/movable/screen/gun/move - name = "Allow Walking" - icon_state = "no_walk0" - -/atom/movable/screen/gun/move/update_icon(mob/user) - if(user.gun_mode) - if(user.target_can_move) - icon_state = "no_walk1" - name = "Disallow Walking" - else - icon_state = "no_walk0" - name = "Allow Walking" - screen_loc = initial(screen_loc) - return - screen_loc = null - -/atom/movable/screen/gun/move/clicked(mob/user) - if (..()) - return 1 - - if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes. - return 1 - if(!isgun(user.get_held_item())) - to_chat(user, "You need your gun in your active hand to do that!") - return 1 - user.AllowTargetMove() - gun_click_time = world.time - return 1 - - -/atom/movable/screen/gun/run - name = "Allow Running" - icon_state = "no_run0" - -/atom/movable/screen/gun/run/update_icon(mob/user) - if(user.gun_mode) - if(user.target_can_move) - if(user.target_can_run) - icon_state = "no_run1" - name = "Disallow Running" - else - icon_state = "no_run0" - name = "Allow Running" - screen_loc = initial(screen_loc) - return - screen_loc = null - -/atom/movable/screen/gun/run/clicked(mob/user) - if (..()) - return 1 - - if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes. - return 1 - if(!isgun(user.get_held_item())) - to_chat(user, "You need your gun in your active hand to do that!") - return 1 - user.AllowTargetRun() - gun_click_time = world.time - return 1 - - -/atom/movable/screen/gun/item - name = "Allow Item Use" - icon_state = "no_item0" - -/atom/movable/screen/gun/item/update_icon(mob/user) - if(user.gun_mode) - if(user.target_can_click) - icon_state = "no_item1" - name = "Allow Item Use" - else - icon_state = "no_item0" - name = "Disallow Item Use" - screen_loc = initial(screen_loc) - return - screen_loc = null - -/atom/movable/screen/gun/item/clicked(mob/user) - if (..()) - return 1 - - if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes. - return 1 - if(!isgun(user.get_held_item())) - to_chat(user, "You need your gun in your active hand to do that!") - return 1 - user.AllowTargetClick() - gun_click_time = world.time - return 1 - - -/atom/movable/screen/gun/mode - name = "Toggle Gun Mode" - icon_state = "gun0" - -/atom/movable/screen/gun/mode/update_icon(mob/user) - if(user.gun_mode) - icon_state = "gun1" - else - icon_state = "gun0" - -/atom/movable/screen/gun/mode/clicked(mob/user) - if (..()) - return 1 - user.ToggleGunMode() - return 1 - - /atom/movable/screen/zone_sel name = "damage zone" icon_state = "zone_sel" @@ -633,7 +518,7 @@ name = "queen locator" icon = 'icons/mob/hud/alien_standard.dmi' icon_state = "trackoff" - var/track_state = TRACKER_QUEEN + var/list/track_state = list(TRACKER_QUEEN, 0) /atom/movable/screen/queen_locator/clicked(mob/living/carbon/xenomorph/user, mods) if(!istype(user)) @@ -648,15 +533,23 @@ if(mods["alt"]) var/list/options = list() if(user.hive.living_xeno_queen) - options["Queen"] = TRACKER_QUEEN + options["Queen"] = list(TRACKER_QUEEN, 0) + if(user.hive.hive_location) - options["Hive Core"] = TRACKER_HIVE + options["Hive Core"] = list(TRACKER_HIVE, 0) + var/xeno_leader_index = 1 for(var/xeno in user.hive.xeno_leader_list) var/mob/living/carbon/xenomorph/xeno_lead = user.hive.xeno_leader_list[xeno_leader_index] if(xeno_lead) - options["Xeno Leader [xeno_lead]"] = "[xeno_leader_index]" + options["Xeno Leader [xeno_lead]"] = list(TRACKER_LEADER, xeno_leader_index) xeno_leader_index++ + + var/tunnel_index = 1 + for(var/obj/structure/tunnel/tracked_tunnel in user.hive.tunnels) + options["Tunnel [tracked_tunnel.tunnel_desc]"] = list(TRACKER_TUNNEL, tunnel_index) + tunnel_index++ + var/selected = tgui_input_list(user, "Select what you want the locator to track.", "Locator Options", options) if(selected) track_state = options[selected] diff --git a/code/_onclick/human.dm b/code/_onclick/human.dm index 7f023b4de5d3..cb71e27f9d1a 100644 --- a/code/_onclick/human.dm +++ b/code/_onclick/human.dm @@ -108,7 +108,7 @@ return user.visible_message(SPAN_NOTICE("\The [user] starts unstrapping \the [back_item] from [xeno]"), \ SPAN_NOTICE("You start unstrapping \the [back_item] from [xeno]."), null, 5, CHAT_TYPE_FLUFF_ACTION) - if(!do_after(user, HUMAN_STRIP_DELAY * user.get_skill_duration_multiplier(), INTERRUPT_ALL, BUSY_ICON_GENERIC, xeno, INTERRUPT_MOVED, BUSY_ICON_GENERIC)) + if(!do_after(user, HUMAN_STRIP_DELAY * user.get_skill_duration_multiplier(SKILL_CQC), INTERRUPT_ALL, BUSY_ICON_GENERIC, xeno, INTERRUPT_MOVED, BUSY_ICON_GENERIC)) to_chat(user, SPAN_WARNING("You were interrupted!")) return diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index ce942c81aa52..b67953b1edbe 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -10,72 +10,80 @@ else to_chat(src, SPAN_NOTICE(" You will no longer examine things you click on.")) -/mob/dead/observer/click(atom/A, list/mods) +/mob/dead/observer/click(atom/target, list/mods) if(..()) - return 1 + return TRUE if (mods["shift"] && mods["middle"]) - point_to(A) + point_to(target) return TRUE if(mods["ctrl"]) - if(A == src) + if(target == src) if(!can_reenter_corpse || !mind || !mind.current) return if(alert(src, "Are you sure you want to re-enter your corpse?", "Confirm", "Yes", "No") == "Yes") reenter_corpse() return TRUE - if(ismob(A) || isVehicle(A)) - if(isxeno(A) && SSticker.mode.check_xeno_late_join(src)) //if it's a xeno and all checks are alright, we are gonna try to take their body - var/mob/living/carbon/xenomorph/X = A - if(X.stat == DEAD || is_admin_level(X.z) || X.aghosted) - to_chat(src, SPAN_WARNING("You cannot join as [X].")) - ManualFollow(X) - return + if(ismob(target) || isVehicle(target)) + if(isxeno(target) && SSticker.mode.check_xeno_late_join(src)) //if it's a xeno and all checks are alright, we are gonna try to take their body + var/mob/living/carbon/xenomorph/xeno = target + if(xeno.stat == DEAD || is_admin_level(xeno.z) || xeno.aghosted) + to_chat(src, SPAN_WARNING("You cannot join as [xeno].")) + ManualFollow(xeno) + return FALSE if(!SSticker.mode.xeno_bypass_timer) - if((!islarva(X) && X.away_timer < XENO_LEAVE_TIMER) || (islarva(X) && X.away_timer < XENO_LEAVE_TIMER_LARVA)) - var/to_wait = XENO_LEAVE_TIMER - X.away_timer - if(islarva(X)) - to_wait = XENO_LEAVE_TIMER_LARVA - X.away_timer + if((!islarva(xeno) && xeno.away_timer < XENO_LEAVE_TIMER) || (islarva(xeno) && xeno.away_timer < XENO_LEAVE_TIMER_LARVA)) + var/to_wait = XENO_LEAVE_TIMER - xeno.away_timer + if(islarva(xeno)) + to_wait = XENO_LEAVE_TIMER_LARVA - xeno.away_timer if(to_wait > 60 SECONDS) // don't spam for clearly non-AFK xenos to_chat(src, SPAN_WARNING("That player hasn't been away long enough. Please wait [to_wait] second\s longer.")) - ManualFollow(A) + ManualFollow(target) return FALSE var/deathtime = world.time - timeofdeath - if(deathtime < 2.5 MINUTES) + if(deathtime < XENO_JOIN_DEAD_LARVA_TIME) var/message = "You have been dead for [DisplayTimeText(deathtime)]." message = SPAN_WARNING("[message]") to_chat(src, message) - to_chat(src, SPAN_WARNING("You must wait 2.5 minutes before rejoining the game!")) - ManualFollow(A) + to_chat(src, SPAN_WARNING("You must wait atleast 2.5 minutes before rejoining the game!")) + ManualFollow(target) return FALSE - if(alert(src, "Are you sure you want to transfer yourself into [X]?", "Confirm Transfer", "Yes", "No") != "Yes") + if(xeno.hive) + for(var/mob_name in xeno.hive.banished_ckeys) + if(xeno.hive.banished_ckeys[mob_name] == ckey) + to_chat(src, SPAN_WARNING("You are banished from the [xeno.hive], you may not rejoin unless the Queen re-admits you or dies.")) + ManualFollow(target) + return FALSE + + if(alert(src, "Are you sure you want to transfer yourself into [xeno]?", "Confirm Transfer", "Yes", "No") != "Yes") return FALSE - if(((!islarva(X) && X.away_timer < XENO_LEAVE_TIMER) || (islarva(X) && X.away_timer < XENO_LEAVE_TIMER_LARVA)) || X.stat == DEAD) // Do it again, just in case + if(((!islarva(xeno) && xeno.away_timer < XENO_LEAVE_TIMER) || (islarva(xeno) && xeno.away_timer < XENO_LEAVE_TIMER_LARVA)) || xeno.stat == DEAD) // Do it again, just in case to_chat(src, SPAN_WARNING("That xenomorph can no longer be controlled. Please try another.")) return FALSE - SSticker.mode.transfer_xeno(src, X) + SSticker.mode.transfer_xeno(src, xeno) return TRUE - ManualFollow(A) + ManualFollow(target) return TRUE - following = null - abstract_move(get_turf(A)) - return 1 + if(!istype(target, /atom/movable/screen)) + following = null + abstract_move(get_turf(target)) + return TRUE if(world.time <= next_move) - return 1 + return TRUE next_move = world.time + 8 // You are responsible for checking config.ghost_interaction when you override this function // Not all of them require checking, see below if(!mods["shift"]) - A.attack_ghost(src) - return 1 + target.attack_ghost(src) + return FALSE // Oh by the way this didn't work with old click code which is why clicking shit didn't spam you /atom/proc/attack_ghost(mob/dead/observer/user) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index c53d58185753..9c9784286d09 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -12,9 +12,10 @@ if (isStructure(A) && get_dist(src, A) <= 1) var/obj/structure/S = A S.do_climb(src, mods) + return TRUE else if(!(isitem(A) && get_dist(src, A) <= 1) && client.prefs.toggle_prefs & TOGGLE_MIDDLE_MOUSE_SWAP_HANDS) swap_hand() - return TRUE + return TRUE return ..() @@ -33,4 +34,4 @@ Have no reason to click on anything at all. */ /mob/new_player/click() - return 1 + return diff --git a/code/_onclick/xeno.dm b/code/_onclick/xeno.dm index 379b4746c858..62d612790930 100644 --- a/code/_onclick/xeno.dm +++ b/code/_onclick/xeno.dm @@ -2,7 +2,7 @@ Xenomorph */ -/mob/living/carbon/xenomorph/UnarmedAttack(atom/target, proximity, click_parameters, tile_attack = FALSE) +/mob/living/carbon/xenomorph/UnarmedAttack(atom/target, proximity, click_parameters, tile_attack = FALSE, ignores_resin = FALSE) if(lying || burrow) //No attacks while laying down return FALSE var/mob/alt @@ -28,6 +28,16 @@ break if (target == T && alt) target = alt + if (T && ignores_resin) // Will not target resin walls and doors if this is set to true. This is normally only set to true through a directional attack. + if(istype(T, /obj/structure/mineral_door/resin)) + var/obj/structure/mineral_door/resin/attacked_door = T + if(hivenumber == attacked_door.hivenumber) + return FALSE + if(istype(T, /turf/closed/wall/resin)) + var/turf/closed/wall/resin/attacked_wall = T + if(hivenumber == attacked_wall.hivenumber) + return FALSE + target = target.handle_barriers(src, , (PASS_MOB_THRU_XENO|PASS_TYPE_CRAWLER)) // Checks if target will be attacked by the current alien OR if the blocker will be attacked switch(target.attack_alien(src)) if(XENO_ATTACK_ACTION) @@ -75,7 +85,7 @@ return if (client && client.prefs && client.prefs.toggle_prefs & TOGGLE_DIRECTIONAL_ATTACK) next_move += 0.25 SECONDS //Slight delay on missed directional attacks. If it finds a mob in the target tile, this will be overwritten by the attack delay. - return UnarmedAttack(get_step(src, Get_Compass_Dir(src, A)), tile_attack = TRUE) + return UnarmedAttack(get_step(src, Get_Compass_Dir(src, A)), tile_attack = TRUE, ignores_resin = TRUE) return FALSE /**The parent proc, will default to UnarmedAttack behaviour unless overriden @@ -89,43 +99,35 @@ so that it doesn't double up on the delays) so that it applies the delay immedia /atom/proc/attack_alien(mob/user as mob) return -/mob/living/carbon/xenomorph/click(atom/A, list/mods) - if (queued_action) - handle_queued_action(A) +/mob/living/carbon/xenomorph/click(atom/target, list/mods) + if(queued_action) + handle_queued_action(target) return TRUE - if (mods["alt"] && mods["shift"]) - if (istype(A, /mob/living/carbon/xenomorph)) - var/mob/living/carbon/xenomorph/X = A - - if (X && !QDELETED(X) && X != observed_xeno && X.stat != DEAD && !is_admin_level(X.z) && X.check_state(1) && X.hivenumber == hivenumber) - if (caste && istype(caste, /datum/caste_datum/queen)) - var/mob/living/carbon/xenomorph/oldXeno = observed_xeno - overwatch(X, FALSE) - - if (oldXeno) - oldXeno.hud_set_queen_overwatch() - if (X && !QDELETED(X)) - X.hud_set_queen_overwatch() - - else - overwatch(X) + var/alt_pressed = mods["alt"] == "1" + var/shift_pressed = mods["shift"] == "1" + var/middle_pressed = mods["middle"] == "1" + if(alt_pressed && shift_pressed) + if(istype(target, /mob/living/carbon/xenomorph)) + var/mob/living/carbon/xenomorph/xeno = target + if(!QDELETED(xeno) && xeno.stat != DEAD && !is_admin_level(xeno.z) && xeno.check_state(TRUE) && xeno.hivenumber == hivenumber) + overwatch(xeno) next_move = world.time + 3 // Some minimal delay so this isn't crazy spammy - return 1 - - if(mods["shift"] && !mods["middle"]) - if(selected_ability && client && client.prefs && !(client.prefs.toggle_prefs & TOGGLE_MIDDLE_MOUSE_CLICK)) - selected_ability.use_ability_wrapper(A, mods) - return TRUE - - if(mods["middle"] && !mods["shift"]) - if(selected_ability && client && client.prefs && client.prefs.toggle_prefs & TOGGLE_MIDDLE_MOUSE_CLICK) - selected_ability.use_ability_wrapper(A, mods) + return TRUE + + var/middle_pref = client.prefs && (client.prefs.toggle_prefs & TOGGLE_MIDDLE_MOUSE_CLICK) != 0 // client is already tested to be non-null by caller + if(selected_ability && shift_pressed == !middle_pref && middle_pressed == middle_pref) + if(istype(target, /atom/movable/screen)) + // Click through the UI: Currently this won't attempt to sprite click any mob there, just the turf + var/turf/turf = params2turf(mods["screen-loc"], get_turf(client.eye), client) + if(turf) + target = turf + if(selected_ability.use_ability_wrapper(target, mods)) return TRUE if(next_move >= world.time) - return TRUE + return FALSE return ..() diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index e33b20fae606..08de7b5c02ff 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -20,10 +20,12 @@ var/policy var/static/regex/ic_filter_regex + var/list/fail_to_topic_whitelisted_ips /datum/controller/configuration/proc/admin_reload() if(IsAdminAdvancedProcCall()) - return + alert_proccall("configuration admin_reload") + return PROC_BLOCKED log_admin("[key_name(usr)] has forcefully reloaded the configuration from disk.") message_admins("[key_name_admin(usr)] has forcefully reloaded the configuration from disk.") full_wipe() @@ -32,7 +34,8 @@ /datum/controller/configuration/proc/Load(_directory) if(IsAdminAdvancedProcCall()) //If admin proccall is detected down the line it will horribly break everything. - return + alert_proccall("configuration Load") + return PROC_BLOCKED if(_directory) directory = _directory if(entries) @@ -50,6 +53,7 @@ loadmaplist(CONFIG_GROUND_MAPS_FILE, GROUND_MAP) loadmaplist(CONFIG_SHIP_MAPS_FILE, SHIP_MAP) LoadChatFilter() + LoadTopicRateWhitelist() if(Master) Master.OnConfigLoad() @@ -115,7 +119,8 @@ /datum/controller/configuration/proc/full_wipe() if(IsAdminAdvancedProcCall()) - return + alert_proccall("configuration full_wipe") + return PROC_BLOCKED entries_by_type.Cut() QDEL_LIST_ASSOC_VAL(entries) entries = null @@ -161,7 +166,8 @@ /datum/controller/configuration/proc/LoadEntries(filename, list/stack = list()) if(IsAdminAdvancedProcCall()) - return + alert_proccall("configuration LoadEntries") + return PROC_BLOCKED var/filename_to_test = world.system_type == MS_WINDOWS ? lowertext(filename) : filename if(filename_to_test in stack) @@ -262,7 +268,7 @@ CRASH("Missing config entry for [entry_type]!") if((E.protection & CONFIG_ENTRY_HIDDEN) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]") log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]") - return + return PROC_BLOCKED return E.config_entry_value @@ -276,7 +282,7 @@ CRASH("Missing config entry for [entry_type]!") if((E.protection & CONFIG_ENTRY_LOCKED) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Set" && GLOB.LastAdminCalledTargetRef == "[REF(src)]") log_admin_private("Config rewrite of [entry_type] to [new_val] attempted by [key_name(usr)]") - return + return PROC_BLOCKED return E.ValidateAndSet("[new_val]") @@ -324,3 +330,19 @@ //Message admins when you can. /datum/controller/configuration/proc/DelayedMessageAdmins(text) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(message_admins), text), 0) + +/datum/controller/configuration/proc/LoadTopicRateWhitelist() + LAZYINITLIST(fail_to_topic_whitelisted_ips) + if(!fexists("[directory]/topic_rate_limit_whitelist.txt")) + log_config("Error 404: topic_rate_limit_whitelist.txt not found!") + return + + log_config("Loading config file topic_rate_limit_whitelist.txt...") + + for(var/line in file2list("[directory]/topic_rate_limit_whitelist.txt")) + if(!line) + continue + if(findtextEx(line, "#", 1, 2)) + continue + + fail_to_topic_whitelisted_ips[line] = 1 diff --git a/code/controllers/configuration/entries/dbconfig.dm b/code/controllers/configuration/entries/dbconfig.dm new file mode 100644 index 000000000000..be4799988f3b --- /dev/null +++ b/code/controllers/configuration/entries/dbconfig.dm @@ -0,0 +1,33 @@ +/datum/config_entry/string/db_provider + config_entry_value = "native" + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/db_address + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/number/db_port + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/db_database + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/db_username + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/db_password + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/db_debug_mode + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/number/db_min_threads + config_entry_value = 1 + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/number/db_max_threads + config_entry_value = 100 + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/db_filename + config_entry_value = "data/local.db" + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 357be8306b2a..743f9be9fec0 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -116,3 +116,14 @@ /datum/config_entry/flag/events_disallowed config_entry_value = FALSE + + +///Used to determine how many extra larva you want per burst. Supports fractions. See /datum/hive_status/proc/increase_larva_after_burst() +/datum/config_entry/number/extra_larva_per_burst + config_entry_value = 1 + integer = FALSE + +/datum/config_entry/number/embryo_burst_timer + min_val = 1 + config_entry_value = 450 + integer = TRUE diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index fe1d7eb27192..125ab1effa77 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -263,7 +263,7 @@ Voting // Gamemode to auto-switch to at the start of the round /datum/config_entry/string/gamemode_default - config_entry_value = "extended" + config_entry_value = "Extended" // Rounds needed for gamemode vote /datum/config_entry/number/gamemode_rounds_needed @@ -529,6 +529,25 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /datum/config_entry/string/round_results_webhook_url +/// InfluxDB v2 Host to connect to for sending statistics (over HTTP API) +/datum/config_entry/string/influxdb_host +/// InfluxDB v2 Bucket to send staistics to +/datum/config_entry/string/influxdb_bucket +/// InfluxDB v2 Organization to access buckets of +/datum/config_entry/string/influxdb_org +/// InfluxDB v2 API Token to access the organization and bucket +/datum/config_entry/string/influxdb_token + +/// How often to snapshot general game statistics to influxdb driver +/datum/config_entry/number/influxdb_stats_period + config_entry_value = 30 +/// How often to snapshot MC statistics +/datum/config_entry/number/influxdb_mcstats_period + config_entry_value = 60 +/// How often to send queued influxdb statistics +/datum/config_entry/number/influxdb_send_period + config_entry_value = 10 + /// logs all timers in buckets on automatic bucket reset (Useful for timer debugging) /datum/config_entry/flag/log_timers_on_bucket_reset @@ -542,3 +561,67 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /datum/config_entry/number/hard_deletes_overrun_limit default = 0 min_val = 0 + +/datum/config_entry/string/bot_prefix + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/bot_command + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/number/certification_minutes + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/number/topic_max_size + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/log_world_topic + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/keyed_list/topic_tokens + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_TEXT + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/keyed_list/topic_tokens/ValidateListEntry(key_name, key_value) + return key_value != "topic_token" && ..() + + +//Fail2Topic settings. +/datum/config_entry/number/topic_rate_limit + config_entry_value = 5 + min_val = 1 + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/number/topic_max_fails + config_entry_value = 5 + min_val = 1 + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/topic_rule_name + config_entry_value = "_DD_Fail2topic" + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/number/topic_max_size + config_entry_value = 500 + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/topic_enabled + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/redis_enabled + config_entry_value = FALSE + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/redis_logging + config_entry_value = FALSE + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/redis_connection + config_entry_value = "redis://127.0.0.1/" + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/instance_name + config_entry_value = "game" + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/guest_ban diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 283fe79cfead..38e57df93cef 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -7,6 +7,20 @@ SUBSYSTEM_DEF(assets) var/list/preload = list() var/datum/asset_transport/transport = new() +/datum/controller/subsystem/assets/OnConfigLoad() + var/newtransporttype = /datum/asset_transport + switch (CONFIG_GET(string/asset_transport)) + if ("webroot") + newtransporttype = /datum/asset_transport/webroot + + if (newtransporttype == transport.type) + return + + var/datum/asset_transport/newtransport = new newtransporttype () + if (newtransport.validate_config()) + transport = newtransport + transport.Load() + /datum/controller/subsystem/assets/Initialize() for(var/type in typesof(/datum/asset)) var/datum/asset/A = type diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 833ae334ab7a..23da8cc8c9eb 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -9,15 +9,24 @@ SUBSYSTEM_DEF(atoms) flags = SS_NO_FIRE var/old_initialized + /// A count of how many initalize changes we've made. We want to prevent old_initialize being overriden by some other value, breaking init code + var/initialized_changed = 0 + var/init_start_time + var/processing_late_loaders = FALSE var/list/late_loaders = list() var/list/roundstart_loaders = list() var/list/BadInitializeCalls = list() + initialized = INITIALIZATION_INSSATOMS + /datum/controller/subsystem/atoms/Initialize(timeofday) + init_start_time = world.time initialized = INITIALIZATION_INNEW_MAPLOAD InitializeAtoms() + initialized = INITIALIZATION_INNEW_REGULAR + old_initialized = initialized // Set up roundstart seed list. This is here because vendors were // bugging out and not populating with the correct packet names @@ -29,46 +38,84 @@ SUBSYSTEM_DEF(atoms) if(initialized == INITIALIZATION_INSSATOMS) return - initialized = INITIALIZATION_INNEW_MAPLOAD + set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD) fix_atoms_locs(atoms) + // This may look a bit odd, but if the actual atom creation runtimes for some reason, we absolutely need to set initialized BACK + CreateAtoms(atoms) + clear_tracked_initalize() + + InitializeLateLoaders() + +/// Processes all late_loaders, checking the length each iteration and prevents duplicate calls +/// This is necessary because of an edge case where there might be simultanious calls to InitializeAtoms +/datum/controller/subsystem/atoms/proc/InitializeLateLoaders() + if(processing_late_loaders) // If we still manage to double this proc, try a ++ here, or solve the root of the problem + #ifdef TESTING + testing("Ignoring duplicate request to InitializeLateLoaders") + #endif + return + + processing_late_loaders = TRUE + + for(var/I = 1; I <= late_loaders.len; I++) + var/atom/A = late_loaders[I] + //I hate that we need this + if(QDELETED(A)) + continue + A.LateInitialize() + + #ifdef TESTING + testing("Late initialized [late_loaders.len] atoms") + #endif + late_loaders.Cut() + processing_late_loaders = FALSE + +/// Actually creates the list of atoms. Exists soley so a runtime in the creation logic doesn't cause initalized to totally break +/datum/controller/subsystem/atoms/proc/CreateAtoms(list/atoms) + #ifdef TESTING var/count + #endif + var/list/mapload_arg = list(TRUE) if(atoms) + #ifdef TESTING count = atoms.len - for(var/I in atoms) - var/atom/A = I + #endif + + for(var/I in 1 to atoms.len) + var/atom/A = atoms[I] if(!(A.flags_atom & INITIALIZED)) - InitAtom(I, TRUE, mapload_arg) CHECK_TICK + InitAtom(A, TRUE, mapload_arg) else + #ifdef TESTING count = 0 - for(var/atom/A in world) + #endif + + for(var/atom/A as anything in world) if(!(A.flags_atom & INITIALIZED)) InitAtom(A, FALSE, mapload_arg) + #ifdef TESTING ++count + #endif CHECK_TICK + #ifdef TESTING testing("Initialized [count] atoms") - pass(count) - - initialized = INITIALIZATION_INNEW_REGULAR - - if(late_loaders.len) - for(var/I in late_loaders) - var/atom/A = I - A.LateInitialize() - testing("Late initialized [late_loaders.len] atoms") - late_loaders.Cut() + #endif /// Init this specific atom /datum/controller/subsystem/atoms/proc/InitAtom(atom/A, from_template = FALSE, list/arguments) var/the_type = A.type if(QDELING(A)) - BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE + // Check init_start_time to not worry about atoms created before the atoms SS that are cleaned up before this + if (A.gc_destroyed > init_start_time) + BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE return TRUE + // This is handled and battle tested by dreamchecker. Limit to UNIT_TESTS just in case that ever fails. #ifdef UNIT_TESTS var/start_tick = world.time #endif @@ -82,23 +129,24 @@ SUBSYSTEM_DEF(atoms) var/qdeleted = FALSE - if(result != INITIALIZE_HINT_NORMAL) - switch(result) - if(INITIALIZE_HINT_LATELOAD) - if(arguments[1]) //mapload - late_loaders += A - else - A.LateInitialize() - if(INITIALIZE_HINT_QDEL) - qdel(A) - qdeleted = TRUE - if(INITIALIZE_HINT_ROUNDSTART) - if(SSticker.current_state >= GAME_STATE_PLAYING) - A.LateInitialize() - else - roundstart_loaders += A + switch(result) + if (INITIALIZE_HINT_NORMAL) + // pass + if(INITIALIZE_HINT_LATELOAD) + if(arguments[1]) //mapload + late_loaders += A else - BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT + A.LateInitialize() + if(INITIALIZE_HINT_ROUNDSTART) + if(SSticker.current_state >= GAME_STATE_PLAYING) + A.LateInitialize() + else + roundstart_loaders += A + if(INITIALIZE_HINT_QDEL) + qdel(A) + qdeleted = TRUE + else + BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT if(!A) //possible harddel qdeleted = TRUE @@ -130,11 +178,29 @@ SUBSYSTEM_DEF(atoms) A.loc = A.loc /datum/controller/subsystem/atoms/proc/map_loader_begin() - old_initialized = initialized - initialized = INITIALIZATION_INSSATOMS + set_tracked_initalized(INITIALIZATION_INSSATOMS) /datum/controller/subsystem/atoms/proc/map_loader_stop() - initialized = old_initialized + clear_tracked_initalize() + +/// Use this to set initialized to prevent error states where old_initialized is overriden. It keeps happening and it's cheesing me off +/datum/controller/subsystem/atoms/proc/set_tracked_initalized(value) + if(!initialized_changed) + old_initialized = initialized + initialized = value + else + // TG has this as a stack_trace, but currently is a non-issue so lets not escalate it to be a runtime + debug_log("We started maploading while we were already maploading. You doing something odd?") + initialized_changed += 1 + +/datum/controller/subsystem/atoms/proc/clear_tracked_initalize() + initialized_changed -= 1 + if(!initialized_changed) + initialized = old_initialized + +/// Returns TRUE if anything is currently being initialized +/datum/controller/subsystem/atoms/proc/initializing_something() + return initialized_changed > 0 /datum/controller/subsystem/atoms/Recover() initialized = SSatoms.initialized @@ -160,4 +226,4 @@ SUBSYSTEM_DEF(atoms) /datum/controller/subsystem/atoms/Shutdown() var/initlog = InitLog() if(initlog) - text2file(initlog, "data/initialize.log") + text2file(initlog, "[GLOB.log_directory]/initialize.log") diff --git a/code/controllers/subsystem/autofire.dm b/code/controllers/subsystem/autofire.dm new file mode 100644 index 000000000000..3d3abbd2669f --- /dev/null +++ b/code/controllers/subsystem/autofire.dm @@ -0,0 +1,85 @@ +/** + * # Autofire Subsystem + * + * Maintains a timer-like system to handle autofiring. Much of this code is modeled + * after or adapted from TGMC's runechat subsytem. + * + * Note that this has the same structure for storing and queueing shooter component as the timer subsystem does + * for handling timers: the bucket_list is a list of autofire component, each of which are the head + * of a linked list. Any given index in bucket_list could be null, representing an empty bucket. + * + * Doesn't support any event scheduled for more than 100 ticks in the future, as it has no secondary queue by design + */ +SUBSYSTEM_DEF(automatedfire) + name = "Automated fire" + flags = SS_TICKER | SS_NO_INIT + wait = 1 + priority = SS_PRIORITY_AUTOFIRE + + /// 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 first non-empty bucket + var/practical_offset = 1 + ///How many buckets for every frame of world.fps + var/bucket_resolution = 0 + /// How many shooter are in the buckets + var/shooter_count = 0 + /// List of buckets, each bucket holds every shooter that has to shoot this byond tick + var/list/bucket_list = list() + /// Reference to the next shooter before we clean shooter.next + var/datum/component/automatedfire/next_shooter + +/datum/controller/subsystem/automatedfire/PreInit() + bucket_list.len = AUTOFIRE_BUCKET_LEN + head_offset = world.time + bucket_resolution = world.tick_lag + +/datum/controller/subsystem/automatedfire/stat_entry(msg = "ActShooters: [shooter_count]") + return ..() + +/datum/controller/subsystem/automatedfire/fire(resumed = FALSE) + // Check for when we need to loop the buckets, this occurs when + // the head_offset is approaching AUTOFIRE_BUCKET_LEN ticks in the past + if (practical_offset > AUTOFIRE_BUCKET_LEN) + head_offset += TICKS2DS(AUTOFIRE_BUCKET_LEN) + practical_offset = 1 + resumed = FALSE + + // Check for when we have to reset buckets, typically from auto-reset + if ((length(bucket_list) != AUTOFIRE_BUCKET_LEN) || (world.tick_lag != bucket_resolution)) + reset_buckets() + bucket_list = src.bucket_list + resumed = FALSE + + // Store a reference to the 'working' shooter so that we can resume if the MC + // has us stop mid-way through processing + var/static/datum/component/automatedfire/shooter + if (!resumed) + shooter = null + + // Iterate through each bucket starting from the practical offset + while (practical_offset <= AUTOFIRE_BUCKET_LEN && head_offset + ((practical_offset - 1) * world.tick_lag) <= world.time) + if(!shooter) + shooter = bucket_list[practical_offset] + bucket_list[practical_offset] = null + + while (shooter) + next_shooter = shooter.next + INVOKE_ASYNC(shooter, TYPE_PROC_REF(/datum/component/automatedfire, process_shot)) + + SSautomatedfire.shooter_count-- + shooter = next_shooter + if (MC_TICK_CHECK) + return + + // Move to the next bucket + practical_offset++ + +/datum/controller/subsystem/automatedfire/Recover() + bucket_list |= SSautomatedfire.bucket_list + +///In the event of a change of world.tick_lag, we refresh the size of the bucket and the bucket resolution +/datum/controller/subsystem/automatedfire/proc/reset_buckets() + bucket_list.len = AUTOFIRE_BUCKET_LEN + head_offset = world.time + bucket_resolution = world.tick_lag diff --git a/code/controllers/subsystem/communications.dm b/code/controllers/subsystem/communications.dm index 1fbc92f73d84..a98eaa0f7876 100644 --- a/code/controllers/subsystem/communications.dm +++ b/code/controllers/subsystem/communications.dm @@ -216,6 +216,7 @@ var/const/RADIO_DEFAULT = "radio_default" var/const/RADIO_TO_AIRALARM = "radio_airalarm" //air alarms var/const/RADIO_FROM_AIRALARM = "radio_airalarm_rcvr" //devices interested in receiving signals from air alarms var/const/RADIO_CHAT = "radio_telecoms" +var/const/RADIO_SIGNALS = "radio_signals" var/const/RADIO_ATMOSIA = "radio_atmos" var/const/RADIO_NAVBEACONS = "radio_navbeacon" var/const/RADIO_AIRLOCK = "radio_airlock" @@ -368,6 +369,9 @@ SUBSYSTEM_DEF(radio) for(var/datum/weakref/device_ref as anything in devices[filter]) var/obj/device = device_ref.resolve() + if(!device) + continue + if(device == source) continue @@ -400,12 +404,9 @@ SUBSYSTEM_DEF(radio) /datum/radio_frequency/proc/remove_listener(obj/device) for (var/devices_filter in devices) var/list/devices_line = devices[devices_filter] - devices_line -= WEAKREF(device) - while (null in devices_line) - devices_line -= null - if (devices_line.len==0) + devices_line -= device.weak_reference + if (!length(devices_line)) devices -= devices_filter - qdel(devices_line) /datum/signal var/obj/source diff --git a/code/controllers/subsystem/fail_to_topic.dm b/code/controllers/subsystem/fail_to_topic.dm new file mode 100644 index 000000000000..45674683a443 --- /dev/null +++ b/code/controllers/subsystem/fail_to_topic.dm @@ -0,0 +1,81 @@ +SUBSYSTEM_DEF(fail_to_topic) + name = "Fail to Topic" + init_order = SS_INIT_FAIL_TO_TOPIC + flags = SS_BACKGROUND + runlevels = ALL + + var/list/rate_limiting = list() + var/list/fail_counts = list() + var/list/active_bans = list() + var/list/currentrun = list() + + var/rate_limit + var/max_fails + var/enabled = FALSE + +/datum/controller/subsystem/fail_to_topic/Initialize(timeofday) + rate_limit = ((CONFIG_GET(number/topic_rate_limit)) SECONDS) + max_fails = CONFIG_GET(number/topic_max_fails) + enabled = CONFIG_GET(flag/topic_enabled) + + if (world.system_type == UNIX && enabled) + enabled = FALSE + WARNING("fail_to_topic subsystem disabled. UNIX is not supported.") + return SS_INIT_NO_NEED + + if (!enabled) + can_fire = FALSE + return SS_INIT_NO_NEED + + return SS_INIT_SUCCESS + +/datum/controller/subsystem/fail_to_topic/fire(resumed = FALSE) + if(!resumed) + currentrun = rate_limiting.Copy() + //cache for sanic speed (lists are references anyways) + var/list/current_run = currentrun + + while(current_run.len) + var/ip = current_run[current_run.len] + var/last_attempt = current_run[ip] + current_run.len-- + + // last_attempt list housekeeping + if(world.time - last_attempt > rate_limit) + rate_limiting -= ip + fail_counts -= ip + + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/fail_to_topic/proc/IsRateLimited(ip) + if(!enabled) + return FALSE + + var/last_attempt = rate_limiting[ip] + + if (config.fail_to_topic_whitelisted_ips[ip]) + return FALSE + + if (active_bans[ip]) + return TRUE + + rate_limiting[ip] = world.time + + if (isnull(last_attempt)) + return FALSE + + if (world.time - last_attempt > rate_limit) + fail_counts -= ip + return FALSE + else + var/failures = fail_counts[ip] + + if (isnull(failures)) + fail_counts[ip] = 1 + return TRUE + else if (failures > max_fails) + return TRUE + else + fail_counts[ip] = failures + 1 + return TRUE diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 100cf0835e76..e94d6b1aff1d 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -139,6 +139,13 @@ SUBSYSTEM_DEF(garbage) pass_counts[i] = 0 fail_counts[i] = 0 +#ifdef EXPERIMENT_515_QDEL_HARD_REFERENCE +// 1 from the hard reference in the queue, and 1 from the variable used before this +#define IS_DELETED(datum, _) (refcount(##datum) == 2) +#else +#define IS_DELETED(datum, gcd_at_time) (isnull(##datum) || ##datum.gc_destroyed != gcd_at_time) +#endif + /datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_FILTER) if (level == GC_QUEUE_FILTER) delslasttick = 0 @@ -159,26 +166,33 @@ SUBSYSTEM_DEF(garbage) //Normally this isn't expensive, but the gc queue can grow to 40k items, and that gets costly/causes overrun. for (var/i in 1 to length(queue)) var/list/L = queue[i] - if (length(L) < 2) + if (length(L) < GC_QUEUE_ITEM_INDEX_COUNT) count++ if (MC_TICK_CHECK) return continue - var/GCd_at_time = L[1] - 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/refID = L[2] + +#ifdef EXPERIMENT_515_QDEL_HARD_REFERENCE + var/datum/D = L[GC_QUEUE_ITEM_REF] +#else + var/GCd_at_time = L[GC_QUEUE_ITEM_GCD_DESTROYED] + var/refID = L[GC_QUEUE_ITEM_REF] var/datum/D D = locate(refID) +#endif - if (!D || D.gc_destroyed != GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake + if (IS_DELETED(D, GCd_at_time)) // So if something else coincidently gets the same ref, it's not deleted by mistake ++gcedlasttick ++totalgcs pass_counts[level]++ #ifdef REFERENCE_TRACKING - reference_find_on_fail -= refID //It's deleted we don't care anymore. + reference_find_on_fail -= text_ref(D) //It's deleted we don't care anymore. #endif if (MC_TICK_CHECK) return @@ -194,7 +208,7 @@ SUBSYSTEM_DEF(garbage) switch (level) if (GC_QUEUE_CHECK) #ifdef REFERENCE_TRACKING - if(reference_find_on_fail[refID]) + if(reference_find_on_fail[text_ref(D)]) INVOKE_ASYNC(D, TYPE_PROC_REF(/datum,find_references)) ref_searching = TRUE #ifdef GC_FAILURE_HARD_LOOKUP @@ -202,12 +216,17 @@ SUBSYSTEM_DEF(garbage) INVOKE_ASYNC(D, TYPE_PROC_REF(/datum,find_references)) ref_searching = TRUE #endif - reference_find_on_fail -= refID + reference_find_on_fail -= text_ref(D) #endif var/type = D.type var/datum/qdel_item/I = items[type] - //log_world("## TESTING: GC: -- [text_ref(D)] | [type] was unable to be GC'd --") + var/message = "## TESTING: GC: -- [text_ref(D)] | [type] was unable to be GC'd --" +#if DM_VERSION >= 515 + message = "[message] (ref count of [refcount(D)])" +#endif + log_world(message) + #ifdef TESTING for(var/c in GLOB.admins) //Using testing() here would fill the logs with ADMIN_VV garbage var/client/admin = c @@ -242,19 +261,30 @@ SUBSYSTEM_DEF(garbage) queue.Cut(1,count+1) count = 0 +#undef IS_DELETED + /datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_FILTER) if (isnull(D)) return if (level > GC_QUEUE_COUNT) HardDelete(D) return - var/gctime = world.time + var/queue_time = world.time + +#ifdef EXPERIMENT_515_QDEL_HARD_REFERENCE + var/refid = D +#else var/refid = text_ref(D) +#endif + + var/static/uid = 0 + uid = WRAP(uid+1, 1, SHORT_REAL_LIMIT - 1) + if (D.gc_destroyed <= 0) + D.gc_destroyed = uid - D.gc_destroyed = gctime var/list/queue = queues[level] - queue[++queue.len] = list(gctime, refid) // not += for byond reasons + queue[++queue.len] = list(queue_time, refid, D.gc_destroyed) // not += for byond reasons //this is mainly to separate things profile wise. /datum/controller/subsystem/garbage/proc/HardDelete(datum/D, force) diff --git a/code/controllers/subsystem/influxdriver.dm b/code/controllers/subsystem/influxdriver.dm new file mode 100644 index 000000000000..7e5289dfc518 --- /dev/null +++ b/code/controllers/subsystem/influxdriver.dm @@ -0,0 +1,132 @@ +/// Sends collected statistics to an influxdb v2 backend periodically +SUBSYSTEM_DEF(influxdriver) + name = "InfluxDB Driver" + wait = 10 SECONDS + init_order = SS_INIT_INFLUXDRIVER + priority = SS_PRIORITY_INFLUXDRIVER + runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY + + var/list/send_queue = list() + + /// Maximum amount of metric lines to send at most in one request + /// This is neccessary because sending a lot of metrics can get expensive + /// and drive the subsystem into overtime, but we can't split the work as it'd be even less efficient + var/max_batch = 150 + + /// Last timestamp in microseconds + var/timestamp_cache_realtime + /// Last tick time the timestamp was taken at + var/timestamp_cache_worldtime + +/datum/controller/subsystem/influxdriver/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_send_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 2 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxdriver/stat_entry(msg) + msg += "period=[wait] queue=[length(send_queue)]" + return ..() + +/datum/controller/subsystem/influxdriver/proc/unix_timestamp_string() // pending change to rust-g + return RUSTG_CALL(RUST_G, "unix_timestamp")() + +/datum/controller/subsystem/influxdriver/proc/update_timestamp() + PRIVATE_PROC(TRUE) + // We make only one request to rustg per game tick, so we cache the result per world.time + var/whole_timestamp = unix_timestamp_string() // Format "7129739474.4758981" - timestamp with up to 7-8 decimals + var/list/tsparts = splittext(whole_timestamp, ".") + var/fractional = copytext(pad_trailing(tsparts[2], "0", 6), 1, 7) // in microseconds + timestamp_cache_worldtime = world.time + timestamp_cache_realtime = "[tsparts[1]][fractional]" + +/datum/controller/subsystem/influxdriver/fire(resumed) + var/maxlen = min(length(send_queue)+1, max_batch) + var/list/queue = send_queue.Copy(1, maxlen) + send_queue.Cut(1, maxlen) + flush_queue(queue) + +/// Flushes measurements batch to InfluxDB backend +/datum/controller/subsystem/influxdriver/proc/flush_queue(list/queue) + PRIVATE_PROC(TRUE) + + var/host = CONFIG_GET(string/influxdb_host) + var/token = CONFIG_GET(string/influxdb_token) + var/bucket = CONFIG_GET(string/influxdb_bucket) + var/org = CONFIG_GET(string/influxdb_org) + + if(!host || !token || !bucket || !org) + can_fire = FALSE + return + + if(!length(queue)) + return // Nothing to do + + var/url = "[host]/api/v2/write?org=[org]&bucket=[bucket]&precision=us" // microseconds + var/list/headers = list() + headers["Authorization"] = "Token [token]" + headers["Content-Type"] = "text/plain; charset=utf-8" + headers["Accept"] = "application/json" + + var/datum/http_request/request = new + var/payload = "" + for(var/line in queue) + payload += "[line]\n" + request.prepare(RUSTG_HTTP_METHOD_POST, url, payload, headers) + request.begin_async() + // TODO possibly check back result of request later + +/// Enqueues sending to InfluxDB Backend selected measurement values - round_id and timestamp are filled in automatically +/datum/controller/subsystem/influxdriver/proc/enqueue_stats(measurement, list/tags, list/fields) + . = FALSE + var/valid = FALSE + var/serialized = "[measurement],round_id=[GLOB.round_id]" + if(tags) + for(var/tag in tags) + var/serialized_tag = serialize_field(tag, tags[tag]) + if(serialized_tag) + serialized += ",[serialized_tag]" + serialized += " " + var/comma = "" + for(var/field in fields) + var/serialized_field = serialize_field(field, fields[field]) + if(serialized_field) + valid = TRUE + serialized += "[comma][serialized_field]" + comma = "," + if(!valid) + CRASH("Attempted to serialize to InfluxDB backend an invalid measurement (likely has no fields)") + if(timestamp_cache_worldtime != world.time) + update_timestamp() + serialized += " [timestamp_cache_realtime]" + send_queue += serialized + return TRUE + +/// Enqueues sending varied stats in a dumb and simpler format directly as: measurement count= +/datum/controller/subsystem/influxdriver/proc/enqueue_stats_crude(measurement, value, field_name = "count") + . = FALSE + var/serialized_field = serialize_field(field_name, value) + if(!length(serialized_field)) + return + if(timestamp_cache_worldtime != world.time) + update_timestamp() + var/serialized = "[measurement],round_id=[GLOB.round_id] [serialized_field] [timestamp_cache_realtime]" + send_queue += serialized + return TRUE + +/// Puts a single field or tag value into InfluxDB Line format +/datum/controller/subsystem/influxdriver/proc/serialize_field(field, value) + var/static/regex/whitelistedCharacters = regex(@{"([^a-zA-Z0-9_]+)"}, "g") + var/sanitized_field = whitelistedCharacters.Replace("[field]", "") + if(!length(sanitized_field) || copytext(sanitized_field, 1, 2) == "_") + CRASH("Invalid tag/field for InfluxDB serialization: '[sanitized_field]' (original: '[field]')") + var/sanitized_value + if(isnum(value)) + sanitized_value = value + else if(istext(value)) + sanitized_value = whitelistedCharacters.Replace("[value]", "") + if(!length(sanitized_value) || copytext(sanitized_value, 1, 2) == "_") + CRASH("Invalid value for InfluxDB serialization: '[sanitized_value]' (original: '[value]')") + else + CRASH("Invalid value type passed for InfluxDB serialization: '[value]'") + return "[sanitized_field]=[sanitized_value]" diff --git a/code/controllers/subsystem/influxmcstats.dm b/code/controllers/subsystem/influxmcstats.dm new file mode 100644 index 000000000000..a1bf171d81a3 --- /dev/null +++ b/code/controllers/subsystem/influxmcstats.dm @@ -0,0 +1,47 @@ +SUBSYSTEM_DEF(influxmcstats) + name = "InfluxDB MC Stats" + wait = 60 SECONDS + priority = SS_PRIORITY_INFLUXMCSTATS + init_order = SS_INIT_INFLUXMCSTATS + runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT + flags = SS_KEEP_TIMING + var/checkpoint = 0 + var/list/subsystem_name_cache = list() + +/datum/controller/subsystem/influxmcstats/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_mcstats_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 10 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxmcstats/stat_entry(msg) + msg += "period=[wait] checkpoint=[checkpoint]" + return ..() + +/datum/controller/subsystem/influxmcstats/fire(resumed) + if(!SSinfluxdriver.can_fire) + can_fire = FALSE + return + + var/list/data = list() + data["time_dilation_current"] = SStime_track.time_dilation_current + data["time_dilation_avg"] = SStime_track.time_dilation_avg + data["time_dilation_avg_slow"] = SStime_track.time_dilation_avg_slow + data["time_dilation_avg_fast"] = SStime_track.time_dilation_avg_fast + SSinfluxdriver.enqueue_stats("tidi", null, data) + + SSinfluxdriver.enqueue_stats("cpu", null, list("cpu" = world.cpu, "map_cpu" = world.map_cpu)) + + var/static/regex/get_last_path_element = regex(@{"/([^/]+)$"}) + checkpoint++ + for(var/datum/controller/subsystem/SS in Master.subsystems) + if(!SS.can_fire) + continue + if(!subsystem_name_cache[SS.type]) + get_last_path_element.Find("[SS.type]") + subsystem_name_cache[SS.type] = "SS[get_last_path_element.group[1]]" + var/SSname = subsystem_name_cache[SS.type] + if(!SSname) + stack_trace("Influx MC Stats couldnt name a subsystem, type=[SS.type]") + continue + SSinfluxdriver.enqueue_stats("sstimings", list("ss" = SSname), list("cost" = SS.cost, "tick_overrun" = SS.tick_overrun, "tick_usage" = SS.tick_usage, "wait" = SS.wait)) diff --git a/code/controllers/subsystem/influxstats.dm b/code/controllers/subsystem/influxstats.dm new file mode 100644 index 000000000000..01015b83191d --- /dev/null +++ b/code/controllers/subsystem/influxstats.dm @@ -0,0 +1,156 @@ +/// Sends generic round running statistics to the InfluxDB backend +SUBSYSTEM_DEF(influxstats) + name = "InfluxDB Game Stats" + wait = 60 SECONDS + priority = SS_PRIORITY_INFLUXSTATS + init_order = SS_INIT_INFLUXSTATS + runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT + flags = SS_KEEP_TIMING + + var/checkpoint = 0 //! Counter of data snapshots sent + var/step = 1 //! Current task in progress, for pausing/resuming + +/datum/controller/subsystem/influxstats/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_stats_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 10 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxstats/stat_entry(msg) + msg += "period=[wait] checkpoint=[checkpoint] step=[step]" + return ..() + +/datum/controller/subsystem/influxstats/fire(resumed) + if(!SSinfluxdriver.can_fire) + can_fire = FALSE + return + + checkpoint++ + while(step < 5) // Yes, you could make one SS per stats category, and have proper scheduling and variable periods, but... + switch(step++) + if(1) // Connected players statistics + run_player_statistics() + if(2) // Job occupations + if(SSticker.current_state == GAME_STATE_PLAYING) + run_job_statistics() + if(3) // Round-wide gameplay statistics held in entity + if(SSticker.current_state == GAME_STATE_PLAYING) + run_round_statistics() + if(4) // Handpicked Round-wide gameplay statistics + if(SSticker.current_state == GAME_STATE_PLAYING) + run_special_round_statistics() + if(MC_TICK_CHECK) + return + + step = 1 + +/datum/controller/subsystem/influxstats/proc/flatten_entity_list(list/data) + var/list/result = list() + for(var/key in data) + var/datum/entity/statistic/entry = data[key] + result[key] = entry.value + return result + +/datum/controller/subsystem/influxstats/proc/run_special_round_statistics() + for(var/hive_tag in GLOB.hive_datum) + var/datum/hive_status/hive = GLOB.hive_datum[hive_tag] + SSinfluxdriver.enqueue_stats("pooled_larva", list("hive" = hive.reporting_id), list("count" = hive.stored_larva)) + var/burst_larvas = GLOB.larva_burst_by_hive[hive] || 0 + SSinfluxdriver.enqueue_stats("burst_larva", list("hive" = hive.reporting_id), list("count" = burst_larvas)) + +/datum/controller/subsystem/influxstats/proc/run_round_statistics() + var/datum/entity/statistic/round/stats = SSticker?.mode?.round_stats + if(!stats) + return // Sadge + + SSinfluxdriver.enqueue_stats_crude("chestbursts", stats.total_larva_burst) + SSinfluxdriver.enqueue_stats_crude("hugged", stats.total_huggers_applied) + SSinfluxdriver.enqueue_stats_crude("friendlyfire", stats.total_friendly_fire_instances) + + var/list/participants = flatten_entity_list(stats.participants) + if(length(participants)) + SSinfluxdriver.enqueue_stats("participants", list(), participants) + + var/list/total_deaths = flatten_entity_list(stats.total_deaths) + if(length(total_deaths)) + SSinfluxdriver.enqueue_stats("deaths", list(), total_deaths) + + SSinfluxdriver.enqueue_stats("shots", list(), + list("fired" = stats.total_projectiles_fired, "hits" = stats.total_projectiles_hit, + "hits_human" = stats.total_projectiles_hit_human, "hits_xeno" = stats.total_projectiles_hit_xeno) + ) + +/datum/controller/subsystem/influxstats/proc/run_player_statistics() + var/staff_count = 0 + var/mentor_count = 0 + for(var/client/client in GLOB.admins) + if(CLIENT_IS_STAFF(client)) + staff_count++ + else if(CLIENT_HAS_RIGHTS(client, R_MENTOR)) + mentor_count++ + SSinfluxdriver.enqueue_stats("online", null, list("count" = length(GLOB.clients))) + + var/list/adm = get_admin_counts() + var/present_admins = length(adm["present"]) + var/afk_admins = length(adm["afk"]) + SSinfluxdriver.enqueue_stats("online_staff", null, list("total" = staff_count, "mentors" = mentor_count, "present" = present_admins, "afk" = afk_admins)) + + // Grab ahelp stats + SSinfluxdriver.enqueue_stats("tickets", null, list( + "open" = length(GLOB.ahelp_tickets.active_tickets), + "closed" = length(GLOB.ahelp_tickets.closed_tickets), + "resolved" = length(GLOB.ahelp_tickets.resolved_tickets), + )) + +/datum/controller/subsystem/influxstats/proc/run_job_statistics() + var/list/team_job_stats = list() + var/list/squad_job_stats = ROLES_SQUAD_ALL.Copy() + for(var/squad in squad_job_stats) + squad_job_stats[squad] = list() + + for(var/client/client in GLOB.clients) + var/team + var/mob/mob = client.mob + if(!mob || mob.statistic_exempt) + continue + var/area/area = get_area(mob) + if(!area || area.statistic_exempt) + continue + var/job = mob.job + if(isobserver(mob) || mob.stat == DEAD) + job = JOB_OBSERVER + team = "observers" + else if(!job) + continue + else if(mob.faction == FACTION_MARINE || mob.faction == FACTION_SURVIVOR) + team = "humans" + var/mob/living/carbon/human/employed_human = mob + if(istype(employed_human)) + var/squad = employed_human.assigned_squad?.name + if(squad in squad_job_stats) + squad_job_stats[squad][job] = (squad_job_stats[squad][job] || 0) + 1 + continue // Defer to squad stats instead + // else: So you're in the USCM and have a job but aren't an human? Tell me more Dr Jones... + else if(ishuman(mob)) + team = "humans_others" + else if(isxeno(mob)) + var/mob/living/xeno_enabled_mob = mob + var/datum/hive_status/hive = GLOB.hive_datum[xeno_enabled_mob.hivenumber] + if(!hive) + team = "xenos_others" + else + team = "xenos_[hive.reporting_id]" + else + team = "others" + LAZYINITLIST(team_job_stats[team]) + if(!team_job_stats[team][job]) + team_job_stats[team][job] = 0 + team_job_stats[team][job] += 1 + + for(var/team in team_job_stats) + for(var/job in team_job_stats[team]) + SSinfluxdriver.enqueue_stats("job_stats", list("team" = team, "job" = job), list("count" = team_job_stats[team][job])) + + for(var/squad in squad_job_stats) + for(var/job in squad_job_stats[squad]) + SSinfluxdriver.enqueue_stats("job_stats", list("team" = "humans", "job" = job, "squad" = squad), list("count" = squad_job_stats[squad][job])) diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index b05863b418b7..afecabd74be0 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -85,7 +85,7 @@ SUBSYSTEM_DEF(mapping) z_list = SSmapping.z_list #define INIT_ANNOUNCE(X) to_chat(world, "[X]"); log_world(X) -/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE) +/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE, override_map_path = "maps/") . = list() var/start_time = REALTIMEOFDAY @@ -96,7 +96,7 @@ SUBSYSTEM_DEF(mapping) var/total_z = 0 var/list/parsed_maps = list() for (var/file in files) - var/full_path = "maps/[path]/[file]" + var/full_path = "[override_map_path]/[path]/[file]" var/datum/parsed_map/pm = new(file(full_path)) var/bounds = pm?.bounds if (!bounds) @@ -123,19 +123,23 @@ SUBSYSTEM_DEF(mapping) ++i // load the maps - for (var/P in parsed_maps) - var/datum/parsed_map/pm = P - if (!pm.load(1, 1, start_z + parsed_maps[P], no_changeturf = TRUE)) + for (var/datum/parsed_map/pm as anything in parsed_maps) + var/cur_z = start_z + parsed_maps[pm] + if (!pm.load(1, 1, cur_z, no_changeturf = TRUE)) errorList |= pm.original_path + if(istype(z_list[cur_z], /datum/space_level)) + var/datum/space_level/cur_level = z_list[cur_z] + cur_level.x_bounds = pm.bounds[MAP_MAXX] + cur_level.y_bounds = pm.bounds[MAP_MAXY] if(!silent) INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!") return parsed_maps -/datum/controller/subsystem/mapping/proc/Loadship(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE) - LoadGroup(errorList, name, path, files, traits, default_traits, silent) +/datum/controller/subsystem/mapping/proc/Loadship(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE, override_map_path = "maps/") + LoadGroup(errorList, name, path, files, traits, default_traits, silent, override_map_path = override_map_path) -/datum/controller/subsystem/mapping/proc/Loadground(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE) - LoadGroup(errorList, name, path, files, traits, default_traits, silent) +/datum/controller/subsystem/mapping/proc/Loadground(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE, override_map_path = "maps/") + LoadGroup(errorList, name, path, files, traits, default_traits, silent, override_map_path = override_map_path) /datum/controller/subsystem/mapping/proc/loadWorld() //if any of these fail, something has gone horribly, HORRIBLY, wrong @@ -149,12 +153,18 @@ SUBSYSTEM_DEF(mapping) var/datum/map_config/ground_map = configs[GROUND_MAP] INIT_ANNOUNCE("Loading [ground_map.map_name]...") - Loadground(FailedZs, ground_map.map_name, ground_map.map_path, ground_map.map_file, ground_map.traits, ZTRAITS_GROUND) + var/ground_base_path = "maps/" + if(ground_map.override_map) + ground_base_path = "data/" + Loadground(FailedZs, ground_map.map_name, ground_map.map_path, ground_map.map_file, ground_map.traits, ZTRAITS_GROUND, override_map_path = ground_base_path) if(!ground_map.disable_ship_map) var/datum/map_config/ship_map = configs[SHIP_MAP] + var/ship_base_path = "maps/" + if(ship_map.override_map) + ship_base_path = "data/" INIT_ANNOUNCE("Loading [ship_map.map_name]...") - Loadship(FailedZs, ship_map.map_name, ship_map.map_path, ship_map.map_file, ship_map.traits, ZTRAITS_MAIN_SHIP) + Loadship(FailedZs, ship_map.map_name, ship_map.map_path, ship_map.map_file, ship_map.traits, ZTRAITS_MAIN_SHIP, override_map_path = ship_base_path) if(LAZYLEN(FailedZs)) //but seriously, unless the server's filesystem is messed up this will never happen var/msg = "RED ALERT! The following map files failed to load: [FailedZs[1]]" diff --git a/code/controllers/subsystem/minimap.dm b/code/controllers/subsystem/minimap.dm index 0a7e894c7516..b154c7673855 100644 --- a/code/controllers/subsystem/minimap.dm +++ b/code/controllers/subsystem/minimap.dm @@ -39,13 +39,13 @@ SUBSYSTEM_DEF(minimaps) var/list/minimap_added = list() /datum/controller/subsystem/minimaps/Initialize(start_timeofday) - for(var/level=1 to length(SSmapping.z_list)) + for(var/level in 1 to length(SSmapping.z_list)) minimaps_by_z["[level]"] = new /datum/hud_displays - if(!is_ground_level(level)) + if(!is_ground_level(level) && !is_mainship_level(level)) continue var/icon/icon_gen = new('icons/ui_icons/minimap.dmi') //480x480 blank icon template for drawing on the map - for(var/xval = 1 to world.maxx) - for(var/yval = 1 to world.maxy) //Scan all the turfs and draw as needed + for(var/xval in 1 to world.maxx) + for(var/yval in 1 to world.maxy) //Scan all the turfs and draw as needed var/turf/location = locate(xval,yval,level) if(istype(location, /turf/open/space)) continue @@ -97,7 +97,7 @@ SUBSYSTEM_DEF(minimaps) initialized = TRUE - for(var/i=1 to length(earlyadds)) //lateload icons + for(var/i in 1 to length(earlyadds)) //lateload icons earlyadds[i].Invoke() earlyadds = null //then clear them @@ -135,7 +135,10 @@ SUBSYSTEM_DEF(minimaps) depthcount++ continue for(var/datum/minimap_updator/updator as anything in update_targets[flag]) - updator.minimap.overlays += minimaps_by_z["[updator.ztarget]"].images_raw[flag] + if(length(updator.minimap.overlays)) + updator.minimap.overlays += minimaps_by_z["[updator.ztarget]"].images_raw[flag] + else + updator.minimap.overlays = minimaps_by_z["[updator.ztarget]"].images_raw[flag] depthcount++ iteration++ if(MC_TICK_CHECK) @@ -249,8 +252,8 @@ SUBSYSTEM_DEF(minimaps) minimaps_by_z["[zlevel]"].images_raw["[flag]"] += blip if(ismovableatom(target)) RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_z_change)) - RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) - removal_cbs[target] = CALLBACK(src, PROC_REF(removeimage), blip, target, zlevel) + blip.RegisterSignal(target, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/image, minimap_on_move)) + removal_cbs[target] = CALLBACK(src, PROC_REF(removeimage), blip, target) RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(remove_marker)) @@ -258,9 +261,14 @@ SUBSYSTEM_DEF(minimaps) /** * removes an image from raw tracked lists, invoked by callback */ -/datum/controller/subsystem/minimaps/proc/removeimage(image/blip, atom/target, zlevel) +/datum/controller/subsystem/minimaps/proc/removeimage(image/blip, atom/target) + var/turf/turf_gotten = get_turf(target) + if(!turf_gotten) + return + var/z_level = turf_gotten.z for(var/flag in GLOB.all_minimap_flags) - minimaps_by_z["[zlevel]"].images_raw["[flag]"] -= blip + minimaps_by_z["[z_level]"].images_raw["[flag]"] -= blip + blip.UnregisterSignal(target, COMSIG_MOVABLE_MOVED) removal_cbs -= target /** @@ -279,29 +287,30 @@ SUBSYSTEM_DEF(minimaps) minimaps_by_z["[oldz]"].images_assoc["[flag]"] -= source minimaps_by_z["[oldz]"].images_raw["[flag]"] -= ref_old - removal_cbs -= source - removal_cbs[source] = CALLBACK(src, PROC_REF(removeimage), ref_old, source, newz) - /** * Simple proc, updates overlay position on the map when a atom moves */ -/datum/controller/subsystem/minimaps/proc/on_move(atom/movable/source, oldloc) +/image/proc/minimap_on_move(atom/movable/source, oldloc) SIGNAL_HANDLER var/source_z = source.z if(!source_z) return - images_by_source[source].pixel_x = MINIMAP_PIXEL_FROM_WORLD(source.x) + minimaps_by_z["[source_z]"].x_offset - images_by_source[source].pixel_y = MINIMAP_PIXEL_FROM_WORLD(source.y) + minimaps_by_z["[source_z]"].y_offset + pixel_x = MINIMAP_PIXEL_FROM_WORLD(source.x) + SSminimaps.minimaps_by_z["[source_z]"].x_offset + pixel_y = MINIMAP_PIXEL_FROM_WORLD(source.y) + SSminimaps.minimaps_by_z["[source_z]"].y_offset /** - * Removes an atom and it's blip from the subsystem + * Removes an atom and it's blip from the subsystem. + * Force has no effect on this proc, but is here because we are a COMSIG_PARENT_QDELETING handler. */ -/datum/controller/subsystem/minimaps/proc/remove_marker(atom/source, minimap_flag) +/datum/controller/subsystem/minimaps/proc/remove_marker(atom/source, force, minimap_flag) SIGNAL_HANDLER if(!removal_cbs[source]) //already removed return - UnregisterSignal(source, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_Z_CHANGED)) + UnregisterSignal(source, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_Z_CHANGED)) + images_by_source -= source + removal_cbs[source].Invoke() + removal_cbs -= source var/turf/turf_gotten = get_turf(source) if(!turf_gotten) return @@ -311,10 +320,6 @@ SUBSYSTEM_DEF(minimaps) else for(var/flag in GLOB.all_minimap_flags) minimaps_by_z["[z_level]"].images_assoc["[flag]"] -= source - images_by_source -= source - removal_cbs[source].Invoke() - removal_cbs -= source - /** * Fetches a /atom/movable/screen/minimap instance or creates on if none exists @@ -390,18 +395,24 @@ SUBSYSTEM_DEF(minimaps) owner.client.screen += map minimap_displayed = !minimap_displayed -/datum/action/minimap/give_to(mob/M) +/datum/action/minimap/give_to(mob/target) . = ..() if(default_overwatch_level) map = SSminimaps.fetch_minimap_object(default_overwatch_level, minimap_flags) else - RegisterSignal(M, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_owner_z_change)) - if(!SSminimaps.minimaps_by_z["[M.z]"] || !SSminimaps.minimaps_by_z["[M.z]"].hud_image) + RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_owner_z_change)) + + var/turf/turf_gotten = get_turf(target) + if(!turf_gotten) + return + var/z_level = turf_gotten.z + + if(!SSminimaps.minimaps_by_z["[z_level]"] || !SSminimaps.minimaps_by_z["[z_level]"].hud_image) return - map = SSminimaps.fetch_minimap_object(M.z, minimap_flags) + map = SSminimaps.fetch_minimap_object(z_level, minimap_flags) -/datum/action/minimap/remove_from(mob/M) +/datum/action/minimap/remove_from(mob/target) . = ..() if(minimap_displayed) owner?.client?.screen -= map @@ -437,8 +448,8 @@ SUBSYSTEM_DEF(minimaps) /datum/tacmap var/allowed_flags = MINIMAP_FLAG_USCM - ///by default Zlevel 3, groundside is targeted - var/targeted_zlevel = 3 + /// by default the ground map - this picks the first level matching the trait. if it exists + var/targeted_ztrait = ZTRAIT_GROUND var/atom/owner var/datum/tacmap_holder/map_holder @@ -454,7 +465,10 @@ SUBSYSTEM_DEF(minimaps) /datum/tacmap/tgui_interact(mob/user, datum/tgui/ui) if(!map_holder) - map_holder = SSminimaps.fetch_tacmap_datum(targeted_zlevel, allowed_flags) + var/level = SSmapping.levels_by_trait(targeted_ztrait) + if(!level[1]) + return + map_holder = SSminimaps.fetch_tacmap_datum(level[1], allowed_flags) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -479,6 +493,16 @@ SUBSYSTEM_DEF(minimaps) else return UI_CLOSE +/datum/tacmap/xeno/ui_status(mob/user) + if(!isxeno(user)) + return UI_CLOSE + + var/mob/living/carbon/xenomorph/xeno = user + if(!xeno.hive?.living_xeno_queen?.ovipositor) + return UI_CLOSE + + return UI_INTERACTIVE + /datum/tacmap_holder var/map_ref var/atom/movable/screen/minimap/map diff --git a/code/controllers/subsystem/nightmare.dm b/code/controllers/subsystem/nightmare.dm index fd0828329388..e963653b54a0 100644 --- a/code/controllers/subsystem/nightmare.dm +++ b/code/controllers/subsystem/nightmare.dm @@ -42,6 +42,9 @@ SUBSYSTEM_DEF(nightmare) // this is the only way i've found to make this work, other than going // full cooperative scheduling with the tasks / a ticking SS + if(!initialized) + message_admins("Nightmare subsystem is performing prepare_game prior to initialization! No nightmare inserts will be loaded.") + if(stat == NIGHTMARE_STATUS_DONE) return TRUE if(stat == NIGHTMARE_STATUS_RUNNING) diff --git a/code/controllers/subsystem/perf_logging.dm b/code/controllers/subsystem/perf_logging.dm index 6e0fbed6d1f5..5ca98ad10dd0 100644 --- a/code/controllers/subsystem/perf_logging.dm +++ b/code/controllers/subsystem/perf_logging.dm @@ -42,9 +42,8 @@ SUBSYSTEM_DEF(perf_logging) var/datum/map_config/ground = SSmapping.configs[GROUND_MAP] if(!ground) return ord = 0 - round = SSentity_manager.select(/datum/entity/mc_round) + round = SSentity_manager.round round.map_name = ground.map_name - round.save() var/datum/entity/mc_controller/C for(var/datum/controller/subsystem/SS in Master.subsystems) C = SSentity_manager.select_by_key(/datum/entity/mc_controller, "[SS.type]") diff --git a/code/controllers/subsystem/reagents.dm b/code/controllers/subsystem/reagents.dm new file mode 100644 index 000000000000..5a310801b191 --- /dev/null +++ b/code/controllers/subsystem/reagents.dm @@ -0,0 +1,73 @@ +SUBSYSTEM_DEF(reagents) + name = "Reagents" + init_order = SS_INIT_REAGENTS + flags = SS_NO_FIRE + +/datum/controller/subsystem/reagents/Initialize() + // Initalize to create the global chemistry lists: + // Must be before SSatoms.InitializeAtoms and SSmapping + prepare_properties() + prepare_reagents() + + return SS_INIT_SUCCESS + +/datum/controller/subsystem/reagents/Recover() + initialized = SSreagents.initialized + +/datum/controller/subsystem/reagents/proc/prepare_properties() + //Chemical Properties - Initialises all /datum/chem_property into a list indexed by property name + var/paths = typesof(/datum/chem_property) + chemical_properties_list = list() + //Some filters + chemical_properties_list["negative"] = list() + chemical_properties_list["neutral"] = list() + chemical_properties_list["positive"] = list() + chemical_properties_list["rare"] = list() + //Save + for(var/path in paths) + var/datum/chem_property/prop = new path() + if(!prop.name) + continue + chemical_properties_list[prop.name] = prop + if(prop.starter) + //Add a separate instance to the chemical property database + var/datum/chem_property/chem = new path() + chem.level = 0 + chemical_data.research_property_data += chem + if(prop.rarity > PROPERTY_DISABLED) + //Filters for the generator picking properties + if(prop.rarity == PROPERTY_RARE || prop.rarity == PROPERTY_LEGENDARY) + chemical_properties_list["rare"][prop.name] = prop + else if(isNegativeProperty(prop)) + chemical_properties_list["negative"][prop.name] = prop + else if(isNeutralProperty(prop)) + chemical_properties_list["neutral"][prop.name] = prop + else if(isPositiveProperty(prop)) + chemical_properties_list["positive"][prop.name] = prop + +/datum/controller/subsystem/reagents/proc/prepare_reagents() + //I dislike having these here but map-objects are initialised before world/New() is called. >_> + set waitfor = FALSE + //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id + //Generated chemicals should be initialized last, hence the substract then readd. + var/list/paths = subtypesof(/datum/reagent) - typesof(/datum/reagent/generated) - subtypesof(/datum/reagent/generated) + subtypesof(/datum/reagent/generated) + chemical_reagents_list = list() + for(var/path in paths) + var/datum/reagent/chem = new path() + chem.save_chemclass() + chemical_reagents_list[chem.id] = chem + + //Chemical Reactions - Initialises all /datum/chemical_reaction into a list + // It is filtered into multiple lists within a list. + // For example: + // chemical_reaction_list["phoron"] is a list of all reactions relating to phoron + var/list/regular_paths = subtypesof(/datum/chemical_reaction) - typesof(/datum/chemical_reaction/generated) + var/list/generated_paths = subtypesof(/datum/chemical_reaction/generated) //Generated chemicals should be initialized last + chemical_reactions_filtered_list = list() + chemical_reactions_list = list() + + for(paths in list(regular_paths, generated_paths)) + for(var/path in paths) + var/datum/chemical_reaction/react = new path() + chemical_reactions_list[react.id] = react + react.add_to_filtered_list() diff --git a/code/controllers/subsystem/redis.dm b/code/controllers/subsystem/redis.dm new file mode 100644 index 000000000000..bb151c2823c4 --- /dev/null +++ b/code/controllers/subsystem/redis.dm @@ -0,0 +1,147 @@ +SUBSYSTEM_DEF(redis) + name = "Redis" + init_order = SS_INIT_REDIS + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + wait = 1 + flags = SS_TICKER + + /// if a connection to redis has been established + var/connected = FALSE + + /// subscribed to channels on the redis server + var/list/subbed_channels = list() + + /// message queue, for messages sent prior to initialization + var/list/datum/redis_message/queue = list() + + /// the name this server uses externally + var/instance_name = "game" + /// if this server is sending logs to redis, in addition to the file system + var/redis_logging = FALSE + +/datum/controller/subsystem/redis/stat_entry(msg) + msg = "S:[length(subbed_channels)] | Q:[length(queue)] | C:[connected ? "Y" : "N"]" + return ..() + +/datum/controller/subsystem/redis/Initialize() + instance_name = CONFIG_GET(string/instance_name) + redis_logging = CONFIG_GET(flag/redis_logging) + + if(connect() == CONFIG_DISABLED) + can_fire = FALSE + return SS_INIT_SUCCESS + + if(!connected) + return SS_INIT_FAILURE + + + for(var/datum/redis_message/message as anything in queue) + publish(message.channel, message.message) + queue -= message + + for(var/callback in subtypesof(/datum/redis_callback)) + var/datum/redis_callback/redis_cb = new callback() + + if(isnull(redis_cb.channel)) + stack_trace("[redis_cb.type] has no channel set!") + continue + + if(redis_cb.channel in subbed_channels) + stack_trace("Attempted to subscribe to the channel '[redis_cb.channel]' from [redis_cb.type] twice!") + + rustg_redis_subscribe(redis_cb.channel) + subbed_channels[redis_cb.channel] = redis_cb + + log_debug("Registered [length(subbed_channels)] callback(s).") + + return SS_INIT_SUCCESS + +/datum/controller/subsystem/redis/fire() + if(!connected) + can_fire = FALSE + return + + check_messages() + + for(var/datum/redis_message/message as anything in queue) + publish(message.channel, message.message) + queue -= message + +/datum/controller/subsystem/redis/Shutdown() + if(!connected) + return + disconnect(SHUTDOWN) + +/datum/controller/subsystem/redis/proc/connect() + if(!CONFIG_GET(flag/redis_enabled)) + return CONFIG_DISABLED + + var/connection_attempt = rustg_redis_connect(CONFIG_GET(string/redis_connection)) + + if(connection_attempt) + message_admins("Failed to connect to redis: [connection_attempt]") + return + + var/list/data = list("source" = SSredis.instance_name, "type" = "connect") + publish("byond.meta", json_encode(data)) + + connected = TRUE + can_fire = TRUE + +/datum/controller/subsystem/redis/proc/disconnect(reason) + message_admins("Note: Redis connection interrupted.") + var/list/data = list("source" = SSredis.instance_name, "type" = "disconnect", "reason" = reason) + publish("byond.meta", json_encode(data)) + rustg_redis_disconnect() + connected = FALSE + +/datum/controller/subsystem/redis/proc/reconnect() + connect() + + if(!connected) + return + + for(var/channel in subbed_channels) + rustg_redis_subscribe(channel) + +/datum/controller/subsystem/redis/proc/check_messages() + var/raw_data = rustg_redis_get_messages() + var/list/usable_data + + try + usable_data = json_decode(raw_data) + catch + message_admins("Failed to deserialise a redis message.") + log_debug("Failed to deserialise: [raw_data]") + return + + for(var/channel in usable_data) + if(channel == RUSTG_REDIS_ERROR_CHANNEL) + message_admins("Redis error: [json_encode(usable_data[channel])]") + continue + + if(!(channel in subbed_channels)) + stack_trace("Received a message on a non-subscribed channel.") + continue + + var/datum/redis_callback/redis_cb = subbed_channels[channel] + + for(var/message in usable_data[channel]) + redis_cb.on_message(message) + +/datum/controller/subsystem/redis/proc/publish(channel, message) + if(!connected) + var/datum/redis_message/redis = new() + redis.channel = channel + redis.message = message + + queue += redis + return + + rustg_redis_publish(channel, message) + +/datum/controller/subsystem/redis/CanProcCall(procname) + return FALSE + +/datum/controller/subsystem/redis/vv_edit_var(var_name, var_value) + return FALSE diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 3498258cfbae..9a94eb3371f9 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -29,7 +29,7 @@ SUBSYSTEM_DEF(statpanels) global_data = list( "Map: [SSmapping.configs?[GROUND_MAP]?.map_name || "Loading..."]", cached ? "Next Map: [cached?.map_name]" : null, -// "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]", // this is commented because we don't have it and we should have it instead of using debug DB - be the hero of today + "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]", // "Round Time: [ROUND_TIME]", "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]", "Round Time: [duration2text()]", diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 3062f10bff90..0e23b99a9cc2 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -99,6 +99,7 @@ SUBSYSTEM_DEF(ticker) current_state = GAME_STATE_FINISHED ooc_allowed = TRUE mode.declare_completion(force_ending) + REDIS_PUBLISH("byond.round", "type" = "round-complete") flash_clients() if(text2num(SSperf_logging?.round?.id) % CONFIG_GET(number/gamemode_rounds_needed) == 0) addtimer(CALLBACK( @@ -134,6 +135,8 @@ SUBSYSTEM_DEF(ticker) current_state = GAME_STATE_SETTING_UP INVOKE_ASYNC(src, PROC_REF(setup_start)) + REDIS_PUBLISH("byond.round", "type" = "round-start") + for(var/client/C in GLOB.admins) remove_verb(C, roundstart_mod_verbs) admin_verbs_minor_event -= roundstart_mod_verbs @@ -400,7 +403,7 @@ SUBSYSTEM_DEF(ticker) if(M.client) var/client/C = M.client if(C.player_data && C.player_data.playtime_loaded && length(C.player_data.playtimes) == 0) - msg_admin_niche("NEW PLAYER: [key_name(player, 1, 1, 0)] (?). IP: [player.lastKnownIP], CID: [player.computer_id]") + msg_admin_niche("NEW PLAYER: [key_name(player, 1, 1, 0)]. IP: [player.lastKnownIP], CID: [player.computer_id]") QDEL_IN(player, 5) /datum/controller/subsystem/ticker/proc/old_create_characters() @@ -421,7 +424,7 @@ SUBSYSTEM_DEF(ticker) for(var/mob/living/carbon/human/player in GLOB.human_mob_list) if(player.mind) - if(player.job == "Commanding Officers") + if(player.job == JOB_CO) captainless = FALSE if(player.job) RoleAuthority.equip_role(player, RoleAuthority.roles_by_name[player.job], late_join = FALSE) @@ -429,7 +432,7 @@ SUBSYSTEM_DEF(ticker) if(player.client) var/client/C = player.client if(C.player_data && C.player_data.playtime_loaded && length(C.player_data.playtimes) == 0) - msg_admin_niche("NEW PLAYER: [key_name(player, 1, 1, 0)] (?). IP: [player.lastKnownIP], CID: [player.computer_id]") + msg_admin_niche("NEW PLAYER: [key_name(player, 1, 1, 0)]. IP: [player.lastKnownIP], CID: [player.computer_id]") if(C.player_data && C.player_data.playtime_loaded && ((round(C.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1)) <= 5)) msg_sea(("NEW PLAYER: [key_name(player, 0, 1, 0)] only has [(round(C.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1))] hours as a human. Current role: [get_actual_job_name(player)] - Current location: [get_area(player)]"), TRUE) if(captainless) diff --git a/code/controllers/subsystem/time_track.dm b/code/controllers/subsystem/time_track.dm new file mode 100644 index 000000000000..a01c4a68755f --- /dev/null +++ b/code/controllers/subsystem/time_track.dm @@ -0,0 +1,125 @@ +SUBSYSTEM_DEF(time_track) + name = "Time Tracking" + wait = 100 + init_order = SS_INIT_TIMETRACK + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + + var/time_dilation_current = 0 + + var/time_dilation_avg_fast = 0 + var/time_dilation_avg = 0 + var/time_dilation_avg_slow = 0 + + var/first_run = TRUE + + var/last_tick_realtime = 0 + var/last_tick_byond_time = 0 + var/last_tick_tickcount = 0 + var/list/sendmaps_names_map = list( + "SendMaps" = "send_maps", + "SendMaps: Initial housekeeping" = "initial_house", + "SendMaps: Cleanup" = "cleanup", + "SendMaps: Client loop" = "client_loop", + "SendMaps: Per client" = "per_client", + "SendMaps: Per client: Deleted images" = "deleted_images", + "SendMaps: Per client: HUD update" = "hud_update", + "SendMaps: Per client: Statpanel update" = "statpanel_update", + "SendMaps: Per client: Map data" = "map_data", + "SendMaps: Per client: Map data: Check eye position" = "check_eye_pos", + "SendMaps: Per client: Map data: Update chunks" = "update_chunks", + "SendMaps: Per client: Map data: Send turfmap updates" = "turfmap_updates", + "SendMaps: Per client: Map data: Send changed turfs" = "changed_turfs", + "SendMaps: Per client: Map data: Send turf chunk info" = "turf_chunk_info", + "SendMaps: Per client: Map data: Send obj changes" = "obj_changes", + "SendMaps: Per client: Map data: Send mob changes" = "mob_changes", + "SendMaps: Per client: Map data: Send notable turf visual contents" = "send_turf_vis_conts", + "SendMaps: Per client: Map data: Send pending animations" = "pending_animations", + "SendMaps: Per client: Map data: Look for movable changes" = "look_for_movable_changes", + "SendMaps: Per client: Map data: Look for movable changes: Check notable turf visual contents" = "check_turf_vis_conts", + "SendMaps: Per client: Map data: Look for movable changes: Check HUD/image visual contents" = "check_hud/image_vis_contents", + "SendMaps: Per client: Map data: Look for movable changes: Loop through turfs in range" = "turfs_in_range", + "SendMaps: Per client: Map data: Look for movable changes: Movables examined" = "movables_examined", + ) + +/datum/controller/subsystem/time_track/Initialize() + GLOB.perf_log = "[GLOB.log_directory]/perf-[GLOB.round_id ? GLOB.round_id : "NULL"]-[SSmapping.configs[GROUND_MAP]?.map_name].csv" + world.Profile(PROFILE_RESTART, type = "sendmaps") + //Need to do the sendmaps stuff in its own file, since it works different then everything else + var/list/sendmaps_headers = list() + for(var/proper_name in sendmaps_names_map) + sendmaps_headers += sendmaps_names_map[proper_name] + sendmaps_headers += "[sendmaps_names_map[proper_name]]_count" + + log_perf( + list( + "time", + "players", + "tidi", + "tidi_fastavg", + "tidi_avg", + "tidi_slowavg", + "maptick", + "num_timers", + "in_progress", + "in_callback", + ) + sendmaps_headers + ) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/time_track/fire() + + var/current_realtime = REALTIMEOFDAY + var/current_byondtime = world.time + var/current_tickcount = world.time/world.tick_lag + + if (!first_run) + var/tick_drift = max(0, (((current_realtime - last_tick_realtime) - (current_byondtime - last_tick_byond_time)) / world.tick_lag)) + + time_dilation_current = tick_drift / (current_tickcount - last_tick_tickcount) * 100 + + time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current) + time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast) + time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg) + else + first_run = FALSE + last_tick_realtime = current_realtime + last_tick_byond_time = current_byondtime + last_tick_tickcount = current_tickcount + + var/sendmaps_json = world.Profile(PROFILE_REFRESH, type = "sendmaps", format="json") + var/list/send_maps_data = null + try + send_maps_data = json_decode(sendmaps_json) + catch + text2file(sendmaps_json,"bad_sendmaps.json") + can_fire = FALSE + return + var/send_maps_sort = send_maps_data.Copy() //Doing it like this guarentees us a properly sorted list + + for(var/list/packet in send_maps_data) + send_maps_sort[packet["name"]] = packet + + var/list/send_maps_values = list() + for(var/entry_name in sendmaps_names_map) + var/list/packet = send_maps_sort[entry_name] + if(!packet) //If the entry does not have a value for us, just put in 0 for both + send_maps_values += 0 + send_maps_values += 0 + continue + send_maps_values += packet["value"] + send_maps_values += packet["calls"] + + log_perf( + list( + world.time, + length(GLOB.clients), + time_dilation_current, + time_dilation_avg_fast, + time_dilation_avg, + time_dilation_avg_slow, + MAPTICK_LAST_INTERNAL_TICK_USAGE, + length(SStimer.timer_id_dict), + SSdatabase.in_progress, + SSdatabase.in_callback, + ) + send_maps_values + ) diff --git a/code/controllers/subsystem/x_evolution.dm b/code/controllers/subsystem/x_evolution.dm index 9f84513e9e2d..be787b37de80 100644 --- a/code/controllers/subsystem/x_evolution.dm +++ b/code/controllers/subsystem/x_evolution.dm @@ -3,7 +3,7 @@ #define EVOLUTION_INCREMENT_TIME (30 MINUTES) // Evolution increases by 1 every 25 minutes. SUBSYSTEM_DEF(xevolution) - name = "Evilution" + name = "Evilution" //This is not a typo, do not change it. wait = 1 MINUTES priority = SS_PRIORITY_INACTIVITY diff --git a/code/controllers/topic.dm b/code/controllers/topic.dm new file mode 100644 index 000000000000..6f98241e73bc --- /dev/null +++ b/code/controllers/topic.dm @@ -0,0 +1,31 @@ +SUBSYSTEM_DEF(topic) + name = "Topic" + init_order = SS_INIT_TOPIC + flags = SS_NO_FIRE + +/datum/controller/subsystem/topic/Initialize(timeofday) + // Initialize topic datums + var/list/anonymous_functions = list() + for(var/path in subtypesof(/datum/world_topic)) + var/datum/world_topic/T = new path() + if(T.anonymous) + anonymous_functions[T.key] = TRUE + GLOB.topic_commands[T.key] = T + + // Setup the anonymous access token + GLOB.topic_tokens["anonymous"] = anonymous_functions + // Parse and setup authed tokens from config + var/list/tokens = CONFIG_GET(keyed_list/topic_tokens) + for(var/token in tokens) + var/list/keys = list() + if(tokens[token] == "all") + for(var/key in GLOB.topic_commands) + keys[key] = TRUE + else + for(var/key in splittext(tokens[token], ",")) + keys[trim(key)] = TRUE + // Grant access to anonymous topic calls (version, authed functions etc.) by default + keys |= anonymous_functions + GLOB.topic_tokens[token] = keys + + return SS_INIT_SUCCESS diff --git a/code/datums/ASRS.dm b/code/datums/ASRS.dm index 2ddb9d3133c0..86a7363f07ea 100644 --- a/code/datums/ASRS.dm +++ b/code/datums/ASRS.dm @@ -54,12 +54,12 @@ buyable = 0 group = "ASRS" -/datum/supply_packs/ammo_l42_mag_box/asrs +/datum/supply_packs/ammo_m4ra_mag_box/asrs buyable = 0 group = "ASRS" cost = ASRS_VERY_LOW_WEIGHT -/datum/supply_packs/ammo_l42_mag_box_ap/asrs +/datum/supply_packs/ammo_m4ra_mag_box_ap/asrs buyable = 0 group = "ASRS" diff --git a/code/datums/_ndatabase/code/brsql_connection_settings.dm b/code/datums/_ndatabase/code/brsql_connection_settings.dm index ae42dd3b704b..7f003612a94a 100644 --- a/code/datums/_ndatabase/code/brsql_connection_settings.dm +++ b/code/datums/_ndatabase/code/brsql_connection_settings.dm @@ -30,13 +30,14 @@ /datum/db/connection_settings/brsql/New(list/config) ..() - ipaddress = config["db_address"] - port = text2num(config["db_port"]) - username = config["db_username"] - password = config["db_password"] - db = config["db_database"] - min_threads = text2num(config["db_min_threads"] || "1") - max_threads = text2num(config["db_max_threads"] || "100") + + ipaddress = CONFIG_GET(string/db_address) + port = CONFIG_GET(number/db_port) + username = CONFIG_GET(string/db_username) + password = CONFIG_GET(string/db_password) + db = CONFIG_GET(string/db_database) + min_threads = CONFIG_GET(number/db_min_threads) + max_threads = CONFIG_GET(number/db_max_threads) /datum/db/connection_settings/brsql/create_connection() var/datum/db/connection/brsql_connection/connection = new() diff --git a/code/datums/_ndatabase/code/interfaces/connection_settings.dm b/code/datums/_ndatabase/code/interfaces/connection_settings.dm index a4fc0fa1dc19..4092ee712ba9 100644 --- a/code/datums/_ndatabase/code/interfaces/connection_settings.dm +++ b/code/datums/_ndatabase/code/interfaces/connection_settings.dm @@ -23,13 +23,13 @@ var/debug_mode /datum/db/connection_settings/New(list/config) - debug_mode = !!config["db_debug_mode"] + debug_mode = CONFIG_GET(flag/db_debug_mode) /datum/db/connection_settings/proc/create_connection() return null -/proc/connection_settings_from_config(list/config) - var/typestr = text2path("/datum/db/connection_settings/"+config["db_provider"]) +/proc/connection_settings_from_config(config) + var/typestr = text2path("/datum/db/connection_settings/" + config) if(!typestr) typestr = /datum/db/connection_settings/native return new typestr(config) diff --git a/code/datums/_ndatabase/code/interfaces/filter.dm b/code/datums/_ndatabase/code/interfaces/filter.dm index 958f783dacf3..10a182869788 100644 --- a/code/datums/_ndatabase/code/interfaces/filter.dm +++ b/code/datums/_ndatabase/code/interfaces/filter.dm @@ -99,8 +99,3 @@ /datum/db/filter/link/get_columns() CRASH("NOT SUPPORTED. USE compare_two EQUALS") - -#define DB_AND new /datum/db/filter/and -#define DB_OR new /datum/db/filter/or -#define DB_COMP new /datum/db/filter/comparison -#define DB_COMP2 new /datum/db/filter/compare_two diff --git a/code/datums/_ndatabase/code/native_connection_settings.dm b/code/datums/_ndatabase/code/native_connection_settings.dm index fe29f81cc997..64675e83e69d 100644 --- a/code/datums/_ndatabase/code/native_connection_settings.dm +++ b/code/datums/_ndatabase/code/native_connection_settings.dm @@ -24,7 +24,8 @@ /datum/db/connection_settings/native/New(list/config) ..() - filename = config["db_filename"] + + filename = CONFIG_GET(string/db_filename) /datum/db/connection_settings/native/create_connection() var/datum/db/connection/native/connection = new() diff --git a/code/datums/_ndatabase/subsystems/database_query_manager.dm b/code/datums/_ndatabase/subsystems/database_query_manager.dm index 7de34325711b..7eef5842e2dd 100644 --- a/code/datums/_ndatabase/subsystems/database_query_manager.dm +++ b/code/datums/_ndatabase/subsystems/database_query_manager.dm @@ -27,7 +27,7 @@ var/datum/controller/subsystem/database_query_manager/SSdatabase init_order = SS_INIT_DATABASE init_stage = INITSTAGE_EARLY priority = SS_PRIORITY_DATABASE // Low prio SS_TICKER - flags = SS_TICKER + flags = SS_TICKER|SS_NO_INIT var/datum/db/connection/connection var/datum/db/connection_settings/settings @@ -52,15 +52,14 @@ var/datum/controller/subsystem/database_query_manager/SSdatabase queries_active = list() queries_current = list() queries_standby = list() - var/list/result = loadsql("config/dbconfig.txt") - settings = connection_settings_from_config(result) NEW_SS_GLOBAL(SSdatabase) -/datum/controller/subsystem/database_query_manager/Initialize() - set waitfor=0 +/datum/controller/subsystem/database_query_manager/proc/start_up() + set waitfor = FALSE + + settings = connection_settings_from_config(CONFIG_GET(string/db_provider)) connection = settings.create_connection() connection.keep() - return SS_INIT_SUCCESS /datum/controller/subsystem/database_query_manager/stat_entry(msg) var/text = (connection && connection.status == DB_CONNECTION_READY) ? ("READY") : ("PREPPING") diff --git a/code/datums/_ndatabase/subsystems/entity_manager.dm b/code/datums/_ndatabase/subsystems/entity_manager.dm index c7e0a97941c0..667f2a855563 100644 --- a/code/datums/_ndatabase/subsystems/entity_manager.dm +++ b/code/datums/_ndatabase/subsystems/entity_manager.dm @@ -27,6 +27,8 @@ var/datum/controller/subsystem/entity_manager/SSentity_manager init_stage = INITSTAGE_EARLY priority = SS_PRIORITY_ENTITY runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY + flags = SS_NO_INIT + var/datum/db/adapter/adapter var/list/datum/entity_meta/tables var/list/datum/entity_meta/tables_unsorted @@ -35,6 +37,8 @@ var/datum/controller/subsystem/entity_manager/SSentity_manager var/list/datum/entity_meta/currentrun + var/datum/entity/mc_round/round + var/ready = FALSE /datum/controller/subsystem/entity_manager/New() @@ -64,7 +68,7 @@ var/datum/controller/subsystem/entity_manager/SSentity_manager NEW_SS_GLOBAL(SSentity_manager) -/datum/controller/subsystem/entity_manager/Initialize() +/datum/controller/subsystem/entity_manager/proc/start_up() set waitfor=0 UNTIL(SSdatabase.connection.connection_ready()) adapter = SSdatabase.connection.get_adapter() @@ -80,7 +84,6 @@ var/datum/controller/subsystem/entity_manager/SSentity_manager adapter.prepare_view(view) ready = TRUE - return SS_INIT_SUCCESS /datum/controller/subsystem/entity_manager/proc/prepare_tables() adapter.sync_table_meta() @@ -289,3 +292,9 @@ var/datum/controller/subsystem/entity_manager/SSentity_manager var/V = new meta.destination_entity() meta.map(V, r) to_write.Add(V) + +/datum/controller/subsystem/entity_manager/proc/setup_round_id() + round = SSentity_manager.select(/datum/entity/mc_round) + round.save() + round.sync_then(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(start_logging))) + diff --git a/code/datums/agents/tools.dm b/code/datums/agents/tools.dm index 787784729b52..be753f30abce 100644 --- a/code/datums/agents/tools.dm +++ b/code/datums/agents/tools.dm @@ -7,28 +7,28 @@ req_access = list() req_role = null listed_products = list( - list("

WEAPONS

", -1, null, null, null), + list("WEAPONS", 0, null, null, null), list("Configured Stunbaton", 25, /obj/item/weapon/baton/antag, "white", "A stun baton with more charge, tuned to work only for agents."), list("Tranquilizer Gun", 25, /obj/item/weapon/gun/pistol/tranquilizer, "white", "A tranquilizer gun. Comes with 5 darts. Deals no damage, knockout guaranteed."), list("Chloroform Cloth", 18, /obj/item/weapon/chloroform, "white", "A cloth dosed with chloroform. Has 8 effective uses and can only be used whilst behind a target. You must be in disarm intent to use."), - list("

ONE-USE TOOLS

", -1, null, null, null), + list("ONE-USE TOOLS", 0, null, null, null), list("Experimental Stimulant Pills", 20, /obj/item/storage/pill_bottle/ultrazine/antag, "white", "Useful stimulants that allow you to resist stamina damage. Lasts for approximately 2 minutes. Take only 1 pill. Use with care."), list("Decoy", 14, /obj/item/explosive/grenade/decoy, "white", "A decoy grenade. Emits a loud explosion that can be heard from very far away, keep away from ears. Can be used 3 times."), - list("

UTILITY

", -1, null, null, null), + list("UTILITY", 0, null, null, null), list("Security Access Tuner v2", 25, /obj/item/device/multitool/antag, "white", "An upgraded access tuner, able to rapidly hack various machinery. Disguised as a regular multitool"), list("OoI Tracker", 20, /obj/item/device/tracker, "white", "A tracker that tracks different objects of interest in a nearby range."), - list("

KITS

", -1, null, null, null), + list("KITS", 0, null, null, null), list("Badass Kit", 12, /obj/item/storage/box/badass_kit, "white", "Contains MP private comms encryption key, for snooping into enemy communications and sunglasses that protect you from flashbangs"), list("Tools Kit", 15, /obj/item/storage/toolbox/antag, "white", "A toolbox containing general tools and an engineering pamphlet to help you break into places of interest."), list("Hacking Kit", 15, /obj/item/storage/box/antag_signaller, "white", "A box containing a screwdriver, a multi-tool and an engineering pamphlet, as well as 5 signallers to help you hack doors."), - list("

TRANSFER POINTS

", -1, null, null, "A method of transferring points between agents."), - list("1 point", 1, /obj/item/stack/points/p1, "white", null), - list("5 points", 5, /obj/item/stack/points/p5, "white", null), - list("20 points", 20, /obj/item/stack/points/p20, "white", null), + list("TRANSFER POINTS", 0, null, null, null), + list("1 point", 1, /obj/item/stack/points/p1, "white", "A method of transferring points between agents."), + list("5 points", 5, /obj/item/stack/points/p5, "white", "A method of transferring points between agents."), + list("20 points", 20, /obj/item/stack/points/p20, "white", "A method of transferring points between agents."), ) points = 40 diff --git a/code/datums/agents/tools/stimulants.dm b/code/datums/agents/tools/stimulants.dm index f4cd9c40f9ba..ff177a1310d2 100644 --- a/code/datums/agents/tools/stimulants.dm +++ b/code/datums/agents/tools/stimulants.dm @@ -6,7 +6,6 @@ pill_type_to_fill = /obj/item/reagent_container/pill/stimulant req_access = null - req_role = null /obj/item/storage/pill_bottle/ultrazine/antag/id_check(mob/user) if(!skillcheckexplicit(user, SKILL_ANTAG, SKILL_ANTAG_AGENT)) diff --git a/code/datums/agents/tools/tranq_gun.dm b/code/datums/agents/tools/tranq_gun.dm index e812aa57037e..e95f853cef82 100644 --- a/code/datums/agents/tools/tranq_gun.dm +++ b/code/datums/agents/tools/tranq_gun.dm @@ -6,11 +6,10 @@ item_state = "pk9r" current_mag = /obj/item/ammo_magazine/pistol/tranq - burst_amount = 1 /obj/item/weapon/gun/pistol/tranquilizer/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 + set_fire_delay(FIRE_DELAY_TIER_6) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_7 accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_10 diff --git a/code/datums/autocells/explosion.dm b/code/datums/autocells/explosion.dm index 4a367497bd95..42e1409d595f 100644 --- a/code/datums/autocells/explosion.dm +++ b/code/datums/autocells/explosion.dm @@ -322,7 +322,7 @@ as having entered the turf. M.attack_log += "\[[time_stamp()]\] [key_name(firing_mob)] blew up [key_name(M)] with \a [explosion_source] in [get_area(T)]." firing_mob.attack_log += "\[[time_stamp()]\] [key_name(firing_mob)] blew up [key_name(M)] with \a [explosion_source] in [get_area(T)]." - var/ff_msg = "[key_name(firing_mob)] blew up [key_name(M)] with \a [explosion_source] in [get_area(T)] (JMP LOC) (JMP SRC) ([firing_mob.client ? "PM" : "NO CLIENT"])" + var/ff_msg = "[key_name(firing_mob)] blew up [key_name(M)] with \a [explosion_source] in [get_area(T)] (JMP LOC) (JMP SRC) [ADMIN_PM(firing_mob)]" var/ff_living = TRUE if(M.stat == DEAD) ff_living = FALSE diff --git a/code/datums/callback.dm b/code/datums/callback.dm index 2c7326060a1c..4fbb16c3d259 100644 --- a/code/datums/callback.dm +++ b/code/datums/callback.dm @@ -50,6 +50,13 @@ HELP TO PROC TYPEPATH SHORTCUTS (Purely based on the path in the code) if (length(args) > 2) arguments = args.Copy(3) +/datum/callback/Destroy(force, ...) + delegate = null + if(arguments) + arguments.Cut() + arguments = null + return ..() + /proc/ImmediateInvokeAsync(thingtocall, proctocall, ...) set waitfor = FALSE diff --git a/code/datums/components/autofire/_automated_fire.dm b/code/datums/components/autofire/_automated_fire.dm new file mode 100644 index 000000000000..9abd6a152199 --- /dev/null +++ b/code/datums/components/autofire/_automated_fire.dm @@ -0,0 +1,49 @@ +/datum/component/automatedfire + ///The owner of this component + var/atom/shooter + /// Contains the scheduled fire time, used for scheduling EOL + var/next_fire + /// Contains the reference to the next component in the bucket, used by autofire subsystem + var/datum/component/automatedfire/next + /// Contains the reference to the previous component in the bucket, used by autofire subsystem + var/datum/component/automatedfire/prev + + +/// schedule the shooter into the system, inserting it into the next fire queue +/datum/component/automatedfire/proc/schedule_shot() + //We move to another bucket, so we clean the reference from the former linked list + next = null + prev = null + var/list/bucket_list = SSautomatedfire.bucket_list + + // Ensure the next_fire time is properly bound to avoid missing a scheduled event + next_fire = max(CEILING(next_fire, world.tick_lag), world.time + world.tick_lag) + + // Get bucket position and a local reference to the datum var, it's faster to access this way + var/bucket_pos = AUTOFIRE_BUCKET_POS(next_fire) + + // Get the bucket head for that bucket, increment the bucket count + var/datum/component/automatedfire/bucket_head = bucket_list[bucket_pos] + SSautomatedfire.shooter_count++ + + // If there is no existing head of this bucket, we can set this shooter to be that head + if (!bucket_head) + bucket_list[bucket_pos] = src + return + + // Otherwise it's a simple insertion into the double-linked list + if (bucket_head.next) + next = bucket_head.next + next.prev = src + + bucket_head.next = src + prev = bucket_head + + //Something went wrong, probably a lag spike or something. To prevent infinite loops, we reschedule it to a another next fire + if(prev == src) + next_fire += 1 + schedule_shot() + +///Handle the firing of the autofire component +/datum/component/automatedfire/proc/process_shot() + return diff --git a/code/datums/components/autofire/autofire.dm b/code/datums/components/autofire/autofire.dm new file mode 100644 index 000000000000..2b9401e8d346 --- /dev/null +++ b/code/datums/components/autofire/autofire.dm @@ -0,0 +1,142 @@ +/datum/component/automatedfire/autofire + ///The current fire mode of the shooter + var/fire_mode + ///Delay between two shots when in full auto + var/auto_fire_shot_delay + ///Delay between two burst shots + var/burstfire_shot_delay + ///How many bullets are fired in burst mode + var/burst_shots_to_fire + ///Count the shots fired when bursting + var/shots_fired = 0 + ///If the shooter is currently shooting + var/shooting = FALSE + ///If TRUE, the shooter will reset its references at the end of the burst + var/have_to_reset_at_burst_end = FALSE + ///If we are in a burst + var/bursting = FALSE + /// The multiplier for how much slower the parent should fire in automatic mode. 1 is normal, 1.2 is 20% slower, 2 is 100% slower, etc. + var/automatic_delay_mult = 1 + ///Callback to set bursting mode on the parent + var/datum/callback/callback_bursting + ///Callback to ask the parent to reset its firing vars + var/datum/callback/callback_reset_fire + ///Callback to ask the parent to fire + var/datum/callback/callback_fire + ///Callback to ask the parent to display ammo + var/datum/callback/callback_display_ammo + ///Callback to set parent's fa_firing + var/datum/callback/callback_set_firing + +/datum/component/automatedfire/autofire/Initialize(auto_fire_shot_delay = 0.3 SECONDS, burstfire_shot_delay, burst_shots_to_fire = 3, fire_mode = GUN_FIREMODE_SEMIAUTO, automatic_delay_mult = 1, datum/callback/callback_bursting, datum/callback/callback_reset_fire, datum/callback/callback_fire, datum/callback/callback_display_ammo, datum/callback/callback_set_firing) + . = ..() + + RegisterSignal(parent, COMSIG_GUN_FIRE_MODE_TOGGLE, PROC_REF(modify_fire_mode)) + RegisterSignal(parent, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, PROC_REF(modify_fire_shot_delay)) + RegisterSignal(parent, COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED, PROC_REF(modify_burst_shots_to_fire)) + RegisterSignal(parent, COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED, PROC_REF(modify_burstfire_shot_delay)) + RegisterSignal(parent, COMSIG_GUN_FIRE, PROC_REF(initiate_shot)) + RegisterSignal(parent, COMSIG_GUN_STOP_FIRE, PROC_REF(stop_firing)) + RegisterSignal(parent, COMSIG_GUN_INTERRUPT_FIRE, PROC_REF(hard_reset)) + + src.auto_fire_shot_delay = auto_fire_shot_delay + src.burstfire_shot_delay = burstfire_shot_delay + src.burst_shots_to_fire = burst_shots_to_fire + src.fire_mode = fire_mode + src.automatic_delay_mult = automatic_delay_mult + src.callback_bursting = callback_bursting + src.callback_reset_fire = callback_reset_fire + src.callback_fire = callback_fire + src.callback_display_ammo = callback_display_ammo + src.callback_set_firing = callback_set_firing + +/datum/component/automatedfire/autofire/Destroy(force, silent) + QDEL_NULL(callback_fire) + QDEL_NULL(callback_reset_fire) + QDEL_NULL(callback_bursting) + QDEL_NULL(callback_display_ammo) + QDEL_NULL(callback_set_firing) + return ..() + +///Setter for fire mode +/datum/component/automatedfire/autofire/proc/modify_fire_mode(datum/source, fire_mode) + SIGNAL_HANDLER + src.fire_mode = fire_mode + +///Setter for auto fire shot delay +/datum/component/automatedfire/autofire/proc/modify_fire_shot_delay(datum/source, auto_fire_shot_delay) + SIGNAL_HANDLER + src.auto_fire_shot_delay = auto_fire_shot_delay + +///Setter for the number of shots in a burst +/datum/component/automatedfire/autofire/proc/modify_burst_shots_to_fire(datum/source, burst_shots_to_fire) + SIGNAL_HANDLER + src.burst_shots_to_fire = burst_shots_to_fire + +///Setter for burst shot delay +/datum/component/automatedfire/autofire/proc/modify_burstfire_shot_delay(datum/source, burstfire_shot_delay) + SIGNAL_HANDLER + src.burstfire_shot_delay = burstfire_shot_delay + +///Insert the component in the bucket system if it was not in already +/datum/component/automatedfire/autofire/proc/initiate_shot() + SIGNAL_HANDLER + if(shooting)//if we are already shooting, it means the shooter is still on cooldown + return + shooting = TRUE + process_shot() + +///Remove the component from the bucket system if it was in +/datum/component/automatedfire/autofire/proc/stop_firing() + SIGNAL_HANDLER + if(!shooting) + return + ///We are burst firing, we can't clean the state now. We will do it when the burst is over + if(bursting) + have_to_reset_at_burst_end = TRUE + return + shooting = FALSE + shots_fired = 0 + +///Hard reset the autofire, happens when the shooter fall/is thrown, at the end of a burst or when it runs out of ammunition +/datum/component/automatedfire/autofire/proc/hard_reset() + SIGNAL_HANDLER + callback_reset_fire.Invoke() //resets the gun + shots_fired = 0 + have_to_reset_at_burst_end = FALSE + if(bursting) + bursting = FALSE + callback_bursting.Invoke(FALSE) + shooting = FALSE + + +///Ask the shooter to fire and schedule the next shot if need +/datum/component/automatedfire/autofire/process_shot() + if(!shooting) + return + if(next_fire > world.time)//This mean duplication somewhere, we abort now + return + if(!(callback_fire.Invoke() & AUTOFIRE_CONTINUE))//reset fire if we want to stop + hard_reset() + return + switch(fire_mode) + if(GUN_FIREMODE_BURSTFIRE) + shots_fired++ + if(shots_fired == burst_shots_to_fire) + callback_bursting.Invoke(FALSE) + callback_display_ammo.Invoke() + bursting = FALSE + stop_firing() + if(have_to_reset_at_burst_end)//We failed to reset because we were bursting, we do it now + callback_reset_fire.Invoke() + have_to_reset_at_burst_end = FALSE + return + callback_bursting.Invoke(TRUE) + bursting = TRUE + next_fire = world.time + burstfire_shot_delay + if(GUN_FIREMODE_AUTOMATIC) + callback_set_firing.Invoke(TRUE) + next_fire = world.time + (auto_fire_shot_delay * automatic_delay_mult) + if(GUN_FIREMODE_SEMIAUTO) + return + schedule_shot() diff --git a/code/datums/components/bad_leg.dm b/code/datums/components/bad_leg.dm index a875e0da0f6c..4a8678c4da76 100644 --- a/code/datums/components/bad_leg.dm +++ b/code/datums/components/bad_leg.dm @@ -52,20 +52,28 @@ /datum/component/bad_leg/UnregisterFromParent() ..() - UnregisterSignal(parent_human, COMSIG_MOVABLE_MOVED, PROC_REF(stumble)) - bound_action?.unique_remove_action(parent_human, /datum/action/human_action/rest_legs, src) + if(parent_human) + UnregisterSignal(parent_human, COMSIG_MOVABLE_MOVED, PROC_REF(stumble)) + bound_action?.unique_remove_action(parent_human, /datum/action/human_action/rest_legs, src) /datum/component/bad_leg/proc/stumble(mob/living/carbon/human/parent_human) SIGNAL_HANDLER ///This prevents weird shit like corpses being dragged triggering the messages. - if(parent_human.stat || parent_human.buckled || parent_human.is_mob_incapacitated() || parent_human.is_mob_restrained()) + if(parent_human.stat || parent_human.buckled && !HAS_TRAIT(parent_human, TRAIT_USING_WHEELCHAIR) || parent_human.is_mob_incapacitated() || parent_human.is_mob_restrained()) return if(parent_human.throwing == TRUE) return // unaffected on throws + if(HAS_TRAIT(parent_human, TRAIT_USING_WHEELCHAIR)) + if(last_message_time + MESSAGE_COOLDOWN * 10 < world.time) //longer cooldown if using wheelchairs. + parent_human.visible_message(SPAN_NOTICE("[parent_human] wheels \himself with \his wheelchair."), SPAN_NOTICE("Your wheelchair lets you move while resting your [affected_limb.display_name], lessening the suffering on it.")) + last_message_time = world.time + steps_walking = max(steps_walking - 1, 0) + return + if(HAS_TRAIT(parent_human, TRAIT_HOLDS_CANE)) if(last_message_time + MESSAGE_COOLDOWN * 10 < world.time) //longer cooldown if using canes parent_human.visible_message(SPAN_NOTICE("[parent_human] paces \his movement with \his cane."), SPAN_NOTICE("Your cane lets you pace your movement, lessening the suffering on your [affected_limb.display_name].")) diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm index 6deb27a6817b..ef77aaf471dc 100644 --- a/code/datums/components/footstep.dm +++ b/code/datums/components/footstep.dm @@ -13,8 +13,9 @@ var/falloff ///This can be a list OR a soundfile OR null. Determines whatever sound gets played. var/footstep_sounds + var/drag_sounds -/datum/component/footstep/Initialize(steps_ = 2, volume_ = 50, range_ = null, falloff_ = 1, footstep_sounds_ = "alien_footstep_large") +/datum/component/footstep/Initialize(steps_ = 2, volume_ = 50, range_ = null, falloff_ = 1, footstep_sounds_ = "alien_footstep_large", drag_sounds_ = 'sound/effects/alien_dragsound_large.ogg') if(!isliving(parent)) return COMPONENT_INCOMPATIBLE steps = steps_ @@ -22,6 +23,7 @@ range = range_ falloff = falloff_ footstep_sounds = footstep_sounds_ + drag_sounds = drag_sounds_ RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), PROC_REF(play_simplestep)) @@ -31,7 +33,7 @@ return var/mob/living/LM = parent - if(LM.buckled || LM.lying || LM.throwing || LM.is_ventcrawling) + if(LM.buckled || LM.throwing || LM.is_ventcrawling || LM.stat == DEAD) return if(LM.life_steps_total % steps) @@ -44,5 +46,8 @@ var/turf/open/T = prepare_step() if(!T) return - if(isfile(footstep_sounds) || istext(footstep_sounds)) + var/mob/living/parent_mob = parent + if(parent_mob.lying && (isfile(drag_sounds) || istext(drag_sounds))) + playsound(T, drag_sounds, volume, rand(20000, 25000), range, falloff = falloff) + else if(isfile(footstep_sounds) || istext(footstep_sounds)) playsound(T, footstep_sounds, volume, rand(20000, 25000), range, falloff = falloff) diff --git a/code/datums/components/weed_food.dm b/code/datums/components/weed_food.dm new file mode 100644 index 000000000000..ce6c17e0af95 --- /dev/null +++ b/code/datums/components/weed_food.dm @@ -0,0 +1,302 @@ +#define WEED_FOOD_DELAY 5 MINUTES +#define WEED_FOOD_STATE_DELAY 1 MINUTES + +/atom/movable/vis_obj/weed_food + name = "weeds" + desc = "Weird black weeds in the shape of a body..." + gender = PLURAL + vis_flags = VIS_INHERIT_DIR|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER + icon = 'icons/mob/xenos/weeds.dmi' + var/static/list/icon_states = list("human_1","human_2","human_3","human_4","human_5") + var/static/list/icon_states_flipped = list("human_1_f","human_2_f","human_3_f","human_4_f","human_5_f") + var/icon_state_idx = 0 + var/timer_id = null + var/flipped = FALSE + +/atom/movable/vis_obj/weed_food/Initialize(mapload, is_flipped, ...) + flipped = is_flipped + timer_id = addtimer(CALLBACK(src, PROC_REF(on_animation_timer)), WEED_FOOD_STATE_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_LOOP|TIMER_DELETE_ME) + on_animation_timer() + return ..() + +/// Timer callback for changing the icon_state +/atom/movable/vis_obj/weed_food/proc/on_animation_timer() + icon_state_idx++ + if(icon_state_idx > length(icon_states)) + deltimer(timer_id) + timer_id = null + return + icon_state = flipped ? icon_states_flipped[icon_state_idx] : icon_states[icon_state_idx] + +/** + * A component that can be attached to a mob/living to be merged with weeds after a delay. + * Attempting to attach a new weed_food even if one already exists is equivalent to calling start(). + * + * Attach this to any mob/living that is dead (death or initialized dead) and it should handle the rest. + */ +/datum/component/weed_food + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + /// Whether we are waiting on timer to merge + var/active = FALSE + /// Whether we are merged with weeds + var/merged = FALSE + /// The time we were unmerged (just to handle weeds upgrading) + var/unmerged_time + /// Any active timer for a pending merge + var/timer_id = null + /// The living mob that we are bound to + var/mob/living/parent_mob + /// The turf that our parent is on + var/turf/parent_turf + /// The obj that our parent is buckled to and we have registered a signal + var/obj/parent_buckle + /// The weeds that we are merging/merged with + var/obj/effect/alien/weeds/absorbing_weeds + /// The overlay image when merged + var/atom/movable/vis_obj/weed_food/weed_appearance + +/datum/component/weed_food/Initialize(...) + parent_mob = parent + //if(!istype(parent_mob)) + //return COMPONENT_INCOMPATIBLE + if(!istype(parent_mob, /mob/living/carbon/human)) + return COMPONENT_INCOMPATIBLE // TODO: At the moment we only support humans + + parent_turf = get_turf(parent_mob) + if(parent_turf != parent_mob.loc) + parent_turf = null // if our location is actually a container, we want to be safe from weeds + + start() + +/datum/component/weed_food/InheritComponent(datum/component/C, i_am_original) + start() + +/datum/component/weed_food/Destroy(force, silent) + . = ..() + + unmerge_with_weeds() + QDEL_NULL(weed_appearance) + parent_mob = null + parent_turf = null + +/datum/component/weed_food/RegisterWithParent() + RegisterSignal(parent_mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) + RegisterSignal(parent_mob, list(COMSIG_LIVING_REJUVENATED, COMSIG_HUMAN_REVIVED), PROC_REF(on_rejuv)) + RegisterSignal(parent_mob, COMSIG_HUMAN_SET_UNDEFIBBABLE, PROC_REF(on_update)) + if(parent_turf) + RegisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH, PROC_REF(on_update)) + +/datum/component/weed_food/UnregisterFromParent() + if(parent_mob) + UnregisterSignal(parent_mob, list( + COMSIG_MOVABLE_MOVED, + COMSIG_LIVING_REJUVENATED, + COMSIG_HUMAN_REVIVED, + COMSIG_HUMAN_SET_UNDEFIBBABLE, + )) + if(absorbing_weeds) + UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) + if(parent_turf) + UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH) + if(parent_buckle) + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + +/// SIGNAL_HANDLER for COMSIG_MOVABLE_MOVED +/datum/component/weed_food/proc/on_move() + SIGNAL_HANDLER + + if(absorbing_weeds) + UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) + absorbing_weeds = null + + if(parent_turf) + UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH) + parent_turf = get_turf(parent_mob) + if(parent_turf != parent_mob.loc) + parent_turf = null // if our location is actually a container, we want to be safe from weeds + else + RegisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH, PROC_REF(on_update)) + + // We moved, restart or start the proccess + if(stop() || !merged) + start() + return + + // If we somehow moved when we were merged, handle that + absorbing_weeds = parent_turf?.weeds + if(absorbing_weeds) + RegisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) + return + unmerge_with_weeds() + +/// SIGNAL_HANDLER for COMSIG_LIVING_REJUVENATED and COMSIG_HUMAN_REVIVED +/datum/component/weed_food/proc/on_rejuv() + SIGNAL_HANDLER + + qdel(src) + +/// SIGNAL_HANDLER for COSMIG_OBJ_AFTER_BUCKLE +/datum/component/weed_food/proc/on_after_buckle(obj/source, mob/buckled) + SIGNAL_HANDLER + + if(buckled) + return + start() // We unbuckled, so lets try to start again + +/// SIGNAL_HANDLER for COMSIG_HUMAN_SET_UNDEFIBBABLE & COMSIG_WEEDNODE_GROWTH +/datum/component/weed_food/proc/on_update() + SIGNAL_HANDLER + + start() + +/// SIGNAL_HANDLER for COMSIG_PARENT_QDELETING of weeds +/datum/component/weed_food/proc/on_weed_deletion() + SIGNAL_HANDLER + + if(active) + stop() + return + if(merged) + unmerge_with_weeds() + return + +/** + * Try to start the process to turn into weeds + * Returns TRUE if started successfully + */ +/datum/component/weed_food/proc/start() + if(active) + return FALSE + if(merged) + return FALSE + if(QDELETED(parent_mob)) + return FALSE + + if(parent_mob.buckled) + if(parent_mob.buckled == parent_buckle) + return FALSE // Still buckled to the same thing + if(!istype(parent_mob.buckled, /obj/structure/bed/nest)) + if(parent_buckle) // Still have a lingering reference somehow? + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + parent_buckle = parent_mob.buckled + RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle)) + return FALSE + if(parent_buckle) + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + parent_buckle = null + + if(parent_mob.is_xeno_grabbable()) + return FALSE + if(!(parent_mob.status_flags & PERMANENTLY_DEAD)) + var/mob/living/carbon/human/parent_human = parent_mob + if(istype(parent_human) && !parent_human.undefibbable) + return FALSE + if(!parent_turf?.weeds) + return FALSE + if(SEND_SIGNAL(parent_mob, COMSIG_ATTEMPT_MOB_PULL) & COMPONENT_CANCEL_MOB_PULL) + return FALSE + + if(unmerged_time == world.time) + return merge_with_weeds() // Weeds upgraded, re-merge now re-using the apperance + QDEL_NULL(weed_appearance) + absorbing_weeds = parent_turf.weeds + RegisterSignal(parent_turf.weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) + + active = TRUE + timer_id = addtimer(CALLBACK(src, PROC_REF(merge_with_weeds)), WEED_FOOD_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_DELETE_ME|TIMER_OVERRIDE) + + return TRUE + +/** + * Try to stop the process turning into weeds + * Returns TRUE if stopped successfully (was active when called) + */ +/datum/component/weed_food/proc/stop() + if(!active) + return FALSE + + active = FALSE + deltimer(timer_id) + timer_id = null + + return TRUE + +/** + * Finish becomming one with the weeds + * Returns TRUE if merged successfully + */ +/datum/component/weed_food/proc/merge_with_weeds() + if(merged) + return FALSE + if(QDELETED(parent_mob)) + return FALSE + + if(absorbing_weeds) // Remove the signal that would call stop + UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) + + if(parent_mob.buckled) + if(parent_mob.buckled == parent_buckle) + return FALSE // Still buckled to the same thing somehow? + if(!istype(parent_mob.buckled, /obj/structure/bed/nest)) + if(parent_buckle) // Still have a lingering reference somehow? + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + parent_buckle = parent_mob.buckled + RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle)) + return FALSE + if(parent_buckle) + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + parent_buckle = null + + if(SEND_SIGNAL(parent_mob, COMSIG_ATTEMPT_MOB_PULL) & COMPONENT_CANCEL_MOB_PULL) + return FALSE + + absorbing_weeds = parent_turf?.weeds + if(!absorbing_weeds) + return FALSE + RegisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) + // Technically we could have just left the signal alone, but both because of the posibility of other conditions preventing a merge or weeds somehow changing and on_move didn't catch it, this is less fragile + + active = FALSE + merged = TRUE + + parent_mob.density = FALSE + parent_mob.anchored = TRUE + parent_mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + parent_mob.plane = FLOOR_PLANE + parent_mob.remove_from_all_mob_huds() + + if(!weed_appearance) // Make a new sprite if we aren't re-merging + var/is_flipped = parent_mob.transform.b == -1 // Technically we should check if d is 1 too, but corpses can only be rotated 90 or 270 (1/-1 or -1/1) + if(parent_mob.dir & WEST) + is_flipped = !is_flipped // The direction reversed the effect of the flip! + weed_appearance = new(null, is_flipped) + weed_appearance.color = absorbing_weeds.color + // TODO: For non-humans change the icon_state or something here + parent_mob.vis_contents += weed_appearance + + return TRUE + +/** + * Undo the weedening + * Returns TRUE if unmerged successfully (always) + */ +/datum/component/weed_food/proc/unmerge_with_weeds() + merged = FALSE + unmerged_time = world.time + + if(absorbing_weeds) + UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) + absorbing_weeds = null + + parent_mob.anchored = FALSE + parent_mob.mouse_opacity = MOUSE_OPACITY_ICON + parent_mob.plane = GAME_PLANE + parent_mob.vis_contents -= weed_appearance + + if(!QDELETED(parent_mob)) + parent_mob.add_to_all_mob_huds() + + return TRUE + +#undef WEED_FOOD_DELAY +#undef WEED_FOOD_STATE_DELAY diff --git a/code/datums/construction/construction_template.dm b/code/datums/construction/construction_template.dm index e45a708ea053..0b874def4495 100644 --- a/code/datums/construction/construction_template.dm +++ b/code/datums/construction/construction_template.dm @@ -28,6 +28,10 @@ build_loc = null return ..() +///runs in /obj/effect/alien/resin/construction/proc/set_template() for logic needed to occur then +/datum/construction_template/proc/on_template_creation() + return + /datum/construction_template/proc/set_structure_image() return diff --git a/code/datums/construction/xenomorph/construction_template_xenomorph.dm b/code/datums/construction/xenomorph/construction_template_xenomorph.dm index 9417251d112e..46b7e797632f 100644 --- a/code/datums/construction/xenomorph/construction_template_xenomorph.dm +++ b/code/datums/construction/xenomorph/construction_template_xenomorph.dm @@ -68,5 +68,36 @@ pixel_y = -8 pixel_x = -8 + /// This will be used to orient the nest that will be built + var/direction_to_put_nest + +/datum/construction_template/xenomorph/nest/complete() //overrided for unique build logic + if(!owner || !get_turf(owner)) + log_debug("Constuction template ([name]) completed construction without a build location") + return + if(hive_ref) + hive_ref.remove_construction(owner) + build_loc = get_turf(owner) + var/obj/effect/alien/resin/special/nest/newly_builtor = new build_type(build_loc, hive_ref) + playsound(build_loc, "alien_resin_build", 25) + if(newly_builtor) + newly_builtor.pred_nest.dir = direction_to_put_nest + newly_builtor.pred_nest.pixel_x = newly_builtor.pred_nest.buckling_x["[direction_to_put_nest]"] + newly_builtor.pred_nest.pixel_y = newly_builtor.pred_nest.buckling_y["[direction_to_put_nest]"] + qdel(owner) + qdel(src) + /datum/construction_template/xenomorph/nest/set_structure_image() build_icon = 'icons/mob/xenos/structures48x48.dmi' + +/datum/construction_template/xenomorph/nest/on_template_creation() + var/turf/home_turf = get_turf(owner) + if(!home_turf.density) + for(var/i in GLOB.cardinals) + var/turf/stepped_turf = get_step(home_turf, i) + if(stepped_turf.density) + direction_to_put_nest = get_dir(stepped_turf, owner) + return + xeno_message(SPAN_XENOWARNING("This structure needs to be built directly next to an vertical surface."), 7, XENO_HIVE_NORMAL) + qdel(owner) + qdel(src) diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 312a133f8724..b60b20bc9026 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -305,8 +305,14 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) S.fields["criminal"] = "None" S.fields["incident"] = "" S.fields["ref"] = WEAKREF(H) + + if(H.sec_record && !jobban_isbanned(H, "Records")) + var/new_comment = list("entry" = H.sec_record, "created_by" = list("name" = "\[REDACTED\]", "rank" = "Military Police"), "deleted_by" = null, "deleted_at" = null, "created_at" = "Pre-Deployment") + S.fields["comments"] = list("1" = new_comment) + S.fields["notes"] = H.sec_record security += S + //Locked Record var/datum/data/record/L = new() L.fields["id"] = md5("[H.real_name][H.job]") diff --git a/code/datums/datum.dm b/code/datums/datum.dm index a6f567f17176..b26c6afe4d91 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -54,10 +54,12 @@ */ var/list/cooldowns +#ifndef EXPERIMENT_515_DONT_CACHE_REF /// A cached version of our \ref /// The brunt of \ref costs are in creating entries in the string tree (a tree of immutable strings) /// This avoids doing that more then once per datum by ensuring ref strings always have a reference to them after they're first pulled var/cached_ref +#endif /// A weak reference to another datum var/datum/weakref/weak_reference @@ -93,40 +95,46 @@ */ /datum/proc/Destroy(force=FALSE, ...) SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) tag = null datum_flags &= ~DF_USE_TAG //In case something tries to REF us weak_reference = null //ensure prompt GCing of weakref. - 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(cooldowns) + for(var/cooldown as anything in cooldowns) + var/cd_id = cooldowns[cooldown] + if(cd_id != -1) + deltimer(cd_id) + + if(active_timers) + var/list/timers = active_timers + active_timers = null + for(var/datum/timedevent/timer as anything in timers) + if (timer.spent && !(timer.flags & TIMER_DELETE_ME)) + continue + qdel(timer) //BEGIN: ECS SHIT signal_enabled = FALSE - var/list/dc = datum_components - if(dc) - var/all_components = dc[/datum/component] + if(datum_components) + var/all_components = datum_components[/datum/component] if(length(all_components)) - for(var/I in all_components) - var/datum/component/C = I - qdel(C, FALSE, TRUE) + for(var/datum/component/component as anything in all_components) + qdel(component, FALSE, TRUE) else var/datum/component/C = all_components qdel(C, FALSE, TRUE) - dc.Cut() + if(datum_components) + debug_log("'[src]' datum_components was not null after removing all components! [datum_components.len] entries remained...") + datum_components.Cut() var/list/lookup = comp_lookup if(lookup) for(var/sig in lookup) var/list/comps = lookup[sig] if(length(comps)) - for(var/i in comps) - var/datum/component/comp = i + for(var/datum/component/comp as anything in comps) comp.UnregisterSignal(src, sig) else var/datum/component/comp = comps diff --git a/code/datums/diseases/black_goo.dm b/code/datums/diseases/black_goo.dm index 61c67d43d49c..38a26f3648c7 100644 --- a/code/datums/diseases/black_goo.dm +++ b/code/datums/diseases/black_goo.dm @@ -17,6 +17,7 @@ stage_prob = 4 stage_minimum_age = 150 survive_mob_death = TRUE //FALSE //switch to true to make dead infected humans still transform + longevity = 500 //should allow the dead to rise var/zombie_transforming = 0 //whether we're currently transforming the host into a zombie. var/goo_message_cooldown = 0 //to make sure we don't spam messages too often. var/stage_counter = 0 // tells a dead infectee their stage, so they can know when-abouts they'll revive @@ -106,6 +107,7 @@ if(human && human.loc) if(human.stat == DEAD) human.revive(TRUE) + human.remove_language(LANGUAGE_ENGLISH) // You lose the ability to understand english. Language processing is handled in the mind not the body. var/datum/species/zombie/zombie_species = GLOB.all_species[SPECIES_ZOMBIE] zombie_species.handle_alert_ghost(human) playsound(human.loc, 'sound/hallucinations/wail.ogg', 25, 1) @@ -122,7 +124,7 @@ icon = 'icons/mob/humans/species/r_zombie.dmi' icon_state = "claw_l" flags_item = NODROP|DELONDROP|ITEM_ABSTRACT - force = 40 + force = MELEE_FORCE_TIER_6 //slightly higher than normal w_class = SIZE_MASSIVE sharp = 1 attack_verb = list("slashed", "torn", "scraped", "gashed", "ripped") @@ -133,8 +135,9 @@ return FALSE . = ..() - if(.) - playsound(loc, 'sound/weapons/bladeslice.ogg', 25, 1, 5) + if(!.) + return FALSE + playsound(loc, 'sound/weapons/bladeslice.ogg', 25, 1, 5) if(ishuman_strict(target)) var/mob/living/carbon/human/human = target @@ -147,10 +150,7 @@ target.AddDisease(new /datum/disease/black_goo) to_chat(user, SPAN_XENOWARNING("You sense your target is now infected.")) - if(issynth(target)) - target.apply_effect(2, SLOW) - else - target.apply_effect(2, SUPERSLOW) + target.apply_effect(2, SLOW) /obj/item/weapon/zombie_claws/afterattack(obj/O as obj, mob/user as mob, proximity) if(get_dist(src, O) > 1) @@ -213,16 +213,16 @@ /datum/language/zombie name = "Zombie" - desc = "If you select this from the language screen, expect a ban." - color = "zombie" - - speech_verb = "groans" - ask_verb = "groans" - exclaim_verb = "groans" - - key = "4" + desc = "A growling, guttural method of communication, only Zombies seem to be capable of producing these sounds." + speech_verb = "growls" + ask_verb = "grumbles" + exclaim_verb = "snarls" + color = "monkey" + key = "h" flags = RESTRICTED +/datum/language/zombie/scramble(input) + return pick("Urrghh...", "Rrraaahhh...", "Aaaarghhh...", "Mmmrrrgggghhh...", "Huuuuhhhh...", "Sssssgrrrr...") /obj/item/clothing/glasses/zombie_eyes name = "zombie eyes" diff --git a/code/datums/effects/bleeding.dm b/code/datums/effects/bleeding.dm index af68ad6d10d8..e6cb184850d4 100644 --- a/code/datums/effects/bleeding.dm +++ b/code/datums/effects/bleeding.dm @@ -69,9 +69,12 @@ if(affected_mob.reagents) // Annoying QC check if(affected_mob.reagents.get_reagent_amount("thwei")) blood_loss -= THWEI_BLOOD_REDUCTION - if(affected_mob.reagents.get_reagent_amount("quickclot")) - buffer_blood_loss = 0 - return FALSE + + var/mob/living/carbon/human/affected_human = affected_mob + if(istype(affected_human)) + if(affected_human.chem_effect_flags & CHEM_EFFECT_NO_BLEEDING) + buffer_blood_loss = 0 + return FALSE affected_mob.drip(buffer_blood_loss) buffer_blood_loss = 0 @@ -94,15 +97,14 @@ if(affected_mob.bodytemperature < T0C && (affected_mob.reagents && affected_mob.reagents.get_reagent_amount("cryoxadone") || affected_mob.reagents.get_reagent_amount("clonexadone"))) blood_loss -= CRYO_BLOOD_REDUCTION - var/bicaridine = affected_mob.reagents?.get_reagent_amount("bicaridine") - if(bicaridine > REAGENTS_OVERDOSE && affected_mob.getBruteLoss() <= 0) - blood_loss -= BICAOD_BLOOD_REDUCTION - if(affected_mob.reagents) // Annoying QC check if(affected_mob.reagents.get_reagent_amount("thwei")) blood_loss -= THWEI_BLOOD_REDUCTION - if(affected_mob.reagents.get_reagent_amount("quickclot")) - return FALSE + + var/mob/living/carbon/human/affected_human = affected_mob + if(istype(affected_human)) + if(affected_human.chem_effect_flags & CHEM_EFFECT_NO_BLEEDING) + return FALSE affected_mob.blood_volume = max(affected_mob.blood_volume - blood_loss, 0) diff --git a/code/datums/effects/neurotoxin.dm b/code/datums/effects/neurotoxin.dm index 908f64e1fb74..836fccf49ca3 100644 --- a/code/datums/effects/neurotoxin.dm +++ b/code/datums/effects/neurotoxin.dm @@ -21,9 +21,8 @@ /// Stamina damage per tick. Major balance number. var/stam_dam = 7 -/datum/effects/neurotoxin/New(atom/thing) - ..(thing) - cause_data = create_cause_data("neurotoxic gas") +/datum/effects/neurotoxin/New(atom/thing, mob/from = null) + ..(thing, from, effect_name) /datum/effects/neurotoxin/validate_atom(atom/thing) if(isxeno(thing) || isobj(thing)) @@ -36,9 +35,10 @@ var/mob/living/carbon/affected_mob = affected_atom if(!.) return FALSE - if(affected_mob.stat) + if(affected_mob.stat == DEAD) return // General effects + affected_mob.last_damage_data = cause_data affected_mob.apply_stamina_damage(stam_dam) affected_mob.make_dizzy(12) @@ -129,7 +129,7 @@ if(0 to 5) if(hallu_area) for(var/mob/dead/observer/observer as anything in GLOB.observer_list) - to_chat(observer, SPAN_DEADSAY("[victim] has experienced a rare neuro-induced 'Schizo Lurker Pounce' hallucination (5% chance) at \the [hallu_area]" + " (JMP)")) + to_chat(observer, SPAN_DEADSAY("[victim] has experienced a rare neuro-induced 'Schizo Lurker Pounce' hallucination (5% chance) at \the [hallu_area]" + " [OBSERVER_JMP(observer, victim)]")) playsound_client(victim?.client,pick('sound/voice/alien_pounce.ogg','sound/voice/alien_pounce.ogg')) victim.KnockDown(3) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound_client), victim.client,"alien_claw_flesh"), 1 SECONDS) @@ -142,7 +142,7 @@ if(6 to 10) if(hallu_area) for(var/mob/dead/observer/observer as anything in GLOB.observer_list) - to_chat(observer, SPAN_DEADSAY("[victim] has experienced a rare neuro-induced 'OB' hallucination (4% chance) at \the [hallu_area]" + " (JMP)")) + to_chat(observer, SPAN_DEADSAY("[victim] has experienced a rare neuro-induced 'OB' hallucination (4% chance) at \the [hallu_area]" + " [OBSERVER_JMP(observer, victim)]")) playsound_client(victim.client,'sound/effects/ob_alert.ogg') addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound_client), victim.client,'sound/weapons/gun_orbital_travel.ogg'), 2 SECONDS) if(11 to 16) @@ -151,7 +151,7 @@ if(17 to 24) if(hallu_area) for(var/mob/dead/observer/observer as anything in GLOB.observer_list) - to_chat(observer, SPAN_DEADSAY("[victim] has experienced a rare neuro-induced 'Fake CAS firemission' hallucination (7% chance) at \the [hallu_area]" + " (JMP)")) + to_chat(observer, SPAN_DEADSAY("[victim] has experienced a rare neuro-induced 'Fake CAS firemission' hallucination (7% chance) at \the [hallu_area]" + " [OBSERVER_JMP(observer, victim)]")) hallucination_fakecas_sequence(victim) //Not gonna spam a billion timers for this one so outsourcing to a proc with sleeps is a better async solution if(25 to 42) to_chat(victim,SPAN_HIGHDANGER("A SHELL IS ABOUT TO IMPACT [pick(SPAN_UNDERLINE("TOWARDS THE [pick("WEST","EAST","SOUTH","NORTH")]"),SPAN_UNDERLINE("RIGHT ONTOP OF YOU!"))]!")) diff --git a/code/datums/elements/bloody_feet.dm b/code/datums/elements/bloody_feet.dm index 6a5a8a23ac6b..3bcccd8377c6 100644 --- a/code/datums/elements/bloody_feet.dm +++ b/code/datums/elements/bloody_feet.dm @@ -24,12 +24,12 @@ H.bloody_footsteps = steps_to_take LAZYADD(entered_bloody_turf, target) - RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) - RegisterSignal(target, COMSIG_HUMAN_BLOOD_CROSSED, PROC_REF(blood_crossed)) - RegisterSignal(target, COMSIG_HUMAN_CLEAR_BLOODY_FEET, PROC_REF(clear_blood)) + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved), override = TRUE) + RegisterSignal(target, COMSIG_HUMAN_BLOOD_CROSSED, PROC_REF(blood_crossed), override = TRUE) + RegisterSignal(target, COMSIG_HUMAN_CLEAR_BLOODY_FEET, PROC_REF(clear_blood), override = TRUE) if(shoes) LAZYSET(target_shoes, target, shoes) - RegisterSignal(shoes, COMSIG_ITEM_DROPPED, PROC_REF(on_shoes_removed)) + RegisterSignal(shoes, COMSIG_ITEM_DROPPED, PROC_REF(on_shoes_removed), override = TRUE) if(dry_time) addtimer(CALLBACK(src, PROC_REF(clear_blood), target), dry_time) diff --git a/code/datums/emergency_calls/big_game_hunter.dm b/code/datums/emergency_calls/big_game_hunter.dm index 16a0b0b5da6a..e749b6654355 100644 --- a/code/datums/emergency_calls/big_game_hunter.dm +++ b/code/datums/emergency_calls/big_game_hunter.dm @@ -10,7 +10,7 @@ /datum/emergency_call/van_bandolier/New() . = ..() - arrival_message = "Incoming Transmission: 'Heard your distress call, [MAIN_SHIP_NAME]. It had best be something which will look good on my wall, eh? Tally ho!'" + arrival_message = "'Heard your distress call, [MAIN_SHIP_NAME]. It had best be something which will look good on my wall, eh? Tally ho!'" /datum/emergency_call/van_bandolier/create_member(datum/mind/M, turf/override_spawn_loc) var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() diff --git a/code/datums/emergency_calls/clf.dm b/code/datums/emergency_calls/clf.dm index 75ce93a4f680..0a5f09e2a2f2 100644 --- a/code/datums/emergency_calls/clf.dm +++ b/code/datums/emergency_calls/clf.dm @@ -4,7 +4,7 @@ /datum/emergency_call/clf name = "Colonial Liberation Front (Squad)" mob_max = 10 - arrival_message = "Incoming Transmission: 'Attention, you are tresspassing on our soverign territory. Expect no forgiveness.'" + arrival_message = "'Attention, you are tresspassing on our soverign territory. Expect no forgiveness.'" objectives = "Assault the USCM, and sabotage as much as you can. Ensure any survivors escape in your custody." probability = 20 hostility = TRUE diff --git a/code/datums/emergency_calls/cmb.dm b/code/datums/emergency_calls/cmb.dm index 5ff35194dbb7..52da1c967a00 100644 --- a/code/datums/emergency_calls/cmb.dm +++ b/code/datums/emergency_calls/cmb.dm @@ -112,7 +112,7 @@ /datum/emergency_call/cmb/anchorpoint/New() ..() - arrival_message = "Incoming Transmission: [MAIN_SHIP_NAME], this is Anchorpoint Station. Be advised, a QRF Team of our Colonial Marines is currently attempting to board you. Open your ports, transmitting docking codes now. Standby." + arrival_message = "[MAIN_SHIP_NAME], this is Anchorpoint Station. Be advised, a QRF Team of our Colonial Marines is currently attempting to board you. Open your ports, transmitting docking codes now. Standby." objectives = "QRF Team. You are here to reinforce the cmb team we deployed earlier. Make contact and work with the CMB Marshal and their deputies. Facilitate their protection and evacuation if necessary. Secondary Objective: Investigate the reason for distress aboard the [MAIN_SHIP_NAME], and assist the crew if possible." /datum/emergency_call/cmb/anchorpoint/create_member(datum/mind/M, turf/override_spawn_loc) @@ -126,7 +126,7 @@ if(!leader && HAS_FLAG(mob?.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job)) leader = mob - to_chat(mob, SPAN_ROLE_HEADER("You are the Marine Team Leader of Anchorpoint Station!")) + to_chat(mob, SPAN_ROLE_HEADER("You are the Marine Fireteam Leader of Anchorpoint Station!")) arm_equipment(mob, /datum/equipment_preset/uscm/cmb/leader, TRUE, TRUE) // placeholder else if(smartgunners < max_smartgunners && HAS_FLAG(mob?.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(mob.client, JOB_SQUAD_SMARTGUN, time_required_for_job)) smartgunners++ @@ -151,10 +151,10 @@ /datum/emergency_call/cmb/anchorpoint/print_backstory(mob/living/carbon/human/M) if(M == leader) - to_chat(M, SPAN_BOLD("You are the Anchorpoint QRF Team Leader, originally from [pick(70;"The United Americas", 20;"Sol", 10;"a colony on the frontier")].")) + to_chat(M, SPAN_BOLD("You are the Anchorpoint QRF Fireteam Leader, originally from [pick(70;"The United Americas", 20;"Sol", 10;"a colony on the frontier")].")) to_chat(M, SPAN_BOLD("You've served on The Station for [pick(50; "a Sol year, and a tour of duty", 40;"a couple months", 10;"six years, three tours")].")) to_chat(M, SPAN_BOLD("Living, training and working alongside Colonial Marshals at Anchorpoint Station has kept you well disciplined, and you've always felt proud to be the cavalry.")) - to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the USS Almayer, and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) + to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the [MAIN_SHIP_NAME], and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) to_chat(M, SPAN_BOLD("Working on conjunction with the Colonial Marshals on many incidents has created a comradery between your organizations. The Marshals handle investigations and policing, while you come in to get the job done during riots or incursions. Any job where heavy lifting was required, you were there.")) to_chat(M, SPAN_BOLD("You were activated as a part of a Quick Reaction Force to reinforce Colonial Marshals in distress.")) to_chat(M, SPAN_BOLD("You weren't sure if it was a false alarm or not. Turns out it isn't...")) @@ -163,7 +163,7 @@ to_chat(M, SPAN_BOLD("You are the Anchorpoint QRF Team Smartgunner, originally from [pick(70;"The United Americas", 20;"Sol", 10;"a colony on the frontier")].")) to_chat(M, SPAN_BOLD("You've served on The Station for [pick(45; "a Sol year, and a tour of duty", 20;"a couple months", 5;"six long years, three consecutive tours")].")) to_chat(M, SPAN_BOLD("Living, training and working alongside Colonial Marshals at Anchorpoint Station has kept you well disciplined, and you've always felt proud to be the cavalry.")) - to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the USS Almayer, and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) + to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the [MAIN_SHIP_NAME], and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) to_chat(M, SPAN_BOLD("Working on conjunction with the Colonial Marshals on many incidents has created a comradery between your organizations. The Marshals handle investigations and policing, while you come in to get the job done during riots or incursions. Any job where heavy lifting was required, you were there.")) to_chat(M, SPAN_BOLD("You were activated as a part of a Quick Reaction Force to reinforce Colonial Marshals in distress.")) to_chat(M, SPAN_BOLD("You weren't sure if it was a false alarm or not. Turns out it isn't... But you've been waiting for an excuse to let loose that M56.")) @@ -172,7 +172,7 @@ to_chat(M, SPAN_BOLD("You are the Anchorpoint QRF Team Corpsman, originally from [pick(70;"The United Americas", 20;"Sol", 10;"a colony on the frontier")].")) to_chat(M, SPAN_BOLD("You've served on The Station for [pick(45; "a Sol year, and a tour of duty", 20;"a couple months", 5;"six long years, three consecutive tours")].")) to_chat(M, SPAN_BOLD("Living, training and working alongside Colonial Marshals at Anchorpoint Station has kept you well disciplined, and you've always felt proud to be the cavalry.")) - to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the USS Almayer, and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) + to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the [MAIN_SHIP_NAME], and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) to_chat(M, SPAN_BOLD("Working on conjunction with the Colonial Marshals on many incidents has created a comradery between your organizations. The Marshals handle investigations and policing, while you come in to get the job done during riots or incursions. Any job where heavy lifting was required, you were there.")) to_chat(M, SPAN_BOLD("You were activated as a part of a Quick Reaction Force to reinforce Colonial Marshals in distress.")) to_chat(M, SPAN_BOLD("You weren't sure if it was a false alarm or not. Turns out it isn't...")) @@ -181,7 +181,7 @@ to_chat(M, SPAN_BOLD("You are the Anchorpoint QRF Team Technical Specialist, originally from [pick(70;"The United Americas", 20;"Sol", 10;"a colony on the frontier")].")) to_chat(M, SPAN_BOLD("You've served on The Station for [pick(45; "a Sol year, and a tour of duty", 20;"a couple months", 5;"six long years, three consecutive tours")].")) to_chat(M, SPAN_BOLD("Living, training and working alongside Colonial Marshals at Anchorpoint Station has kept you well disciplined, and you've always felt proud to be the cavalry.")) - to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the USS Almayer, and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) + to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the [MAIN_SHIP_NAME], and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) to_chat(M, SPAN_BOLD("Working on conjunction with the Colonial Marshals on many incidents has created a comradery between your organizations. The Marshals handle investigations and policing, while you come in to get the job done during riots or incursions. Any job where heavy lifting was required, you were there.")) to_chat(M, SPAN_BOLD("You were activated as a part of a Quick Reaction Force to reinforce Colonial Marshals in distress.")) to_chat(M, SPAN_BOLD("You weren't sure if it was a false alarm or not. Turns out it isn't...")) @@ -190,7 +190,7 @@ to_chat(M, SPAN_BOLD("You are a Rifleman of the Anchorpoint Team QRF, originally from [pick(70;"The United Americas", 20;"Sol", 10;"a colony on the frontier")].")) to_chat(M, SPAN_BOLD("You've served on The Station for [pick(45; "a Sol year, and a tour of duty", 20;"a couple months", 5;"six long years, three consecutive tours")].")) to_chat(M, SPAN_BOLD("Living, training and working alongside Colonial Marshals at Anchorpoint Station has kept you well disciplined, and you've always felt proud to be the cavalry.")) - to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the USS Almayer, and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) + to_chat(M, SPAN_BOLD("During your time at Anchorpoint, you [pick(20; "had your life saved by a Colonial Marshal", 20;"quelled a corporate riot", 10; "defended the station against a UPP incursion", 10;"experienced a pathogenic outbreak", 10;"assisted the Colonial Marshals during an enacted martial law", 10;"were deployed to the [MAIN_SHIP_NAME], and understand its layout", 10;"assisted the Colonial Marshals with barricaded fugitive situation", 5;"helped the ICC take down a suspected smuggling ring", 5;"helped take down a human trafficking scheme alongside the Colonial Marshals" )].")) to_chat(M, SPAN_BOLD("Working on conjunction with the Colonial Marshals on many incidents has created a comradery between your organizations. The Marshals handle investigations and policing, while you come in to get the job done during riots or incursions. Any job where heavy lifting was required, you were there.")) to_chat(M, SPAN_BOLD("You were activated as a part of a Quick Reaction Force to reinforce Colonial Marshals in distress.")) to_chat(M, SPAN_BOLD("You weren't sure if it was a false alarm or not. Turns out it isn't...")) diff --git a/code/datums/emergency_calls/colonist.dm b/code/datums/emergency_calls/colonist.dm index 7430cf6c6bc5..8b39ca12a01e 100644 --- a/code/datums/emergency_calls/colonist.dm +++ b/code/datums/emergency_calls/colonist.dm @@ -5,7 +5,7 @@ name = "Colonists" mob_max = 8 mob_min = 1 - arrival_message = "Incoming Transmission: 'This is the *static*. We are *static*.'" + arrival_message = "'This is the *static*. We are *static*.'" objectives = "Follow the orders given to you." probability = 0 var/preset = /datum/equipment_preset/colonist diff --git a/code/datums/emergency_calls/cryo_marines.dm b/code/datums/emergency_calls/cryo_marines.dm index 1e32ff86fbf5..e7dcba08ed61 100644 --- a/code/datums/emergency_calls/cryo_marines.dm +++ b/code/datums/emergency_calls/cryo_marines.dm @@ -3,7 +3,7 @@ //whiskey outpost extra marines /datum/emergency_call/cryo_squad name = "Marine Cryo Reinforcements (Squad)" - mob_max = 15 + mob_max = 10 mob_min = 1 probability = 0 objectives = "Assist the USCM forces" @@ -12,13 +12,17 @@ name_of_spawn = /obj/effect/landmark/ert_spawns/distress_cryo shuttle_id = "" var/leaders = 0 + spawn_max_amount = TRUE -/datum/emergency_call/cryo_squad/spawn_candidates(announce, override_spawn_loc) +/datum/emergency_call/cryo_squad/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] leaders = cryo_squad.num_leaders - return ..() + . = ..() + shipwide_ai_announcement("Successfully deployed [mob_max] Foxtrot marines, of which [length(members)] are ready for duty.") + if(mob_max > length(members)) + announce_dchat("Some cryomarines were not taken, use the Join As Freed Mob verb to take one of them.") -/datum/emergency_call/cryo_squad/create_member(datum/mind/M, turf/override_spawn_loc) +/datum/emergency_call/cryo_squad/create_member(datum/mind/mind, turf/override_spawn_loc) set waitfor = 0 if(SSmapping.configs[GROUND_MAP].map_name == MAP_WHISKEY_OUTPOST) name_of_spawn = /obj/effect/landmark/ert_spawns/distress_wo @@ -26,34 +30,61 @@ if(!istype(spawn_loc)) return //Didn't find a useable spawn point. - var/mob/living/carbon/human/H = new(spawn_loc) - M.transfer_to(H, TRUE) + var/mob/living/carbon/human/human = new(spawn_loc) + + if(mind) + mind.transfer_to(human, TRUE) + else + human.create_hud() + + if(!mind) + for(var/obj/structure/machinery/cryopod/pod in view(7,human)) + if(pod && !pod.occupant) + pod.go_in_cryopod(human, silent = TRUE) + break sleep(5) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] - if(leaders < cryo_squad.max_leaders && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job)) - leader = H + if(leaders < cryo_squad.max_leaders && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(human.client, JOB_SQUAD_LEADER, time_required_for_job)))) + leader = human leaders++ - arm_equipment(H, /datum/equipment_preset/uscm/leader/cryo, TRUE, TRUE) - to_chat(H, SPAN_ROLE_HEADER("You are a Squad Leader in the USCM")) - to_chat(H, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) - else if (medics < max_medics && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(H.client, JOB_SQUAD_MEDIC, time_required_for_job)) + human.client?.prefs.copy_all_to(human, JOB_SQUAD_LEADER, TRUE, TRUE) + arm_equipment(human, /datum/equipment_preset/uscm/leader/cryo, mind == null, TRUE) + to_chat(human, SPAN_ROLE_HEADER("You are a Squad Leader in the USCM")) + to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) + to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) + else if (heavies < max_heavies && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_HEAVY) && check_timelock(human.client, JOB_SQUAD_SPECIALIST, time_required_for_job)))) + heavies++ + human.client?.prefs.copy_all_to(human, JOB_SQUAD_SPECIALIST, TRUE, TRUE) + arm_equipment(human, /datum/equipment_preset/uscm/spec/cryo, mind == null, TRUE) + to_chat(human, SPAN_ROLE_HEADER("You are a Weapons Specialist in the USCM")) + to_chat(human, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) + to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) + else if (medics < max_medics && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(human.client, JOB_SQUAD_MEDIC, time_required_for_job)))) medics++ - arm_equipment(H, /datum/equipment_preset/uscm/medic/cryo, TRUE, TRUE) - to_chat(H, SPAN_ROLE_HEADER("You are a Hospital Corpsman in the USCM")) - to_chat(H, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) - else if (engineers < max_engineers && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(H.client, JOB_SQUAD_ENGI, time_required_for_job)) + human.client?.prefs.copy_all_to(human, JOB_SQUAD_MEDIC, TRUE, TRUE) + arm_equipment(human, /datum/equipment_preset/uscm/medic/cryo, mind == null, TRUE) + to_chat(human, SPAN_ROLE_HEADER("You are a Hospital Corpsman in the USCM")) + to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) + to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) + else if (engineers < max_engineers && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(human.client, JOB_SQUAD_ENGI, time_required_for_job)))) engineers++ - arm_equipment(H, /datum/equipment_preset/uscm/engineer/cryo, TRUE, TRUE) - to_chat(H, SPAN_ROLE_HEADER("You are an Engineer in the USCM")) - to_chat(H, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) + human.client?.prefs.copy_all_to(human, JOB_SQUAD_ENGI, TRUE, TRUE) + arm_equipment(human, /datum/equipment_preset/uscm/engineer/cryo, mind == null, TRUE) + to_chat(human, SPAN_ROLE_HEADER("You are an Engineer in the USCM")) + to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) + to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) else - arm_equipment(H, /datum/equipment_preset/uscm/pfc/cryo, TRUE, TRUE) - to_chat(H, SPAN_ROLE_HEADER("You are a Rifleman in the USCM")) - to_chat(H, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) + human.client?.prefs.copy_all_to(human, JOB_SQUAD_MARINE, TRUE, TRUE) + arm_equipment(human, /datum/equipment_preset/uscm/pfc/cryo, mind == null, TRUE) + to_chat(human, SPAN_ROLE_HEADER("You are a Rifleman in the USCM")) + to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) + to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) sleep(10) - to_chat(H, SPAN_BOLD("Objectives: [objectives]")) + if(!mind) + human.free_for_ghosts() + to_chat(human, SPAN_BOLD("Objectives: [objectives]")) /datum/emergency_call/cryo_squad/platoon name = "Marine Cryo Reinforcements (Platoon)" diff --git a/code/datums/emergency_calls/cryo_marines_heavy.dm b/code/datums/emergency_calls/cryo_marines_heavy.dm index 6a3636568856..70ce52443573 100644 --- a/code/datums/emergency_calls/cryo_marines_heavy.dm +++ b/code/datums/emergency_calls/cryo_marines_heavy.dm @@ -16,10 +16,12 @@ var/leaders = 0 -/datum/emergency_call/cryo_squad_equipped/spawn_candidates(announce, override_spawn_loc) +/datum/emergency_call/cryo_squad_equipped/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] leaders = cryo_squad.num_leaders - return ..() + . = ..() + if(length(members)) + shipwide_ai_announcement("Successfully deployed [length(members)] Foxtrot marines.") /datum/emergency_call/cryo_squad_equipped/create_member(datum/mind/M, turf/override_spawn_loc) set waitfor = 0 diff --git a/code/datums/emergency_calls/deathsquad.dm b/code/datums/emergency_calls/deathsquad.dm index 10d1e7e12c35..0bfab8fbf2b7 100644 --- a/code/datums/emergency_calls/deathsquad.dm +++ b/code/datums/emergency_calls/deathsquad.dm @@ -6,7 +6,7 @@ name = "Weyland Whiteout Operators" mob_max = 8 mob_min = 5 - arrival_message = "Intercepted Transmission: '!`2*%slau#*jer t*h$em a!l%. le&*ve n(o^ w&*nes%6es.*v$e %#d ou^'" + arrival_message = "'!`2*%slau#*jer t*h$em a!l%. le&*ve n(o^ w&*nes%6es.*v$e %#d ou^'" objectives = "Whiteout protocol is in effect for the target. Ensure there are no traces of the infestation or any witnesses." probability = 0 shuttle_id = "Distress_PMC" diff --git a/code/datums/emergency_calls/deus_vult.dm b/code/datums/emergency_calls/deus_vult.dm index eddf2f5468c4..a5ba948c767e 100644 --- a/code/datums/emergency_calls/deus_vult.dm +++ b/code/datums/emergency_calls/deus_vult.dm @@ -5,7 +5,7 @@ mob_max = 35 mob_min = 10 max_heavies = 10 - arrival_message = "Intercepted Transmission: 'Deus le volt. Deus le volt! DEUS LE VOLT!!'" + arrival_message = "'Deus le volt. Deus le volt! DEUS LE VOLT!!'" objectives = "Clense the place of all that is unholy! Die in glory!" probability = 0 hostility = TRUE diff --git a/code/datums/emergency_calls/dutch.dm b/code/datums/emergency_calls/dutch.dm index 7e1736a153a7..32620fa43014 100644 --- a/code/datums/emergency_calls/dutch.dm +++ b/code/datums/emergency_calls/dutch.dm @@ -9,7 +9,7 @@ max_heavies = 1 max_medics = 1 - arrival_message = "Intercepted Transmission: 'We're here to kick ass and kill Yautja. Mainly kill Yautja." + arrival_message = "'We're here to kick ass and kill Yautja. Mainly kill Yautja." objectives = "Hunt down and kill all Yautja without mercy. Retrieve the gear and leave." probability = 0 @@ -24,18 +24,18 @@ if(!leader && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job)) leader = H - arm_equipment(H, /datum/equipment_preset/fun/dutch/arnie, TRUE, TRUE) + arm_equipment(H, /datum/equipment_preset/dutch/arnie, TRUE, TRUE) else if(heavies < max_heavies && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_HEAVY) && check_timelock(H.client, JOB_SQUAD_SPECIALIST, time_required_for_job)) heavies++ - arm_equipment(H, /datum/equipment_preset/fun/dutch/flamer, TRUE, TRUE) + arm_equipment(H, /datum/equipment_preset/dutch/flamer, TRUE, TRUE) else if(smartgunners < max_smartgunners && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(H.client, JOB_SQUAD_SMARTGUN, time_required_for_job)) smartgunners++ - arm_equipment(H, /datum/equipment_preset/fun/dutch/minigun, TRUE, TRUE) + arm_equipment(H, /datum/equipment_preset/dutch/minigun, TRUE, TRUE) else if(medics < max_medics && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(H.client, JOB_SQUAD_MEDIC, time_required_for_job)) medics++ - arm_equipment(H, /datum/equipment_preset/fun/dutch/medic, TRUE, TRUE) + arm_equipment(H, /datum/equipment_preset/dutch/medic, TRUE, TRUE) else - arm_equipment(H, /datum/equipment_preset/fun/dutch, TRUE, TRUE) + arm_equipment(H, /datum/equipment_preset/dutch, TRUE, TRUE) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) /datum/emergency_call/dutch/full_dozen //AWWW YEAH DA FULL DOZEN FO TODAY @@ -44,6 +44,6 @@ mob_min = 8 max_heavies = 2 max_medics = 2 - arrival_message = "Intercepted Transmission: 'We're here to kick ass and kill Yautja. Mainly kill Yautja." + arrival_message = "'We're here to kick ass and kill Yautja. Mainly kill Yautja." objectives = "Hunt down and kill all Yautja without mercy. Retrieve the gear and leave." probability = 0 diff --git a/code/datums/emergency_calls/emergency_call.dm b/code/datums/emergency_calls/emergency_call.dm index af16b2bb990d..3d43917b2bc7 100644 --- a/code/datums/emergency_calls/emergency_call.dm +++ b/code/datums/emergency_calls/emergency_call.dm @@ -9,6 +9,11 @@ var/list/datum/emergency_call/all_calls = list() //initialized at round start and stores the datums. var/datum/emergency_call/picked_calls[] = list() //Which distress calls are currently active +/datum/game_mode/proc/ares_online() + var/name = "ARES Online" + var/input = "ARES. Online. Good morning, marines." + shipwide_ai_announcement(input, name, 'sound/AI/ares_online.ogg') + //The distress call parent. Cannot be called itself due to "name" being a filtered target. /datum/emergency_call var/name = "name" @@ -33,7 +38,7 @@ var/max_engineers = 1 var/max_heavies = 1 var/max_smartgunners = 1 - var/shuttle_id = "Distress" //Empty shuttle ID means we're not using shuttles (aka spawn straight into cryo) + var/shuttle_id = MOBILE_SHUTTLE_ID_ERT1 //Empty shuttle ID means we're not using shuttles (aka spawn straight into cryo) var/auto_shuttle_launch = FALSE var/spawn_max_amount = FALSE @@ -79,12 +84,12 @@ else return chosen_call -/datum/game_mode/proc/get_specific_call(call_name, announce = TRUE, is_emergency = TRUE, info = "") +/datum/game_mode/proc/get_specific_call(call_name, announce = TRUE, is_emergency = TRUE, info = "", announce_dispatch_message = TRUE) for(var/datum/emergency_call/E in all_calls) //Loop through all potential candidates if(E.name == call_name) var/datum/emergency_call/em_call = new E.type() em_call.objective_info = info - em_call.activate(announce, is_emergency) + em_call.activate(announce, is_emergency, announce_dispatch_message) return error("get_specific_call could not find emergency call '[call_name]'") return @@ -180,7 +185,7 @@ else to_chat(src, SPAN_WARNING("You did not get enlisted in the response team. Better luck next time!")) -/datum/emergency_call/proc/activate(announce = TRUE, turf/override_spawn_loc) +/datum/emergency_call/proc/activate(announce = TRUE, turf/override_spawn_loc, announce_dispatch_message = TRUE) set waitfor = 0 if(!SSticker.mode) //Something horribly wrong with the gamemode ticker return @@ -191,11 +196,11 @@ message_admins("Distress beacon: '[name]' activated [src.hostility? "[SPAN_WARNING("(THEY ARE HOSTILE)")]":"(they are friendly)"]. Looking for candidates.") if(announce) - marine_announcement("A distress beacon has been launched from the [MAIN_SHIP_NAME].", "Priority Alert", 'sound/AI/distressbeacon.ogg') + marine_announcement("A distress beacon has been launched from the [MAIN_SHIP_NAME].", "Priority Alert", 'sound/AI/distressbeacon.ogg', logging = ARES_LOG_SECURITY) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/emergency_call, spawn_candidates), announce, override_spawn_loc), 30 SECONDS) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/emergency_call, spawn_candidates), announce, override_spawn_loc, announce_dispatch_message), 30 SECONDS) -/datum/emergency_call/proc/spawn_candidates(announce = TRUE, override_spawn_loc) +/datum/emergency_call/proc/spawn_candidates(announce = TRUE, override_spawn_loc, announce_dispatch_message = TRUE) if(SSticker.mode) SSticker.mode.picked_calls -= src @@ -207,7 +212,7 @@ candidates = list() if(announce) - marine_announcement("The distress signal has not received a response, the launch tubes are now recalibrating.", "Distress Beacon") + marine_announcement("The distress signal has not received a response, the launch tubes are now recalibrating.", "Distress Beacon", logging = ARES_LOG_SECURITY) return //We've got enough! @@ -237,7 +242,7 @@ to_chat(I.current, SPAN_WARNING("You didn't get selected to join the distress team. Better luck next time!")) if(announce) - marine_announcement(dispatch_message, "Distress Beacon", 'sound/AI/distressreceived.ogg') //Announcement that the Distress Beacon has been answered, does not hint towards the chosen ERT + marine_announcement(dispatch_message, "Distress Beacon", 'sound/AI/distressreceived.ogg', logging = ARES_LOG_SECURITY) //Announcement that the Distress Beacon has been answered, does not hint towards the chosen ERT message_admins("Distress beacon: [src.name] finalized, setting up candidates.") @@ -257,7 +262,7 @@ var/obj/structure/machinery/computer/shuttle/ert/comp = shuttle.getControlConsole() var/list/lzs = comp.get_landing_zones() if(!length(lzs)) - warning("Auto shuttle launch set for ert [name] but no lzs allowed.") + message_admins("Auto shuttle launch set for ert [name] but no lzs allowed.") return var/list/active_lzs = list() @@ -267,10 +272,14 @@ if(!(dock.z in z_levels)) continue // filter for free lzs - if(shuttle.canDock(dock) != DOCKING_SUCCESS) + if(shuttle.canDock(dock) != SHUTTLE_CAN_DOCK) continue active_lzs += list(dock) + if(!length(active_lzs)) + message_admins("Auto shuttle launch set for ert [name] but no lzs available.") + return + SSshuttle.moveShuttleToDock(shuttle, pick(active_lzs), TRUE) var/i = 0 @@ -288,6 +297,8 @@ create_member(null, override_spawn_loc) candidates = list() + if(arrival_message && announce) + marine_announcement(arrival_message, "Intercepted Tranmission:") /datum/emergency_call/proc/add_candidate(mob/M) if(!M.client || (M.mind && (M.mind in candidates)) || istype(M, /mob/living/carbon/xenomorph)) diff --git a/code/datums/emergency_calls/forsaken_xenos.dm b/code/datums/emergency_calls/forsaken_xenos.dm new file mode 100644 index 000000000000..d089830658d9 --- /dev/null +++ b/code/datums/emergency_calls/forsaken_xenos.dm @@ -0,0 +1,26 @@ +/datum/emergency_call/forsaken_xenos + name = "Xenomorphs Groundside (Forsaken)" + mob_min = 1 + mob_max = 4 + hostility = TRUE + name_of_spawn = /obj/effect/landmark/ert_spawns/groundside_xeno + objectives = "You have been left behind to safeguard the abandoned colony. Do not allow trespassers." + +/datum/emergency_call/forsaken_xenos/create_member(datum/mind/new_member, turf/override_spawn_loc) + var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() + + if(!istype(spawn_loc)) + return //Didn't find a useable spawn point. + + var/mob/current_mob = new_member.current + + var/picked = pick_weight(list(/mob/living/carbon/xenomorph/warrior = 2, /mob/living/carbon/xenomorph/lurker = 2, /mob/living/carbon/xenomorph/spitter = 2, /mob/living/carbon/xenomorph/drone = 5, /mob/living/carbon/xenomorph/runner = 5)) + + var/mob/living/carbon/xenomorph/new_xeno = new picked(spawn_loc) + + new_member.transfer_to(new_xeno, TRUE) + + new_xeno.set_hive_and_update(XENO_HIVE_FORSAKEN) + new_xeno.lock_evolve = TRUE + + QDEL_NULL(current_mob) diff --git a/code/datums/emergency_calls/goons.dm b/code/datums/emergency_calls/goons.dm index d3dc290e929a..8a0b00968807 100644 --- a/code/datums/emergency_calls/goons.dm +++ b/code/datums/emergency_calls/goons.dm @@ -2,9 +2,6 @@ name = "Weyland-Yutani Corporate Security (Squad)" mob_max = 6 probability = 0 - shuttle_id = "Distress_PMC" - name_of_spawn = /obj/effect/landmark/ert_spawns/distress_pmc - item_spawn = /obj/effect/landmark/ert_spawns/distress_pmc/item /datum/emergency_call/goon/New() ..() @@ -40,6 +37,65 @@ to_chat(M, SPAN_BOLD("You heard about the original distress signal ages ago, but you have only just gotten permission from corporate to enter the area.")) to_chat(M, SPAN_BOLD("Ensure no damage is incurred against Weyland-Yutani. Make sure the CL is safe.")) +/datum/emergency_call/goon/chem_retrieval + name = "Weyland-Yutani Goon (Chemical Investigation Squad)" + mob_max = 6 + mob_min = 2 + max_medics = 1 + var/checked_objective = FALSE + +/datum/emergency_call/goon/chem_retrieval/New() + ..() + dispatch_message = "[MAIN_SHIP_NAME], this is USCSS Royce. Our squad is boarding to retrieve all samples of a chemical recently scanned from your research department. You should already have received a significant sum of money for your department's discovery. In return we ask that you cooperate and provide everything related to the chemical to our retrieval team." + objectives = "Secure all documents, samples, and chemicals containing the property DNA_Disintegrating from [MAIN_SHIP_NAME] research department and return them to Response Team Station." + +/datum/emergency_call/goon/chem_retrieval/proc/check_objective_info() + if(objective_info) + objectives = "Secure all documents, samples and chemicals related to [objective_info] from [MAIN_SHIP_NAME] research department and return them to Response Team Station." + objectives += "Assume at least 30 units are located within the department. If they can not make more that should be all. Cooperate with the onboard CL to ensure all who know the complete recipe are kept silenced with a contract of confidentiality. All humans who have ingested the chemical must be brought back dead or alive. Viral scan is required for any humans who is suspected of ingestion. You must not deploy to the colony without explicit permission from PMC Dispatch. The professor may call for PMC back up if things get out of hand." + checked_objective = TRUE + +/datum/emergency_call/goon/chem_retrieval/create_member(datum/mind/M, turf/override_spawn_loc) + var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() + + if(!istype(spawn_loc)) + return //Didn't find a useable spawn point. + + var/mob/living/carbon/human/mob = new(spawn_loc) + M.transfer_to(mob, TRUE) + + if(!leader && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job)) + leader = mob + to_chat(mob, SPAN_ROLE_HEADER("You are a Weyland-Yutani Corporate Security Lead!")) + arm_equipment(mob, /datum/equipment_preset/goon/lead, TRUE, TRUE) + else if(medics < max_medics && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(mob.client, JOB_SQUAD_MEDIC, time_required_for_job)) + medics++ + to_chat(mob, SPAN_ROLE_HEADER("You are a Weyland-Yutani Corporate Research Consultant!")) + arm_equipment(mob, /datum/equipment_preset/goon/researcher, TRUE, TRUE) + else + to_chat(mob, SPAN_ROLE_HEADER("You are a Weyland-Yutani Corporate Security Officer!")) + arm_equipment(mob, /datum/equipment_preset/goon/standard, TRUE, TRUE) + + print_backstory(mob) + + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), mob, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) + +/datum/emergency_call/goon/chem_retrieval/print_backstory(mob/living/carbon/human/backstory_human) + if(backstory_human.job == JOB_WY_GOON_RESEARCHER) + to_chat(backstory_human, SPAN_BOLD("You were born [pick(75;"in Europe", 15;"in Asia", 10;"on Mars")] to a wealthy family.")) + to_chat(backstory_human, SPAN_BOLD("Joining the ranks of Weyland-Yutani was the perfect way to further your research goals.")) + to_chat(backstory_human, SPAN_BOLD("You have a very in depth understanding of xenomorphs.")) + to_chat(backstory_human, SPAN_BOLD("You are a well educated scientist employed by Weyland-Yutani to study various non-humans.")) + to_chat(backstory_human, SPAN_BOLD("You heard about the original distress signal ages ago, but you have only just gotten permission from corporate to enter the area.")) + to_chat(backstory_human, SPAN_BOLD("Your only goal is to recover the chemical aboard the Almayer. Do whatever you have to do.")) + else + to_chat(backstory_human, SPAN_BOLD("You were born [pick(75;"in Europe", 15;"in Asia", 10;"on Mars")] to a poor family.")) + to_chat(backstory_human, SPAN_BOLD("Joining the ranks of Weyland-Yutani was all you could do to keep yourself and your loved ones fed.")) + to_chat(backstory_human, SPAN_BOLD("You have had a basic brief on xenomorphs.")) + to_chat(backstory_human, SPAN_BOLD("You are a simple security officer employed by Weyland-Yutani to guard their outposts and colonies.")) + to_chat(backstory_human, SPAN_BOLD("You heard about the original distress signal ages ago, but you have only just gotten permission from corporate to enter the area.")) + to_chat(backstory_human, SPAN_BOLD("Ensure no damage is incurred against Weyland-Yutani. Make sure the researcher is kept safe and follow their instructions.")) + /datum/emergency_call/goon/platoon name = "Weyland-Yutani Corporate Security (Platoon)" mob_min = 8 diff --git a/code/datums/emergency_calls/hefa_knight.dm b/code/datums/emergency_calls/hefa_knight.dm index 5109db2f99fb..2af2f99f443e 100644 --- a/code/datums/emergency_calls/hefa_knight.dm +++ b/code/datums/emergency_calls/hefa_knight.dm @@ -3,7 +3,7 @@ name = "HEFA knights" mob_max = 15 mob_min = 3 - arrival_message = "Intercepted Transmission: 'Prepaerth to surrender thine HEFAs unto the order!'" + arrival_message = "'Prepaerth to surrender thine HEFAs unto the order!'" objectives = "You are a Brother of the Order of HEFA! You and your fellow brothers must retrieve as many HEFAs as possible!" probability = 0 hostility = TRUE diff --git a/code/datums/emergency_calls/inspection.dm b/code/datums/emergency_calls/inspection.dm index 1224818d40e4..72926666ace5 100644 --- a/code/datums/emergency_calls/inspection.dm +++ b/code/datums/emergency_calls/inspection.dm @@ -183,7 +183,7 @@ /datum/emergency_call/inspection_cmb/New() ..() - arrival_message = "Incoming Transmission: [MAIN_SHIP_NAME], This is Anchorpoint Station with the Colonial Marshal Bureau. Be advised, a CMB transport vessel is preparing to board you, submitting Federal docking clearances now. Standby." + arrival_message = "[MAIN_SHIP_NAME], This is Anchorpoint Station with the Colonial Marshal Bureau. Be advised, a CMB transport vessel is preparing to board you, submitting Federal docking clearances now. Standby." objectives = "Get your instructions from the CMB Office at Anchorpoint Station, and carry out your orders. Ensure that Colonial assets are safe and in your custody. Do not enforce or override Marine Law on a Marine Ship unless requested, as it's outside of your juristiction." will_spawn_icc_liaison = prob(90) diff --git a/code/datums/emergency_calls/pirates.dm b/code/datums/emergency_calls/pirates.dm index bb88261c9be5..7a9d333de970 100644 --- a/code/datums/emergency_calls/pirates.dm +++ b/code/datums/emergency_calls/pirates.dm @@ -4,7 +4,7 @@ name = "Fun - Pirates" mob_max = 35 mob_min = 10 - arrival_message = "Intercepted Transmission: 'What shall we do with a drunken sailor? What shall we do with a drunken sailor? What shall we do with a drunken sailor early in the morning?'" + arrival_message = "'What shall we do with a drunken sailor? What shall we do with a drunken sailor? What shall we do with a drunken sailor early in the morning?'" objectives = "Pirate! Loot! Ransom!" probability = 0 hostility = TRUE diff --git a/code/datums/emergency_calls/pizza.dm b/code/datums/emergency_calls/pizza.dm index ea5065dafc29..a35ce584c68d 100644 --- a/code/datums/emergency_calls/pizza.dm +++ b/code/datums/emergency_calls/pizza.dm @@ -4,7 +4,7 @@ name = "Pizza Delivery" mob_max = 1 mob_min = 1 - arrival_message = "Incoming Transmission: 'That'll be... sixteen orders of cheesy fries, eight large double topping pizzas, nine bottles of Four Loko... hello? Is anyone on this ship? Your pizzas are getting cold.'" + arrival_message = "'That'll be... sixteen orders of cheesy fries, eight large double topping pizzas, nine bottles of Four Loko... hello? Is anyone on this ship? Your pizzas are getting cold.'" objectives = "Make sure you get a tip!" shuttle_id = "Distress_Small" name_of_spawn = /obj/effect/landmark/ert_spawns/distress_pizza diff --git a/code/datums/emergency_calls/pmc.dm b/code/datums/emergency_calls/pmc.dm index 37347dcbc058..a06b0cc0c02e 100644 --- a/code/datums/emergency_calls/pmc.dm +++ b/code/datums/emergency_calls/pmc.dm @@ -99,13 +99,13 @@ /datum/emergency_call/pmc/chem_retrieval/New() ..() - dispatch_message = "[MAIN_SHIP_NAME], this is USCSS Royce. Our squad is boarding to retrieve all samples of a chemical recently scanned from your research department. You should already have received a significant sum of money for your department's discovery. In return we ask that you cooperate and provide everything related to the chemical to our retrieval team. If you do not cooperate, the team is authorized to use lethal force and terminate the research department." + dispatch_message = "[MAIN_SHIP_NAME], this is USCSS Royce. We are sending a second squad aboard to retrieve all samples of a chemical recently scanned from your research department. If you do not cooperate, the team is authorized to use lethal force and terminate the research department." objectives = "Secure all documents, samples and chemicals containing the property DNA_Disintegrating from [MAIN_SHIP_NAME] research department." /datum/emergency_call/pmc/chem_retrieval/proc/check_objective_info() if(objective_info) objectives = "Secure all documents, samples and chemicals related to [objective_info] from [MAIN_SHIP_NAME] research department." - objectives += "Assume at least 30 units are located within the department. If they can not make more that should be all. Cooperate with the onboard CL to ensure all who know the complete recipe are kept silenced with a contract of confidentiality. All humans who have ingested the chemical must be brought back dead or alive. Viral scan is required for any humans who is suspected of ingestion. Full termination of the department is authorized if they do not cooperate, but this should be avoided UNLESS ABSOLUTELY NECESSARY. Assisting with [MAIN_SHIP_NAME] current operation is only allowed after successful retrieval and with a signed contract between the CL and acting commander of [MAIN_SHIP_NAME]." + objectives += "Assume at least 30 units are located within the department. If they can not make more that should be all. Cooperate with the onboard Wey-Yu researcher to ensure all who know the complete recipe are kept silenced with a contract of confidentiality. All humans who have ingested the chemical must be brought back dead or alive. Viral scan is required for any humans who is suspected of ingestion. Full termination of the department is authorized if they do not cooperate, but this should be avoided UNLESS ABSOLUTELY NECESSARY." checked_objective = TRUE /datum/emergency_call/pmc/chem_retrieval/create_member(datum/mind/M, turf/override_spawn_loc) diff --git a/code/datums/emergency_calls/provost.dm b/code/datums/emergency_calls/provost.dm index 65bbb9753da7..92c33706c178 100644 --- a/code/datums/emergency_calls/provost.dm +++ b/code/datums/emergency_calls/provost.dm @@ -4,9 +4,11 @@ name = "USCM Provost Enforcers" mob_max = 5 mob_min = 5 - objectives = "Deploy to the USS Almayer and enforce Marine Law." probability = 0 +/datum/emergency_call/provost_enforcer/New() + objectives = "Deploy to the [MAIN_SHIP_NAME] and enforce Marine Law." + return ..() /datum/emergency_call/provost_enforcer/create_member(datum/mind/M, turf/override_spawn_loc) var/turf/T = override_spawn_loc ? override_spawn_loc : get_spawn_point() diff --git a/code/datums/emergency_calls/souto.dm b/code/datums/emergency_calls/souto.dm index c41049624bf2..44aa5284b862 100644 --- a/code/datums/emergency_calls/souto.dm +++ b/code/datums/emergency_calls/souto.dm @@ -4,10 +4,13 @@ name = "Souto Man" mob_max = 1 mob_min = 1 - arrival_message = "Incoming Transmission: Give a round of applause for the marine who sent in ten-thousand Souto tabs to get me here! USS Almayer, Souto Man's here to party with YOU!" objectives = "Party like it's 1999!" probability = 0 +/datum/emergency_call/souto/New() + arrival_message = "Give a round of applause for the marine who sent in ten-thousand Souto tabs to get me here! [MAIN_SHIP_NAME], Souto Man's here to party with YOU!" + return ..() + /datum/emergency_call/souto/create_member(datum/mind/M, turf/override_spawn_loc) var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() diff --git a/code/datums/emergency_calls/tank_crew.dm b/code/datums/emergency_calls/tank_crew.dm index b033c263e86d..fb437c179e48 100644 --- a/code/datums/emergency_calls/tank_crew.dm +++ b/code/datums/emergency_calls/tank_crew.dm @@ -25,6 +25,7 @@ arm_equipment(H, /datum/equipment_preset/uscm/tank/full, TRUE, TRUE) to_chat(H, SPAN_ROLE_HEADER("You are a Vehicle Crewman in the USCM")) to_chat(H, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command.")) + to_chat(H, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced.")) sleep(10) to_chat(H, SPAN_BOLD("Objectives: [objectives]")) diff --git a/code/datums/emergency_calls/xeno_cultists.dm b/code/datums/emergency_calls/xeno_cultists.dm index 247b6b3a1881..e5ebf089a9c2 100644 --- a/code/datums/emergency_calls/xeno_cultists.dm +++ b/code/datums/emergency_calls/xeno_cultists.dm @@ -2,7 +2,7 @@ /datum/emergency_call/xeno_cult name = "Xeno Cultists" mob_max = 6 - arrival_message = "Incoming Transmission: 'Ia! Ia!'" + arrival_message = "'Ia! Ia!'" objectives = "Support the Xenomorphs in any way, up to and including giving your life for them!" probability = 0 hostility = TRUE diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 5544ab0807d0..b691d87a2169 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -101,7 +101,7 @@ return if(!HAS_TRAIT(user, TRAIT_EMOTE_CD_EXEMPT)) TIMER_COOLDOWN_START(user, type, audio_cooldown) - TIMER_COOLDOWN_START(user, COOLDOWN_MOB_AUDIO, 20 SECONDS) + S_TIMER_COOLDOWN_START(user, COOLDOWN_MOB_AUDIO, 20 SECONDS) // We won't ever want to stop this except during qdel playsound(user, tmp_sound, volume, vary) log_emote("[user.name]/[user.key] : [msg ? msg : key]") diff --git a/code/datums/entities/discord_identifier.dm b/code/datums/entities/discord_identifier.dm new file mode 100644 index 000000000000..7475af74ae3c --- /dev/null +++ b/code/datums/entities/discord_identifier.dm @@ -0,0 +1,45 @@ +/datum/entity/discord_identifier + var/identifier + var/playerid + var/realtime + var/used = FALSE + +/datum/entity/discord_identifier/New() + . = ..() + + realtime = world.realtime + +/datum/entity_meta/discord_identifier + entity_type = /datum/entity/discord_identifier + table_name = "discord_identifiers" + key_field = "identifier" + + field_types = list( + "identifier" = DB_FIELDTYPE_STRING_LARGE, + "playerid" = DB_FIELDTYPE_BIGINT, + "realtime" = DB_FIELDTYPE_BIGINT, + "used" = DB_FIELDTYPE_INT, + ) + +/datum/view_record/discord_identifier + var/identifier + var/playerid + var/realtime + var/used + +/datum/entity_view_meta/discord_identifier + root_record_type = /datum/entity/discord_identifier + destination_entity = /datum/view_record/discord_identifier + fields = list( + "identifier", + "playerid", + "realtime", + "used", + ) + order_by = list("identifier" = DB_ORDER_BY_ASC) + +/proc/get_discord_identifier_by_token(token) + var/datum/entity/discord_identifier/ident = DB_EKEY(/datum/entity/discord_identifier, token) + ident.save() + ident.sync() + return ident diff --git a/code/datums/entities/discord_link.dm b/code/datums/entities/discord_link.dm new file mode 100644 index 000000000000..c11fe15c2f68 --- /dev/null +++ b/code/datums/entities/discord_link.dm @@ -0,0 +1,38 @@ +/datum/entity/discord_link + var/player_id + var/discord_id + +/datum/entity_meta/discord_link + entity_type = /datum/entity/discord_link + table_name = "discord_links" + key_field = "discord_id" + + field_types = list( + "player_id" = DB_FIELDTYPE_BIGINT, + "discord_id" = DB_FIELDTYPE_STRING_MEDIUM, + ) + +/datum/view_record/discord_link + var/id + var/player_id + var/discord_id + +/datum/entity_view_meta/discord_link + root_record_type = /datum/entity/discord_link + destination_entity = /datum/view_record/discord_link + fields = list( + "id", + "player_id", + "discord_id", + ) + order_by = list("player_id" = DB_ORDER_BY_ASC) + +/datum/entity_link/player_to_discord + parent_entity = /datum/entity/player + child_entity = /datum/entity/discord_link + child_field = "player_id" + + parent_name = "player" + child_name = "discord_link_id" + + diff --git a/code/datums/entities/login_triplets.dm b/code/datums/entities/login_triplets.dm index a07febbc940d..545f83b90c77 100644 --- a/code/datums/entities/login_triplets.dm +++ b/code/datums/entities/login_triplets.dm @@ -21,6 +21,81 @@ "login_date" = DB_FIELDTYPE_DATE, ) +/datum/view_record/login_triplet + var/ckey + var/ip1 + var/ip2 + var/ip3 + var/ip4 + + var/last_known_cid + var/login_date + +/datum/entity_view_meta/login_triplet + root_record_type = /datum/entity/login_triplet + destination_entity = /datum/view_record/login_triplet + fields = list( + "ckey", + "ip1", + "ip2", + "ip3", + "ip4", + "last_known_cid", + "login_date", + ) + order_by = list("ckey" = DB_ORDER_BY_ASC) + +/proc/analyze_ckey(ckey) + for(var/ip in ips_by_ckey(ckey)) + LAZYOR(., ckeys_by_ip(ip) - ckey) + + for(var/cid in cids_by_ckey(ckey)) + LAZYOR(., ckeys_by_cid(cid) - ckey) + +/proc/cids_by_ckey(ckey) + for(var/datum/view_record/login_triplet/triplet in search_login_triplet_by_ckey(ckey)) + LAZYOR(., triplet.last_known_cid) + +/proc/ips_by_ckey(ckey) + for(var/datum/view_record/login_triplet/triplet in search_login_triplet_by_ckey(ckey)) + LAZYOR(., "[triplet.ip1].[triplet.ip2].[triplet.ip3].[triplet.ip4]") + +/proc/ckeys_by_ip(ip) + for(var/datum/view_record/login_triplet/triplet in search_login_triplet_by_ip(ip)) + LAZYOR(., triplet.ckey) + +/proc/ckeys_by_cid(cid) + for(var/datum/view_record/login_triplet/triplet in search_login_triplet_by_cid(cid)) + LAZYOR(., triplet.ckey) + +/proc/search_login_triplet_by_ckey(ckey) + if(!ckey) + CRASH("No ckey passed to /proc/search_login_triplet_by_ckey") + + return DB_VIEW(/datum/view_record/login_triplet, DB_COMP("ckey", DB_EQUALS, ckey)) + +/proc/search_login_triplet_by_ip(ip) + if(!ip) + CRASH("No IP passed to /proc/search_login_triplet_by_ip") + + var/split_ip = splittext(ip, ".") + if(length(split_ip) != 4) + CRASH("Invalid IP passed to /proc/search_login_triplet_by_ip") + + return DB_VIEW(/datum/view_record/login_triplet, + DB_AND( + DB_COMP("ip1", DB_EQUALS, split_ip[1]), + DB_COMP("ip2", DB_EQUALS, split_ip[2]), + DB_COMP("ip3", DB_EQUALS, split_ip[3]), + DB_COMP("ip4"), DB_EQUALS, split_ip[4] + )) + +/proc/search_login_triplet_by_cid(cid) + if(!cid) + CRASH("No CID passed to /proc/search_login_triplet_by_cid") + + return DB_VIEW(/datum/view_record/login_triplet, DB_COMP("last_known_cid", DB_EQUALS, cid)) + /proc/record_login_triplet(ckey, last_known_ip, last_known_cid) var/datum/entity/login_triplet/LT = DB_ENTITY(/datum/entity/login_triplet) LT.ckey = ckey diff --git a/code/datums/entities/player.dm b/code/datums/entities/player.dm index 7b14d43eb208..ed97c4eafaae 100644 --- a/code/datums/entities/player.dm +++ b/code/datums/entities/player.dm @@ -5,6 +5,8 @@ var/last_known_ip var/last_known_cid + var/discord_link_id + var/last_login var/is_permabanned = FALSE @@ -37,6 +39,7 @@ var/migrating_bans = FALSE var/migrating_jobbans = FALSE + var/datum/entity/discord_link/discord_link var/datum/entity/player/permaban_admin var/datum/entity/player/time_ban_admin var/list/datum/entity/player_note/notes @@ -60,6 +63,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player) "is_permabanned" = DB_FIELDTYPE_INT, "permaban_reason" = DB_FIELDTYPE_STRING_MAX, "permaban_date" = DB_FIELDTYPE_STRING_LARGE, + "discord_link_id" = DB_FIELDTYPE_BIGINT, "permaban_admin_id" = DB_FIELDTYPE_BIGINT, "is_time_banned" = DB_FIELDTYPE_INT, "time_ban_reason" = DB_FIELDTYPE_STRING_MAX, @@ -101,6 +105,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player) note.player_id = id note.text = note_text note.date = "[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]" + note.round_id = GLOB.round_id note.is_confidential = is_confidential note.note_category = note_category note.is_ban = is_ban @@ -133,6 +138,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player) message_admins("[key_name_admin(admin)] deleted one of [ckey]'s notes.") // get note from our list var/datum/entity/player_note/note = DB_ENTITY(/datum/entity/player_note, note_id) + log_admin("Note: [note.text] by [note.admin]") // de-list it notes.Remove(note) // murder it @@ -382,6 +388,8 @@ BSQL_PROTECT_DATUM(/datum/entity/player) permaban_admin = DB_ENTITY(/datum/entity/player, permaban_admin_id) if(time_ban_admin_id) time_ban_admin = DB_ENTITY(/datum/entity/player, time_ban_admin_id) + if(discord_link_id) + discord_link = DB_ENTITY(/datum/entity/discord_link, discord_link_id) @@ -664,10 +672,11 @@ BSQL_PROTECT_DATUM(/datum/entity/player) parent_name = "permabanning_admin" -/datum/view_record/player_ban_view +/datum/view_record/players var/id var/ckey var/is_permabanned + var/is_time_banned var/ban_type var/reason var/date @@ -675,19 +684,22 @@ BSQL_PROTECT_DATUM(/datum/entity/player) var/admin var/last_known_cid var/last_known_ip + var/discord_link_id -/datum/entity_view_meta/timed_ban_list +/datum/entity_view_meta/players root_record_type = /datum/entity/player - destination_entity = /datum/view_record/player_ban_view + destination_entity = /datum/view_record/players fields = list( "id", "ckey", "is_permabanned", // this one for the machine + "is_time_banned", "ban_type" = DB_CASE(DB_COMP("is_permabanned", DB_EQUALS, 1), DB_CONST("permaban"), DB_CONST("timed ban")), // this one is readable "reason" = DB_CASE(DB_COMP("is_permabanned", DB_EQUALS, 1), "permaban_reason", "time_ban_reason"), "date" = DB_CASE(DB_COMP("is_permabanned", DB_EQUALS, 1), "permaban_date", "time_ban_date"), "expiration" = "time_ban_expiration", //don't care if this is permaban, since it will be handled later "admin" = DB_CASE(DB_COMP("is_permabanned", DB_EQUALS, 1), "permabanning_admin.ckey", "banning_admin.ckey"), "last_known_ip", - "last_known_cid") - root_filter = DB_OR(DB_COMP("is_permabanned", DB_EQUALS, 1), DB_COMP("is_time_banned", DB_EQUALS, 1)) + "last_known_cid", + "discord_link_id", + ) diff --git a/code/datums/entities/player_note.dm b/code/datums/entities/player_note.dm index 6e3057ec50ab..420bb5f0a470 100644 --- a/code/datums/entities/player_note.dm +++ b/code/datums/entities/player_note.dm @@ -1,8 +1,11 @@ +#define NOTE_ROUND_ID(note_entity) note_entity.round_id ? "(ID: [note_entity.round_id])" : "" + /datum/entity/player_note var/player_id var/admin_id var/text var/date + var/round_id var/is_ban = FALSE var/ban_time var/is_confidential = FALSE @@ -19,15 +22,16 @@ BSQL_PROTECT_DATUM(/datum/entity/player_note) entity_type = /datum/entity/player_note table_name = "player_notes" field_types = list( - "player_id"=DB_FIELDTYPE_BIGINT, - "admin_id"=DB_FIELDTYPE_BIGINT, - "text"=DB_FIELDTYPE_STRING_MAX, - "date"=DB_FIELDTYPE_STRING_LARGE, - "is_ban"=DB_FIELDTYPE_INT, - "ban_time"=DB_FIELDTYPE_BIGINT, - "is_confidential"=DB_FIELDTYPE_INT, - "admin_rank"=DB_FIELDTYPE_STRING_MEDIUM, - "note_category" =DB_FIELDTYPE_INT, + "player_id" = DB_FIELDTYPE_BIGINT, + "admin_id" = DB_FIELDTYPE_BIGINT, + "text" = DB_FIELDTYPE_STRING_MAX, + "date" = DB_FIELDTYPE_STRING_LARGE, + "round_id" = DB_FIELDTYPE_BIGINT, + "is_ban" = DB_FIELDTYPE_INT, + "ban_time" = DB_FIELDTYPE_BIGINT, + "is_confidential" = DB_FIELDTYPE_INT, + "admin_rank" = DB_FIELDTYPE_STRING_MEDIUM, + "note_category" = DB_FIELDTYPE_INT, ) /datum/entity_meta/player_note/on_read(datum/entity/player_note/note) @@ -64,6 +68,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player_note) var/is_ban var/admin_ckey var/date + var/round_id var/ban_time var/is_confidential var/admin_rank @@ -79,8 +84,14 @@ BSQL_PROTECT_DATUM(/datum/entity/player_note) "is_ban", "admin_ckey" = "admin.ckey", "date", + "round_id", "ban_time", "is_confidential", "admin_rank", "note_category" ) + +/// Returns all notes associated with a CKEY, structured as a list of strings. +/proc/get_all_notes(player_ckey) + for(var/datum/view_record/note_view/note in DB_VIEW(/datum/view_record/note_view, DB_COMP("player_ckey", DB_EQUALS, player_ckey))) + LAZYADDASSOC(., "[note.note_category]", "\"[note.text]\", by [note.admin_ckey] ([note.admin_rank]) on [note.date] ([note.round_id])") diff --git a/code/datums/entities/player_times.dm b/code/datums/entities/player_times.dm index a5c6b1ea7b32..a6304bd5d874 100644 --- a/code/datums/entities/player_times.dm +++ b/code/datums/entities/player_times.dm @@ -136,3 +136,8 @@ BSQL_PROTECT_DATUM(/datum/entity/player_time) LAZYSET(playtime_data, "loading", FALSE) LAZYSET(playtime_data, "loaded", TRUE) + +/// Returns the total time in minutes a specific player ID has played for +/proc/get_total_living_playtime(player_id) + for(var/datum/view_record/playtime/time in DB_VIEW(/datum/view_record/playtime, DB_AND(DB_COMP("player_id", DB_EQUALS, player_id), DB_COMP("role_id", DB_NOTEQUAL, "Observer")))) + . += time.total_minutes diff --git a/code/datums/entities/ticket.dm b/code/datums/entities/ticket.dm index 6a8b67e09195..e34bf4241b2c 100644 --- a/code/datums/entities/ticket.dm +++ b/code/datums/entities/ticket.dm @@ -36,3 +36,6 @@ BSQL_PROTECT_DATUM(/datum/entity/ticket) ticket_ent.round_id = SSperf_logging.round?.id ticket_ent.save() ticket_ent.detach() + + REDIS_PUBLISH("byond.ticket", "ticket-id" = ticket, "action" = action, "message" = message, "recipient" = recipient, "sender" = sender, "urgent" = urgent) + diff --git a/code/datums/factions/uscm.dm b/code/datums/factions/uscm.dm index 2df95df836a9..cf77142ce5d6 100644 --- a/code/datums/factions/uscm.dm +++ b/code/datums/factions/uscm.dm @@ -2,21 +2,21 @@ name = "United States Colonial Marines" faction_tag = FACTION_MARINE -/datum/faction/uscm/modify_hud_holder(image/holder, mob/living/carbon/human/H) - var/datum/squad/squad = H.assigned_squad +/datum/faction/uscm/modify_hud_holder(image/holder, mob/living/carbon/human/current_human) + var/datum/squad/squad = current_human.assigned_squad if(istype(squad)) - var/squad_clr = squad_colors[H.assigned_squad.color] + var/squad_clr = current_human.assigned_squad.equipment_color var/marine_rk - var/obj/item/card/id/I = H.get_idcard() + var/obj/item/card/id/I = current_human.get_idcard() var/_role - if(H.job) - _role = H.job + if(current_human.job) + _role = current_human.job else if(I) _role = I.rank switch(GET_DEFAULT_ROLE(_role)) if(JOB_SQUAD_ENGI) marine_rk = "engi" if(JOB_SQUAD_SPECIALIST) marine_rk = "spec" - if(JOB_SQUAD_RTO) marine_rk = "rto" + if(JOB_SQUAD_TEAM_LEADER) marine_rk = "tl" if(JOB_SQUAD_MEDIC) marine_rk = "med" if(JOB_SQUAD_SMARTGUN) marine_rk = "gun" if(JOB_XO) marine_rk = "xo" @@ -29,45 +29,45 @@ if(JOB_MARINE_RAIDER) marine_rk = "soc" if(JOB_MARINE_RAIDER_SL) marine_rk = "soctl" if(JOB_MARINE_RAIDER_CMD) marine_rk = "soccmd" - if(squad.squad_leader == H) + if(squad.squad_leader == current_human) switch(squad.squad_type) if("Squad") marine_rk = "leader_a" if("Team") marine_rk = "soctl_a" - H.langchat_styles = "langchat_bolded" // bold text for bold leaders + current_human.langchat_styles = "langchat_bolded" // bold text for bold leaders else - H.langchat_styles = initial(H.langchat_styles) + current_human.langchat_styles = initial(current_human.langchat_styles) - H.langchat_color = squad_colors_chat[H.assigned_squad.color] + current_human.langchat_color = current_human.assigned_squad.chat_color - if(!marine_rk) marine_rk = H.rank_fallback + if(!marine_rk) marine_rk = current_human.rank_fallback if(marine_rk) - var/image/IMG = image('icons/mob/hud/marine_hud.dmi', H, "hudsquad") + var/image/IMG = image('icons/mob/hud/marine_hud.dmi', current_human, "hudsquad") if(squad_clr) IMG.color = squad_clr else IMG.color = "#5A934A" holder.overlays += IMG - holder.overlays += image('icons/mob/hud/marine_hud.dmi', H, "hudsquad_[marine_rk]") - if(H.assigned_squad && H.assigned_fireteam) - var/image/IMG2 = image('icons/mob/hud/marine_hud.dmi', H, "hudsquad_[H.assigned_fireteam]") + holder.overlays += image('icons/mob/hud/marine_hud.dmi', current_human, "hudsquad_[marine_rk]") + if(current_human.assigned_squad && current_human.assigned_fireteam) + var/image/IMG2 = image('icons/mob/hud/marine_hud.dmi', current_human, "hudsquad_[current_human.assigned_fireteam]") IMG2.color = squad_clr holder.overlays += IMG2 - if(H.assigned_squad.fireteam_leaders[H.assigned_fireteam] == H) - var/image/IMG3 = image('icons/mob/hud/marine_hud.dmi', H, "hudsquad_ftl") + if(current_human.assigned_squad.fireteam_leaders[current_human.assigned_fireteam] == current_human) + var/image/IMG3 = image('icons/mob/hud/marine_hud.dmi', current_human, "hudsquad_ftl") IMG3.color = squad_clr holder.overlays += IMG3 else var/marine_rk var/border_rk var/icon_prefix = "hudsquad_" - var/obj/item/card/id/ID = H.get_idcard() + var/obj/item/card/id/ID = current_human.get_idcard() var/_role - if(H.mind) - _role = H.job + if(current_human.mind) + _role = current_human.job else if(ID) _role = ID.rank - switch(GET_DEFAULT_ROLE(_role)) + switch(_role) if(JOB_XO) marine_rk = "xo" border_rk = "command" @@ -77,6 +77,9 @@ if(JOB_SO) marine_rk = "so" border_rk = "command" + if(JOB_AUXILIARY_OFFICER) + marine_rk = "aso" + border_rk = "command" if(JOB_GENERAL, JOB_COLONEL, JOB_ACMC, JOB_CMC) marine_rk = "general" border_rk = "command" @@ -188,9 +191,9 @@ icon_prefix = "cmb_" if(marine_rk) - var/image/I = image('icons/mob/hud/marine_hud.dmi', H, "hudsquad") + var/image/I = image('icons/mob/hud/marine_hud.dmi', current_human, "hudsquad") I.color = "#5A934A" holder.overlays += I - holder.overlays += image('icons/mob/hud/marine_hud.dmi', H, "[icon_prefix][marine_rk]") + holder.overlays += image('icons/mob/hud/marine_hud.dmi', current_human, "[icon_prefix][marine_rk]") if(border_rk) - holder.overlays += image('icons/mob/hud/marine_hud.dmi', H, "hudmarineborder[border_rk]") + holder.overlays += image('icons/mob/hud/marine_hud.dmi', current_human, "hudmarineborder[border_rk]") diff --git a/code/datums/fluff_emails.dm b/code/datums/fluff_emails.dm index 6dd8cd590860..f7083541dd5a 100644 --- a/code/datums/fluff_emails.dm +++ b/code/datums/fluff_emails.dm @@ -93,9 +93,9 @@ /datum/fluff_email/almayer/themajor title = "The Major?" entry_text = {" - I keep forgetting what the new Major's name is. I got quizzed by one of the jackass staff officers last week about the captain's name, - and I absolutely spilled my marbles. PCF Mable was watching too, and she probably thinks I've got rocks in my head. I know it's been weeks - since the new captain took over, but for some reason the name keeps escaping me when it matters. Either the cryo-sleepers are juicing my + I keep forgetting what the new Major's name is. I got quizzed by one of the jackass staff officers last week about the Major's name, + and I absolutely spilled my marbles. PFC Mable was watching too, and she probably thinks I've got rocks in my head. I know it's been weeks + since the new Major took over, but for some reason the name keeps escaping me when it matters. Either the cryo-sleepers are juicing my memory capacity or the CO keeps changing their name and not telling anybody. Maybe next jump I'll scrawl it on a sticky note and plaster it to the inside of my sleeper pod. I can't be the only one having this problem. @@ -105,7 +105,8 @@ /datum/fluff_email/almayer/tunes title = "RE: Tunes" entry_text = {" - Cryosleep is killing me, man. Inside and outside. I mean really, they expect us to sit in that tube for god only knows how long, and when we wake up? It's all 'grab a crappy protein bar and grab your gear, you're going to war, Marine!' Bullshit. + Cryosleep is killing me, man. Inside and outside. I mean really, they expect us to sit in that tube for god only knows how long, and when we wake up? + It's all 'grab a crappy protein bar and grab your gear, you're going to war, Marine!' Bullshit.

Anywho, I've been thinking how to make the whole thing more bearable. Tried to take a plush from the bunks with me inside. That dickwad MP took it away from me though, said it was against Operating Procedure. Like I care. Can't do anything fun around here, right? @@ -113,82 +114,81 @@ I don't usually use these things, and frankly that vendor near Medbay has waaay too many cassettes to choose from. Not that I know most songs on them anywho.

- I saw you with a Walkman from time to time, so... any chances you could recommend a tape to me? Or two, I'm not gonna be picky. Just anything to start out with, I just want some nice sounds. Please, I'm gonna go mad if I don't do something about my cryophobia or whatever. This might just help with that. + I saw you with a Walkman from time to time, so... any chances you could recommend a tape to me? Or two, I'm not gonna be picky. + Just anything to start out with, I just want some nice sounds. Please, I'm gonna go mad if I don't do something about my cryophobia or whatever. + This might just help with that. "} -/datum/fluff_email/almayer/lasergun - title = "RE: Lasergun" +/datum/fluff_email/almayer/lasergun1 + title = "Prototype Weapon" entry_text = {" - Hey REDACTED. Thanks for letting me test out the laser gun. That thing is a factual blast to use. It literally set the targets down range on fire! Those cooling coils work wonders. Used it a good few times and the barrel didn't explode! + This thing is an absolute blast to use. + It disintegrated some of the targets down range but you're going to need to work on those cooling coils. + I used it a few times and I'm seeing the front barrel glow red.

- Hell, it's even pretty accurate too. I know there's like, a couple of prototypes issued to some USCM detachments but we got to have this shit in production one day. It's just good. Now, I don't think it's gonna replace the old Mark two's but it would be a nice addition for some of our grunts that prefer the high tech approach. You know the ones, all nerdy and gadget loving geeks in the corps. Hell I can already hear them glossing over this thing in their sleep. + Surprisingly accurate too despite being a prototype. + I know there's like, a couple of prototypes issued to some USCM detachments, but we got to have this shit in production one day.

- Anyway, I've already attached the weapon report you wanted on this thing back to the email. Hopefully you guys in R&D will get some useful info out of it. + Even as a prototype, it's leagues better than some of the junk we're issued. + Now, I don't think it's going to replace the old Mark Twos, but it would be a nice addition for some of our grunts that prefer the high-tech approach.
- Alright see you when I see you - REDACTED
-
- RE:RE: The Plasma Gun (It's called the XM99 Phased Plasma Pulse Rifle) - Hey REDACTED, REDACTED here. Thanks for the report but I'm going to need you to send the Phased Plasma Pulse Rifle back to me. Apparently we're not allowed to ship them out for testing... I guess I must've missed that memo. The memo came three days after I shipped it out to you. Sorry for the inconvenience. You know where to send it back to and how to. I did tell you how right? There was a small pamphlet in the casing if you forgot. -
-
- Don't think this is going to be issued en masse for a while, it's still going under trials and when I got the weapon report you sent me, they sent in a new updated design for the gun which invalidated most of the things in the report, shame. Looks more promising than the last one though. -
-
- Okay, I'll hopefully be seeing the XM99 Phased Plasma Pulse Rifle in the lab soon. -
-
- REDACTED RE:RE:RE: The Plasma Gun (It's called the XM99 Phased Plasma Pulse Rifle) -
- Holy shit, what the fuck did you do to the damned thing? When I opened the case, I could see fractures and scratches everywhere! Did you give this to the entire platoon to try out? And from the data I'm reading, you fired over 178 shots with this. I only gave you two batteries for the thing. -
-
- How the hell did you recharge it?! The prototype can't take any other forms of power other than those two batteries. And even then, you can't recharge those specially made batteries either without the equipment back in the lab here. And the inside of the barrel is all messed up man. The cooling coils expired and there're bits of the barrel loose inside of it. How the hell did you not notice bits of the inside of the barrel spewing out from the muzzle man?! -
-
- Right. They've threatened to drop me from the project if something like this happens again. In the rare case that I send another prototype out, it had better come back in one piece. And I mean in pristine condition, you got that? -
-
Regards, -
REDACTED + You know the ones, all nerdy and gadget loving geeks in the corps. Hell, I can already hear them glossing over this thing in their sleep. + My report has been sent back to you and I'm really excited to see how this turns out. + + "} + + +/datum/fluff_email/almayer/lasergun2 + title = "New Prototype Design" + entry_text = {" + Thanks for sending the report in, we've been mulling over the data you sent over. + We've updated the design for the prototype which solves most of the problems everyone has encountered. + This one looks more promising than the last one. + And as much as everyone wants this done and shippped, I don't think this is going to be issued en masse for a good while. "} /datum/fluff_email/almayer/beatup - title = "RE: Beat Up" + title = "Beat Up" entry_text = {" - Yo. -
-
- Man, last mission was an absolute shit show. The USS Heyst got their shit kicked in with a missile and we got our cargo hold set on fire by that damn suicide craft. They even blew up most of our good ammo too! Now we're left with the soft point backup munitions. Shit, most of 1st platoon is pretty much out of action. Lotta folks are in sickbay and the rest of us are heading off to cryosleep, well what's left of us. -
-
- When the comms got cut and we were cut off from command; Squad Foxtrot was immediately ambushed on the logistics route to get supplies in and out of the combat zone. I suspect they were taping into your comms to find the literal perfect moment to fuck with our logistics. Thankfully those trucks of ours had their engines tricked out by the techies back on LV-176 in the civilian garage. Those guys hosted rally races around their colony and Sergeant DATA EXPUNGED won a few races for us. Instead of taking their trophy, he pulled a few favors to get our trucks pimped out with better engines. We owe our lives to Sarge for winning one for the corps. -
-
- Hell, at least we're all going back to Chinook Station to get resupplied. Hopefully the wounded wake up to the docs on station rather than our poor and cramped excuse for a medical bay. The number of times the medbay has been packed with wounded where even the damn front lobby had bodies lining up on the sides of the walls waiting for treatment; it still amazes. Worse still was the stench from all the blood and guts, it made it hell for the maint. techs to clean up afterwards. -
- I'm still surprised those doctors we had on hand took care of most of them so quickly, even if most of them are still injured heading to the fridge. -
-
- I read the After-Action Report which the Heyst's XO did, and they're leaving out a few details. When it came to that city, they left out how we had to DATA EXPUNGED. The entire building collapsed with them in it too. Damn shame we couldn't save them. -
-
- The only damn silver lining i see in this shit is that the AI is going to cycle cryo again and we ain't waking to deal with whatever bullshit is happening next time. 2nd Platoon is dealing with that, cause 1st platoon is undermanned as is with our casualties. I heard they have a few screws loose, not that ours are entirely in either! But I don't care, it's their problem now y'know? -
-
- Worst case scenario, we don't wake up at all. -
- Right, see you back on station friend. -
-
- Regards, -
- REDACTED + Man last mission was an absolute shit show. +
+ The USS Heyst got their shit kicked in with a missile and we got our cargo hold set on fire. And most of our good ammo is gone too! + Now we're left with the FMJs and the older AP munitions. What's worse is that most of 1st platoon is pretty much out of action. + Lotta folks are in the sickbay and the rest of us are heading off to cryosleep, well what's left of us. There's not many of the old guard left I'm afraid. + Until we get reinforced with more bodies, command has given the go ahead to merge 2nd platoon into 1st for the time being. + + "} + + +/datum/fluff_email/almayer/rallyrace + title = "Rally Racing" + entry_text = {" + Hey, remember last shore leave on LV-179? Man, that was one crazy night. The folks at the colony had setup a rally race with their tractors all stripped of non-essentials. + LCPL Millard got pretty friendly with the locals and got himself into the competition. + We all put in a little wager to see if he'd even get close to first place or even survive to the finish line. + Now most of the boys bet a fair amount against him since he was pretty new to our outfit, yet I've been out on detail with the guy. +
+
+ Millard grew up on one of those shake and bake colonies and used to drive the big daisies around. + He knew the ins and outs of what made them tick. The few of us who had faith in him reaped everyone else's + paycheck for the week with Millard finishing first place by a near country mile. "} + +/datum/fluff_email/almayer/missing + title = "Missing Personnel" + entry_text = {" + Has anyone seen Mendoza around? He owes me half of his paycheck from last month's poker game. + Everyone's payday was a week ago and we're all set to head back to Chinook station. + Could have sworn I saw him near the cargo elevator yesterday. + I'll catch him back at base once we've docked because I need that money to pay off my tab at the bar. + + "} + diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 2104a76afc90..a2932532e78e 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -1,4 +1,4 @@ -GLOBAL_DATUM(revdata, /datum/getrev) +GLOBAL_DATUM_INIT(revdata, /datum/getrev, new) /datum/getrev var/commit // git rev-parse HEAD diff --git a/code/datums/keybinding/communication.dm b/code/datums/keybinding/communication.dm index 9a438fc6dabd..4164198d4818 100644 --- a/code/datums/keybinding/communication.dm +++ b/code/datums/keybinding/communication.dm @@ -42,13 +42,6 @@ full_name = "IC Comms (;)" keybind_signal = COMSIG_KG_CLIENT_RADIO_DOWN -/datum/keybinding/client/communication/mod_say - hotkey_keys = list("Unbound") - classic_keys = list("Unbound") - name = MOD_CHANNEL - full_name = "Mod Say" - keybind_signal = COMSIG_KB_ADMIN_ASAY_DOWN - /datum/keybinding/client/communication/asay hotkey_keys = list("F3") classic_keys = list("F5") diff --git a/code/datums/map_config.dm b/code/datums/map_config.dm index 65133a93d155..1f3c265ead76 100644 --- a/code/datums/map_config.dm +++ b/code/datums/map_config.dm @@ -23,13 +23,15 @@ var/traits = null var/space_empty_levels = 1 var/list/environment_traits = list() - var/armor_style = "default" var/list/gamemodes = list() + var/camouflage_type = "classic" + var/allow_custom_shuttles = TRUE var/shuttles = list() var/announce_text = "" + var/infection_announce_text = "" var/squads_max_num = 4 @@ -63,6 +65,9 @@ var/nightmare_path + /// If truthy this is config for a round overriden map: search for override maps in data/, instead of using a path in maps/ + var/override_map + /datum/map_config/New() survivor_types = list( /datum/equipment_preset/survivor/scientist, @@ -147,24 +152,35 @@ config_filename = filename + override_map = json["override_map"] + CHECK_EXISTS("map_name") map_name = json["map_name"] - CHECK_EXISTS("map_path") - map_path = json["map_path"] webmap_url = json["webmap_url"] short_name = json["short_name"] map_file = json["map_file"] + + var/dirpath = "maps/" + if(override_map) + dirpath = "data/" + map_path = "/" + map_file = OVERRIDE_MAPS_TO_FILENAME[maptype] + else + CHECK_EXISTS("map_path") + map_path = json["map_path"] + dirpath = "[dirpath]/[map_path]" + // "map_file": "BoxStation.dmm" if (istext(map_file)) - if (!fexists("maps/[map_path]/[map_file]")) + if (!fexists("[dirpath]/[map_file]")) log_world("Map file ([map_file]) does not exist!") return // "map_file": ["Lower.dmm", "Upper.dmm"] else if (islist(map_file)) for (var/file in map_file) - if (!fexists("maps/[map_path]/[file]")) + if (!fexists("[dirpath]/[file]")) log_world("Map file ([file]) does not exist!") return else @@ -303,8 +319,8 @@ allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE - if(json["armor"]) - armor_style = json["armor"] + if(json["camouflage"]) + camouflage_type = json["camouflage"] if(json["survivor_message"]) survivor_message = json["survivor_message"] @@ -324,6 +340,9 @@ if(json["announce_text"]) announce_text = json["announce_text"] + if(json["infection_announce_text"]) + infection_announce_text = json["infection_announce_text"] + if(json["weather_holder"]) weather_holder = text2path(json["weather_holder"]) if(!weather_holder) @@ -372,11 +391,14 @@ #undef CHECK_EXISTS /datum/map_config/proc/GetFullMapPaths() + var/dirpath = "maps/[map_path]" + if(override_map) + dirpath = "data/[map_path]" if (istext(map_file)) - return list("maps/[map_path]/[map_file]") + return list("[dirpath]/[map_file]") . = list() for (var/file in map_file) - . += "maps/[map_path]/[file]" + . += "[dirpath]/[file]" /datum/map_config/proc/MakeNextMap(maptype = GROUND_MAP) diff --git a/code/datums/medal_awards.dm b/code/datums/medal_awards.dm index ba2ef283b03f..54af48fd3345 100644 --- a/code/datums/medal_awards.dm +++ b/code/datums/medal_awards.dm @@ -20,9 +20,10 @@ GLOBAL_LIST_EMPTY(jelly_awards) var/recipient_rank var/recipient_ckey var/mob/recipient_mob - var/list/giver_name // Actually key for xenos - var/list/giver_rank // Actually name for xenos + var/list/giver_name // Designation for xenos + var/list/giver_rank // "Name" for xenos var/list/giver_mob + var/list/giver_ckey /datum/recipient_awards/New() medal_names = list() @@ -32,6 +33,7 @@ GLOBAL_LIST_EMPTY(jelly_awards) giver_name = list() giver_rank = list() giver_mob = list() + giver_ckey = list() /proc/give_medal_award(medal_location, as_admin = FALSE) @@ -116,12 +118,13 @@ GLOBAL_LIST_EMPTY(jelly_awards) recipient_award.medal_names += medal_type recipient_award.medal_citations += citation recipient_award.posthumous += posthumous + recipient_award.giver_ckey += usr.ckey if(!as_admin) recipient_award.giver_rank += recipient_ranks[usr.real_name] // Currently not used in marine award message recipient_award.giver_name += usr.real_name // Currently not used in marine award message else - recipient_award.giver_rank += "([usr.ckey])" // Just because it'll be displayed in the panel + recipient_award.giver_rank += null recipient_award.giver_name += null // Create an actual medal item @@ -201,7 +204,7 @@ GLOBAL_LIST_EMPTY(jelly_awards) recipient_castes[recipient_name] = xeno.caste_type recipient_mobs[recipient_name] = xeno possible_recipients += recipient_name - for(var/mob/living/carbon/xenomorph/xeno in hive.totalDeadXenos) + for(var/mob/living/carbon/xenomorph/xeno in hive.total_dead_xenos) if (xeno.persistent_ckey == usr.persistent_ckey) // Don't award previous selves continue if (xeno.tier == 0) // Don't award larva or facehuggers @@ -258,15 +261,21 @@ GLOBAL_LIST_EMPTY(jelly_awards) recipient_award.medal_names += medal_type recipient_award.medal_citations += citation recipient_award.posthumous += posthumous + recipient_award.giver_ckey += usr.ckey + if(!admin_attribution) recipient_award.giver_rank += usr.name - recipient_award.giver_name += usr.key + var/mob/living/carbon/xenomorph/giving_xeno = usr + if(istype(giving_xeno)) + recipient_award.giver_name += giving_xeno.full_designation + else + recipient_award.giver_name += null else if(admin_attribution == "none") recipient_award.giver_rank += null recipient_award.giver_name += null else recipient_award.giver_rank += admin_attribution - recipient_award.giver_name += null // If not null, rescinding it will take stats away from a mob with this key + recipient_award.giver_name += null recipient_award.medal_items += null // TODO: Xeno award item? @@ -337,6 +346,7 @@ GLOBAL_LIST_EMPTY(jelly_awards) recipient_award.giver_name.Cut(index, index + 1) recipient_award.giver_rank.Cut(index, index + 1) recipient_award.giver_mob.Cut(index, index + 1) + recipient_award.giver_ckey.Cut(index, index + 1) recipient_award.medal_items.Cut(index, index + 1) // Remove giver's stat diff --git a/code/datums/mob_hud.dm b/code/datums/mob_hud.dm index b1d9a9c2fade..aa1bc9b40783 100644 --- a/code/datums/mob_hud.dm +++ b/code/datums/mob_hud.dm @@ -232,7 +232,10 @@ var/list/datum/mob_hud/huds = list( hud.remove_hud_from(src) else if (istype(hud, /datum/mob_hud/xeno_infection)) hud.remove_hud_from(src) - + if (xeno_hostile_hud) + xeno_hostile_hud = FALSE + var/datum/mob_hud/hostile_hud = huds[MOB_HUD_XENO_HOSTILE] + hostile_hud.remove_hud_from(src) @@ -438,9 +441,9 @@ var/list/datum/mob_hud/huds = list( holder2_set = 1 return - holder.icon_state = "huddead" + holder.icon_state = HAS_TRAIT(src, TRAIT_HARDCORE) || MODE_HAS_TOGGLEABLE_FLAG(MODE_HARDCORE_PERMA) ? "hudhcdead" : "huddead" if(!holder2_set) - holder2.icon_state = "huddead" + holder2.icon_state = holder.icon_state holder3.icon_state = "huddead" holder2_set = 1 diff --git a/code/datums/pain/pain_yautja.dm b/code/datums/pain/pain_yautja.dm index 6b174d228268..94f5e8d33650 100644 --- a/code/datums/pain/pain_yautja.dm +++ b/code/datums/pain/pain_yautja.dm @@ -1,5 +1,5 @@ /datum/pain/yautja - max_pain = 200 + max_pain = 225 threshold_mild = null threshold_discomforting = null diff --git a/code/datums/paygrades/factions/uscm/marine.dm b/code/datums/paygrades/factions/uscm/marine.dm index 298be5fb089f..e351311e65ee 100644 --- a/code/datums/paygrades/factions/uscm/marine.dm +++ b/code/datums/paygrades/factions/uscm/marine.dm @@ -1,7 +1,7 @@ /datum/paygrade/marine name = "Marine Paygrade" rank_pin = /obj/item/clothing/accessory/ranks/marine - pay_multiplier = 1 + pay_multiplier = 1.6 // ENLISTED PAYGRADES @@ -11,7 +11,7 @@ prefix = "PVT" rank_pin = /obj/item/clothing/accessory/ranks/marine/e1 ranking = 0 - pay_multiplier = 0.8 + pay_multiplier = 1.6 /datum/paygrade/marine/e2 paygrade = "ME2" @@ -19,7 +19,7 @@ prefix = "PFC" rank_pin = /obj/item/clothing/accessory/ranks/marine/e2 ranking = 1 - pay_multiplier = 1 // the default. + pay_multiplier = 1.7 /datum/paygrade/marine/e3 paygrade = "ME3" @@ -27,7 +27,7 @@ prefix = "LCpl" rank_pin = /obj/item/clothing/accessory/ranks/marine/e3 ranking = 2 - pay_multiplier = 1.4 + pay_multiplier = 1.9 /datum/paygrade/marine/e4 paygrade = "ME4" @@ -35,7 +35,7 @@ prefix = "Cpl" rank_pin = /obj/item/clothing/accessory/ranks/marine/e4 ranking = 3 - pay_multiplier = 1.6 + pay_multiplier = 2.1 /datum/paygrade/marine/e5 paygrade = "ME5" @@ -43,7 +43,7 @@ prefix = "Sgt" rank_pin = /obj/item/clothing/accessory/ranks/marine/e5 ranking = 4 - pay_multiplier = 1.8 + pay_multiplier = 2.2 /datum/paygrade/marine/e6 paygrade = "ME6" @@ -51,7 +51,7 @@ prefix = "SSgt" rank_pin = /obj/item/clothing/accessory/ranks/marine/e6 ranking = 5 - pay_multiplier = 2 + pay_multiplier = 2.4 /datum/paygrade/marine/e7 paygrade = "ME7" diff --git a/code/datums/paygrades/helper.dm b/code/datums/paygrades/helper.dm index ba5050b154ad..37bdba047960 100644 --- a/code/datums/paygrades/helper.dm +++ b/code/datums/paygrades/helper.dm @@ -4,6 +4,8 @@ var/datum/paygrade/P = GLOB.paygrades[paygrade] if(size)//Builds the prefix, if one should exist. + if(!P)//For custom admin-made paygrades to not cause runtimes. + return "[paygrade] " var/NP = "" if(P.fprefix)//Factional (pre)prefix NP = "[P.fprefix] " @@ -18,8 +20,17 @@ NP = "Mx. " //inclusivity win! return NP else + if(!P)//For custom admin-made paygrades to not cause runtimes. + return "[paygrade]" return P.name +/proc/get_paygrade_id_by_name(paygrade_name) + var/datum/paygrade/paygrade + for(var/paygrade_id in GLOB.paygrades) + paygrade = GLOB.paygrades[paygrade_id] + if(paygrade.name == paygrade_name) + return paygrade_id + /proc/get_rank_pins(paygrade) if(!paygrade) return null diff --git a/code/datums/paygrades/paygrade.dm b/code/datums/paygrades/paygrade.dm index b15071c882b7..bb0a3aa84bfa 100644 --- a/code/datums/paygrades/paygrade.dm +++ b/code/datums/paygrades/paygrade.dm @@ -25,6 +25,7 @@ GLOBAL_LIST_INIT_TYPED(paygrades, /datum/paygrade, setup_paygrades()) .[pg_id] = new PG GLOBAL_LIST_INIT(highcom_paygrades, list( + "PvI", "NO7", "MO7", "NO8", @@ -52,3 +53,9 @@ GLOBAL_LIST_INIT(co_paygrades, list( "MO5", "MO4" )) + +GLOBAL_LIST_INIT(wy_paygrades, list( + "WYC8", + "WYC9", + "WYC10" +)) diff --git a/code/datums/recipe.dm b/code/datums/recipe.dm index 7c699207d7e8..47752fd59400 100644 --- a/code/datums/recipe.dm +++ b/code/datums/recipe.dm @@ -669,6 +669,15 @@ ) result = /obj/item/reagent_container/food/snacks/waffles +/datum/recipe/pancakes + reagents = list("milk" = 5) + items = list( + /obj/item/reagent_container/food/snacks/doughslice, + /obj/item/reagent_container/food/snacks/doughslice, + /obj/item/reagent_container/food/snacks/doughslice, + ) + result = /obj/item/reagent_container/food/snacks/pancakes + /datum/recipe/donkpocket items = list( /obj/item/reagent_container/food/snacks/dough, @@ -760,7 +769,7 @@ /datum/recipe/syntikabob items = list( /obj/item/stack/rods, - /obj/item/reagent_container/food/snacks/meat/syntiflesh, + /obj/item/reagent_container/food/snacks/meat/synthmeat, ) result = /obj/item/reagent_container/food/snacks/monkeykabob diff --git a/code/datums/redis/callbacks/_redis_callback.dm b/code/datums/redis/callbacks/_redis_callback.dm new file mode 100644 index 000000000000..fd786db056c3 --- /dev/null +++ b/code/datums/redis/callbacks/_redis_callback.dm @@ -0,0 +1,28 @@ + +/** + * # Redis callbacks + * + * This datum is used for assigning callbacks that run + * when a message is received on a specific channel. Subtypes of this + * are automatically registered in SSredis initialization + */ +/datum/redis_callback + /// redis channel that this callback subscribes to + var/channel + + +/** + * This proc is run when a message is received on the callback's channel. + * Must be overwritten. + * + * Arguments: + * * message - The message received on the redis channel. + */ +/datum/redis_callback/proc/on_message(message) + CRASH("on_message not overriden for [type]!") + +/datum/redis_callback/vv_edit_var(var_name, var_value) + return FALSE + +/datum/redis_callback/CanProcCall(procname) + return FALSE diff --git a/code/datums/redis/callbacks/asay.dm b/code/datums/redis/callbacks/asay.dm new file mode 100644 index 000000000000..9c60a394a4ac --- /dev/null +++ b/code/datums/redis/callbacks/asay.dm @@ -0,0 +1,16 @@ +/datum/redis_callback/asay + channel = "byond.asay" + +/datum/redis_callback/asay/on_message(message) + var/list/data = json_decode(message) + + if(data["source"] == SSredis.instance_name) + return + + var/msg = SPAN_MOD("[data["rank"]]: [data["author"]]@[data["source"]]: [strip_html(data["message"])]") + + for(var/client/client in GLOB.admins) + if(!(R_ADMIN & client.admin_holder.rights) && !(R_MOD & client.admin_holder.rights)) + continue + + to_chat(client, msg) diff --git a/code/datums/redis/redis_message.dm b/code/datums/redis/redis_message.dm new file mode 100644 index 000000000000..08b10d3556f6 --- /dev/null +++ b/code/datums/redis/redis_message.dm @@ -0,0 +1,11 @@ +/** + * # Redis message + * + * Used to hold redis messages created prior to the initialization of SSredis + */ +/datum/redis_message + /// destination redis channel + var/channel + /// message being sent to the channel + var/message + diff --git a/code/datums/skills.dm b/code/datums/skills.dm index b72b393d0947..9bc53007173d 100644 --- a/code/datums/skills.dm +++ b/code/datums/skills.dm @@ -319,6 +319,7 @@ CIVILIAN /datum/skills/civilian/survivor/goon name = "Survivor Goon" skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, @@ -330,14 +331,40 @@ CIVILIAN /datum/skills/civilian/survivor/pmc name = "Survivor PMC" additional_skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/civilian/survivor/pmc/medic + name = "Survivor PMC Medic" + additional_skills = list( + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_VEHICLE = SKILL_VEHICLE_SMALL, ) +/datum/skills/civilian/survivor/pmc/engineer + name = "Survivor PMC Engineer" + additional_skills = list( + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + ) + /datum/skills/civilian/survivor/doctor name = "Survivor Doctor" additional_skills = list( @@ -449,7 +476,7 @@ MILITARY SURVIVORS SKILL_CQC = SKILL_CQC_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, SKILL_JTAC = SKILL_JTAC_TRAINED, @@ -465,7 +492,7 @@ MILITARY SURVIVORS SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, SKILL_JTAC = SKILL_JTAC_TRAINED, @@ -481,7 +508,7 @@ MILITARY SURVIVORS SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, SKILL_SPEC_WEAPONS = SKILL_SPEC_SCOUT, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, SKILL_JTAC = SKILL_JTAC_TRAINED, @@ -497,23 +524,23 @@ MILITARY SURVIVORS SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, SKILL_JTAC = SKILL_JTAC_TRAINED, ) -/datum/skills/military/survivor/forecon_grenadier - name = "Reconnaissance Grenadier" +/datum/skills/military/survivor/forecon_sniper + name = "Reconnaissance Sniper" skills = list( SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_CQC = SKILL_CQC_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_GRENADIER, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SNIPER, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, SKILL_JTAC = SKILL_JTAC_TRAINED, @@ -530,7 +557,7 @@ MILITARY SURVIVORS SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_JTAC = SKILL_JTAC_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, SKILL_JTAC = SKILL_JTAC_TRAINED, @@ -545,6 +572,7 @@ COMMAND STAFF /datum/skills/general name = "General" skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_LEADERSHIP = SKILL_LEAD_MASTER, @@ -569,6 +597,7 @@ COMMAND STAFF SKILL_SURGERY = SKILL_SURGERY_NOVICE, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, SKILL_CQC = SKILL_CQC_SKILLED, SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, @@ -588,6 +617,7 @@ COMMAND STAFF SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, SKILL_SURGERY = SKILL_SURGERY_NOVICE, SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, SKILL_CQC = SKILL_CQC_SKILLED, SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, @@ -671,6 +701,24 @@ COMMAND STAFF SKILL_INTEL = SKILL_INTEL_TRAINED, ) +/datum/skills/auxiliary_officer + name = "Auxiliary Support Officer" + skills = list( + SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_INTEL = SKILL_INTEL_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + ) + /datum/skills/CE name = "Chief Engineer" skills = list( @@ -837,7 +885,7 @@ SYNTHETIC SKILL_SURGERY = SKILL_SURGERY_EXPERT, SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_PILOT = SKILL_PILOT_TRAINED, + SKILL_PILOT = SKILL_PILOT_EXPERT, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_MAX, SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, @@ -851,7 +899,7 @@ SYNTHETIC /datum/skills/colonial_synthetic name = SYNTH_COLONY skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_CQC = SKILL_CQC_EXPERT, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, @@ -860,9 +908,9 @@ SYNTHETIC SKILL_SURGERY = SKILL_SURGERY_TRAINED, SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_PILOT = SKILL_PILOT_TRAINED, + SKILL_PILOT = SKILL_PILOT_EXPERT, SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, SKILL_VEHICLE = SKILL_VEHICLE_LARGE, SKILL_JTAC = SKILL_JTAC_BEGINNER, @@ -873,7 +921,7 @@ SYNTHETIC /datum/skills/working_joe name = SYNTH_WORKING_JOE skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_CQC = SKILL_CQC_EXPERT, SKILL_ENGINEER = SKILL_ENGINEER_MASTER, //So they can fully use the Maintenance Jack SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_POLICE = SKILL_POLICE_SKILLED, @@ -961,14 +1009,14 @@ United States Colonial Marines SKILL_CQC = SKILL_CQC_TRAINED, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set. - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_SPEC_WEAPONS = SKILL_SPEC_TRAINED, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, SKILL_JTAC = SKILL_JTAC_BEGINNER ) -/datum/skills/rto - name = "Squad Radio Telephone Operator" +/datum/skills/tl + name = "Fireteam Leader" skills = list( SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, @@ -1018,9 +1066,8 @@ COLONIAL LIBERATION FRONT SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, SKILL_JTAC = SKILL_JTAC_BEGINNER, ) @@ -1032,7 +1079,7 @@ COLONIAL LIBERATION FRONT SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, SKILL_JTAC = SKILL_JTAC_BEGINNER, ) @@ -1041,9 +1088,8 @@ COLONIAL LIBERATION FRONT skills = list( SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, SKILL_JTAC = SKILL_JTAC_BEGINNER, ) @@ -1051,11 +1097,11 @@ COLONIAL LIBERATION FRONT name = "CLF Specialist" skills = list( SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set. SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_JTAC = SKILL_JTAC_TRAINED ) @@ -1065,7 +1111,7 @@ COLONIAL LIBERATION FRONT skills = list( SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, // to use their C4 - SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_POLICE = SKILL_POLICE_SKILLED, @@ -1082,7 +1128,7 @@ COLONIAL LIBERATION FRONT skills = list( SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_LEADERSHIP = SKILL_LEAD_MASTER, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_POLICE = SKILL_POLICE_SKILLED, @@ -1147,9 +1193,9 @@ UNITED PROGRESSIVE PEOPLES SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_DEFAULT, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, ) @@ -1159,9 +1205,9 @@ UNITED PROGRESSIVE PEOPLES SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_DEFAULT, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, ) @@ -1170,9 +1216,9 @@ UNITED PROGRESSIVE PEOPLES skills = list( SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, //trained in medicine more than combat + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_DEFAULT, SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED ) /datum/skills/upp/specialist @@ -1180,14 +1226,13 @@ UNITED PROGRESSIVE PEOPLES skills = list( SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, SKILL_CQC = SKILL_CQC_TRAINED, SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, SKILL_JTAC = SKILL_JTAC_TRAINED, SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_MASTER, ) /datum/skills/upp/SL @@ -1205,10 +1250,10 @@ UNITED PROGRESSIVE PEOPLES /datum/skills/upp/military_police name = "UPP Military Police" skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, @@ -1218,10 +1263,10 @@ UNITED PROGRESSIVE PEOPLES /datum/skills/upp/officer name = "UPP Officer" skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_POLICE = SKILL_POLICE_FLASH, SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, @@ -1234,11 +1279,11 @@ UNITED PROGRESSIVE PEOPLES /datum/skills/upp/commander name = "UPP Command Officer" skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, @@ -1263,6 +1308,7 @@ Private Military Contractors /datum/skills/pmc name = "PMC Private" skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, @@ -1274,18 +1320,21 @@ Private Military Contractors /datum/skills/pmc/medic name = "PMC Medic" skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, ) /datum/skills/pmc/medic/chem name = "PMC Medical Investigator" skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, @@ -1299,6 +1348,7 @@ Private Military Contractors /datum/skills/pmc/smartgunner name = "PMC Smartgunner" skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, @@ -1312,6 +1362,7 @@ Private Military Contractors /datum/skills/pmc/specialist name = "PMC Specialist" skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_POLICE = SKILL_POLICE_SKILLED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, @@ -1332,7 +1383,7 @@ Private Military Contractors SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, @@ -1347,7 +1398,7 @@ Private Military Contractors SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, @@ -1423,18 +1474,17 @@ CONTRACTORS /datum/skills/contractor name = "Contractor Standard" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_MAX, SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_JTAC = SKILL_JTAC_BEGINNER, SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, ) /datum/skills/contractor/leader @@ -1446,11 +1496,11 @@ CONTRACTORS SKILL_LEADERSHIP = SKILL_LEAD_MASTER, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MASTER, - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, SKILL_JTAC = SKILL_JTAC_MASTER, ) @@ -1460,51 +1510,50 @@ CONTRACTORS skills = list( SKILL_FIREARMS = SKILL_FIREARMS_MAX, SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_JTAC = SKILL_JTAC_BEGINNER, ) /datum/skills/contractor/engi name = "Contractor Engi" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_MAX, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX, SKILL_FIREARMS = SKILL_FIREARMS_MAX, SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_MAX, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_JTAC = SKILL_JTAC_EXPERT, SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MAX, + SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, ) /datum/skills/contractor/heavy name = "Contractor Machinegunner" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_MAX, SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, SKILL_JTAC = SKILL_JTAC_BEGINNER, SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, ) /* @@ -1516,7 +1565,7 @@ COLONIAL MARSHALS name = "CMB Deputy" skills = list( SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_EXPERT, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, @@ -1530,7 +1579,7 @@ COLONIAL MARSHALS name = "CMB Marshal" skills = list( SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_EXPERT, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_LEADERSHIP = SKILL_LEAD_MASTER, SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, @@ -1565,6 +1614,82 @@ COLONIAL MARSHALS SKILL_INTEL = SKILL_INTEL_EXPERT, SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER ) + +/datum/skills/military/survivor/upp_private + name = "UPP Private" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/upp_sapper + name = "UPP Sapper" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/upp_medic + name = "UPP Medic" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/upp_spec + name = "UPP Specialist" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + ) + +/datum/skills/military/survivor/upp_sl + name = "UPP Squad Leader" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) + /* --------------------- SPEC-OPS @@ -1593,6 +1718,7 @@ SPEC-OPS SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, @@ -1689,7 +1815,7 @@ MISCELLANEOUS /datum/skills/mercenary name = "Mercenary" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, @@ -1701,7 +1827,7 @@ MISCELLANEOUS /datum/skills/mercenary/elite name = "Elite Mercenary" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_MAX, @@ -1715,7 +1841,7 @@ MISCELLANEOUS /datum/skills/mercenary/elite/medic name = "Elite Mercenary Medic" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_MAX, @@ -1723,13 +1849,13 @@ MISCELLANEOUS SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_JTAC = SKILL_JTAC_BEGINNER, SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_SURGERY = SKILL_SURGERY_EXPERT, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, ) /datum/skills/mercenary/elite/engineer name = "Elite Mercenary Engineer" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_ENGINEER = SKILL_ENGINEER_MASTER, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, SKILL_FIREARMS = SKILL_FIREARMS_MAX, @@ -1744,7 +1870,7 @@ MISCELLANEOUS /datum/skills/mercenary/elite/heavy name = "Elite Mercenary Heavy" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_MAX, @@ -1759,7 +1885,7 @@ MISCELLANEOUS /datum/skills/mercenary/elite/leader name = "Elite Mercenary Leader" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_SKILLED, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_MAX, @@ -1774,29 +1900,31 @@ MISCELLANEOUS /datum/skills/dutchmerc name = "Dutch's Dozen Mercenary" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CQC = SKILL_CQC_TRAINED, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, ) /datum/skills/dutchmedic name = "Dutch's Dozen Medic" skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, ) /datum/skills/tank_crew @@ -1866,11 +1994,12 @@ MISCELLANEOUS SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_ANTAG = SKILL_ANTAG_HUNTER, ) /datum/skills/cultist_leader diff --git a/code/datums/statistics/entities/death_stats.dm b/code/datums/statistics/entities/death_stats.dm index 6fed8884c1d3..4a01e4e9d72b 100644 --- a/code/datums/statistics/entities/death_stats.dm +++ b/code/datums/statistics/entities/death_stats.dm @@ -19,6 +19,7 @@ var/time_of_death var/total_time_alive var/total_damage_taken + var/total_revives_done = 0 var/total_brute = 0 var/total_burn = 0 @@ -51,6 +52,7 @@ "time_of_death" = DB_FIELDTYPE_BIGINT, "total_time_alive" = DB_FIELDTYPE_BIGINT, "total_damage_taken" = DB_FIELDTYPE_INT, + "total_revives_done" = DB_FIELDTYPE_INT, "total_brute" = DB_FIELDTYPE_INT, "total_burn" = DB_FIELDTYPE_INT, @@ -63,13 +65,25 @@ ) /mob/proc/track_mob_death(datum/cause_data/cause_data, turf/death_loc) - if(!mind || statistic_exempt) - return - if(cause_data && !istype(cause_data)) stack_trace("track_mob_death called with string cause ([cause_data]) instead of datum") cause_data = create_cause_data(cause_data) + var/log_message = "\[[time_stamp()]\] [key_name(src)] died to " + if(cause_data) + log_message += "[cause_data.cause_name]" + else + log_message += "unknown causes" + var/mob/cause_mob = cause_data?.resolve_mob() + if(cause_mob) + log_message += " from [key_name(cause_data.resolve_mob())]" + cause_mob.attack_log += "\[[time_stamp()]\] [key_name(cause_mob)] killed [key_name(src)] with [cause_data.cause_name]." + + attack_log += "[log_message]." + + if(!mind || statistic_exempt) + return + var/datum/entity/statistic/death/new_death = DB_ENTITY(/datum/entity/statistic/death) var/datum/entity/player/player_entity = get_player_from_key(mind.ckey) if(player_entity) @@ -94,7 +108,6 @@ new_death.cause_role_name = cause_data?.role new_death.cause_faction_name = cause_data?.faction - var/mob/cause_mob = cause_data?.resolve_mob() if(cause_mob) cause_mob.life_kills_total += life_value @@ -117,6 +130,7 @@ new_death.total_kills = life_kills_total new_death.total_time_alive = life_time_total new_death.total_damage_taken = life_damage_taken_total + new_death.total_revives_done = life_revives_total handle_observer_message(cause_data, cause_mob, death_loc, A) @@ -160,7 +174,7 @@ if(src) to_chat(src, SPAN_DEADSAY(observer_message)) for(var/mob/dead/observer/g in GLOB.observer_list) - to_chat(g, SPAN_DEADSAY(observer_message + " (JMP)")) + to_chat(g, SPAN_DEADSAY("[observer_message] [OBSERVER_JMP(g, death_loc)]")) /mob/living/carbon/xenomorph/handle_observer_message(datum/cause_data/cause_data, mob/cause_mob, turf/death_loc, area/death_area) if(hardcore) diff --git a/code/datums/statistics/entities/panel_stats.dm b/code/datums/statistics/entities/panel_stats.dm index 44f95f2d91d9..d6e391e1731f 100644 --- a/code/datums/statistics/entities/panel_stats.dm +++ b/code/datums/statistics/entities/panel_stats.dm @@ -741,7 +741,6 @@ "total_projectiles_hit_xeno" = total_projectiles_hit_xeno, "total_slashes" = total_slashes, "total_friendly_fire_instances" = total_friendly_fire_instances, - "total_friendly_fire_kills" = total_friendly_fire_kills, "total_huggers_applied" = total_huggers_applied, "total_larva_burst" = total_larva_burst, "participants" = participants_list, diff --git a/code/datums/statistics/entities/round_stats.dm b/code/datums/statistics/entities/round_stats.dm index 4f5f8bd535ca..0e1fb6e387db 100644 --- a/code/datums/statistics/entities/round_stats.dm +++ b/code/datums/statistics/entities/round_stats.dm @@ -20,7 +20,6 @@ var/total_projectiles_hit_human = 0 var/total_projectiles_hit_xeno = 0 var/total_friendly_fire_instances = 0 - var/total_friendly_fire_kills = 0 var/total_slashes = 0 // untracked data @@ -295,7 +294,7 @@ track_dead_participant(new_death.faction_name) /datum/entity/statistic/round/proc/log_round_statistics() - if(!round_stats) + if(!GLOB.round_stats) return var/total_xenos_created = 0 var/total_predators_spawned = 0 @@ -360,7 +359,6 @@ stats += "Total shots fired: [total_projectiles_fired]\n" stats += "Total friendly fire instances: [total_friendly_fire_instances]\n" - stats += "Total friendly fire kills: [total_friendly_fire_kills]\n" stats += "Marines remaining: [end_of_round_marines]\n" stats += "Xenos remaining: [end_of_round_xenos]\n" @@ -368,7 +366,7 @@ stats += "[log_end]" - round_stats << stats // Logging to data/logs/round_stats.log + WRITE_LOG(GLOB.round_stats, stats) /datum/action/show_round_statistics name = "View End-Round Statistics" diff --git a/code/datums/statistics/random_facts/damage_fact.dm b/code/datums/statistics/random_facts/damage_fact.dm index def2d74f66c1..2fa8a5d06491 100644 --- a/code/datums/statistics/random_facts/damage_fact.dm +++ b/code/datums/statistics/random_facts/damage_fact.dm @@ -1,57 +1,9 @@ -/datum/random_fact/damage/announce() - var/death_damage_taken = 0 - var/living_damage_taken = 0 - var/datum/entity/statistic/death/death_to_report = null - var/mob/mob_to_report = null +/datum/random_fact/damage + statistic_name = "damage" + statistic_verb = "took" - if(round_statistics && length(round_statistics.death_stats_list)) - for(var/datum/entity/statistic/death/death in round_statistics.death_stats_list) - if(!check_human && !death.is_xeno) - continue - if(!check_xeno && death.is_xeno) - continue - if(death_damage_taken < death.total_damage_taken) - death_to_report = death - death_damage_taken = death.total_damage_taken +/datum/random_fact/damage/life_grab_stat(mob/fact_mob) + return fact_mob.life_damage_taken_total - var/list/list_to_check = list() - if(check_human) list_to_check += GLOB.alive_human_list - if(check_xeno) list_to_check += GLOB.living_xeno_list - for(var/mob/M as anything in list_to_check) - if(living_damage_taken < M.life_damage_taken_total) - mob_to_report = M - living_damage_taken = M.life_damage_taken_total - - if(!death_to_report && !mob_to_report) - return - - var/name = "" - var/damage_taken = 0 - var/additional_message = "" - if(death_to_report && mob_to_report) - if(living_damage_taken > death_damage_taken) - name = mob_to_report.real_name - damage_taken = living_damage_taken - additional_message = "and survived! Great work!" - else - name = death_to_report.mob_name - damage_taken = death_damage_taken - additional_message = "before dying" - if(death_to_report.cause_name) - additional_message += " to [death_to_report.cause_name]" - additional_message += ". Good work!" - else if(death_to_report) - name = death_to_report.mob_name - damage_taken = death_damage_taken - additional_message = "before dying" - if(death_to_report.cause_name) - additional_message += " to [death_to_report.cause_name]" - additional_message += ". Good work!" - else - name = mob_to_report.real_name - damage_taken = living_damage_taken - additional_message = "and survived! Great work!" - - message = "[name] took a whopping [damage_taken] damage [additional_message]" - - return ..() +/datum/random_fact/damage/death_grab_stat(datum/entity/statistic/death/fact_death) + return fact_death.total_damage_taken diff --git a/code/datums/statistics/random_facts/kills_fact.dm b/code/datums/statistics/random_facts/kills_fact.dm index 22ad0ba27b01..7ef1c2b238de 100644 --- a/code/datums/statistics/random_facts/kills_fact.dm +++ b/code/datums/statistics/random_facts/kills_fact.dm @@ -1,56 +1,9 @@ -/datum/random_fact/kills/announce() - var/death_kills_gotten = 0 - var/living_kills_gotten = 0 - var/datum/entity/statistic/death/death_to_report = null - var/mob/mob_to_report = null +/datum/random_fact/kills + statistic_name = "kills" + statistic_verb = "earned" - if(round_statistics && length(round_statistics.death_stats_list)) - for(var/datum/entity/statistic/death/death in round_statistics.death_stats_list) - if(!check_human && !death.is_xeno) - continue - if(!check_xeno && death.is_xeno) - continue - if(death_kills_gotten < death.total_kills) - death_to_report = death - death_kills_gotten = death.total_kills +/datum/random_fact/kills/life_grab_stat(mob/fact_mob) + return fact_mob.life_kills_total - var/list/list_to_check = list() - if(check_human) list_to_check += GLOB.alive_human_list - if(check_xeno) list_to_check += GLOB.living_xeno_list - for(var/mob/M as anything in list_to_check) - if(living_kills_gotten < M.life_kills_total) - mob_to_report = M - living_kills_gotten = M.life_kills_total - - if(!death_to_report && !mob_to_report) - return - - var/name = "" - var/kills_gotten = 0 - var/additional_message = "" - if(death_to_report && mob_to_report) - if(living_kills_gotten > death_kills_gotten) - name = mob_to_report.real_name - kills_gotten = living_kills_gotten - additional_message = "and survived! Great work!" - else - name = death_to_report.mob_name - kills_gotten = death_kills_gotten - additional_message = "before dying" - if(death_to_report.cause_name) - additional_message += " to [death_to_report.cause_name]" - additional_message += ". Good work!" - else if(death_to_report) - name = death_to_report.mob_name - kills_gotten = death_kills_gotten - additional_message = "before dying" - if(death_to_report.cause_name) - additional_message += " to [death_to_report.cause_name]" - additional_message += ". Good work!" - else - name = mob_to_report.real_name - kills_gotten = living_kills_gotten - additional_message = "and survived! Great work!" - - message = "[name] earned [kills_gotten] kill\s [additional_message]" - . = ..() +/datum/random_fact/kills/death_grab_stat(datum/entity/statistic/death/fact_death) + return fact_death.total_kills diff --git a/code/datums/statistics/random_facts/random_fact.dm b/code/datums/statistics/random_facts/random_fact.dm index f5f166c367a7..76c6e82f776d 100644 --- a/code/datums/statistics/random_facts/random_fact.dm +++ b/code/datums/statistics/random_facts/random_fact.dm @@ -1,5 +1,7 @@ /datum/random_fact var/message = null + var/statistic_name = null + var/statistic_verb = null var/check_human = TRUE var/check_xeno = TRUE @@ -10,7 +12,75 @@ check_xeno = set_check_xeno /datum/random_fact/proc/announce() + calculate_announcement_message() if(message) to_world(SPAN_CENTERBOLD(message)) return TRUE return FALSE + +/datum/random_fact/proc/calculate_announcement_message() + var/death_stat_gotten = 0 + var/living_stat_gotten = 0 + var/datum/entity/statistic/death/death_to_report = null + var/mob/mob_to_report = null + + if(round_statistics && length(round_statistics.death_stats_list)) + for(var/datum/entity/statistic/death/death in round_statistics.death_stats_list) + if(!check_human && !death.is_xeno) + continue + if(!check_xeno && death.is_xeno) + continue + if(death_stat_gotten < death_grab_stat(death)) + death_to_report = death + death_stat_gotten = death_grab_stat(death) + + var/list/list_to_check = list() + if(check_human) + list_to_check += GLOB.alive_human_list + if(check_xeno) + list_to_check += GLOB.living_xeno_list + + for(var/mob/checked_mob as anything in list_to_check) + if(!checked_mob?.persistent_ckey) + continue // We don't care about NPCs + if(living_stat_gotten < life_grab_stat(checked_mob)) + mob_to_report = checked_mob + living_stat_gotten = life_grab_stat(checked_mob) + + if(!death_to_report && !mob_to_report) + return + + var/name = "" + var/stat_gotten = 0 + var/additional_message = "" + if(death_to_report && mob_to_report) + if(living_stat_gotten > death_stat_gotten) + name = mob_to_report.real_name + stat_gotten = living_stat_gotten + additional_message = "and survived! Great work!" + else + name = death_to_report.mob_name + stat_gotten = death_stat_gotten + additional_message = "before dying" + if(death_to_report.cause_name) + additional_message += " to [death_to_report.cause_name]" + additional_message += ". Good work!" + else if(death_to_report) + name = death_to_report.mob_name + stat_gotten = death_stat_gotten + additional_message = "before dying" + if(death_to_report.cause_name) + additional_message += " to [death_to_report.cause_name]" + additional_message += ". Good work!" + else + name = mob_to_report.real_name + stat_gotten = living_stat_gotten + additional_message = "and survived! Great work!" + + message = "[name] [statistic_verb] [stat_gotten] [statistic_name] [additional_message]" + +/datum/random_fact/proc/life_grab_stat(mob/fact_mob) + return 0 + +/datum/random_fact/proc/death_grab_stat(datum/entity/statistic/death/fact_death) + return 0 diff --git a/code/datums/statistics/random_facts/revives_fact.dm b/code/datums/statistics/random_facts/revives_fact.dm new file mode 100644 index 000000000000..60b6daa896d2 --- /dev/null +++ b/code/datums/statistics/random_facts/revives_fact.dm @@ -0,0 +1,9 @@ +/datum/random_fact/revives + statistic_name = "people" + statistic_verb = "revived" + +/datum/random_fact/revives/life_grab_stat(mob/fact_mob) + return fact_mob.life_revives_total + +/datum/random_fact/revives/death_grab_stat(datum/entity/statistic/death/fact_death) + return fact_death.total_revives_done diff --git a/code/datums/supply_packs/ammo.dm b/code/datums/supply_packs/ammo.dm index bd0e57f4017b..164511c25cc0 100644 --- a/code/datums/supply_packs/ammo.dm +++ b/code/datums/supply_packs/ammo.dm @@ -122,16 +122,6 @@ containername = "\improper M39 AP magazines crate" group = "Ammo" -/datum/supply_packs/ammo_smg_mag_box_ext - name = "Magazine box (M39, 10x extended mags)" - contains = list( - /obj/item/ammo_box/magazine/m39/ext, - ) - cost = 30 - containertype = /obj/structure/closet/crate/ammo - containername = "\improper M39 extended magazines crate" - group = "Ammo" - //------------------------For M4RA---------------- /datum/supply_packs/ammo_m4ra_mag_box @@ -308,15 +298,17 @@ //------------------------Smartgunner stuff---------------- -/datum/supply_packs/ammo_smartgun_powerpack - name = "M56 smartgun powerpack crate (x2)" +/datum/supply_packs/ammo_smartgun_battery_pack + name = "M56 smartgun battery crate (x4)" contains = list( - /obj/item/smartgun_powerpack, - /obj/item/smartgun_powerpack, + /obj/item/smartgun_battery, + /obj/item/smartgun_battery, + /obj/item/smartgun_battery, + /obj/item/smartgun_battery, ) cost = 40 containertype = /obj/structure/closet/crate/ammo - containername = "\improper smartgun powerpacks crate" + containername = "\improper smartgun battery crate" group = "Ammo" /datum/supply_packs/ammo_smartgun diff --git a/code/datums/supply_packs/attachments.dm b/code/datums/supply_packs/attachments.dm index 2a812e94cfc1..b685e5c3c37f 100644 --- a/code/datums/supply_packs/attachments.dm +++ b/code/datums/supply_packs/attachments.dm @@ -84,17 +84,6 @@ containername = "extended barrel attachment crate" group = "Attachments" -/datum/supply_packs/muzzle_heavy - name = "barrel charger attachment crate (x2)" - contains = list( - /obj/item/attachable/heavy_barrel, - /obj/item/attachable/heavy_barrel, - ) - cost = 30 - containertype = /obj/structure/closet/crate - containername = "heavy barrel attachment crate" - group = "Attachments" - /datum/supply_packs/muzzle_compensator name = "compensator attachment crate (x6)" contains = list( diff --git a/code/datums/supply_packs/black_market.dm b/code/datums/supply_packs/black_market.dm index 89fa9cf22991..3f4453d03f32 100644 --- a/code/datums/supply_packs/black_market.dm +++ b/code/datums/supply_packs/black_market.dm @@ -141,7 +141,7 @@ Non-USCM items, from CLF, UPP, colonies, etc. Mostly combat-related. new /obj/item/weapon/gun/pistol/holdout(src) new /obj/item/ammo_magazine/pistol/holdout(src) if(3) //clf - switch(rand(1, 4)) + switch(rand(1, 3)) if(1) new /obj/item/weapon/twohanded/lungemine/damaged(src) if(2) @@ -154,11 +154,6 @@ Non-USCM items, from CLF, UPP, colonies, etc. Mostly combat-related. new /obj/item/ammo_magazine/smg/mac15/extended(src) new /obj/item/ammo_magazine/smg/mac15(src) new /obj/item/ammo_magazine/smg/mac15(src) - if(4) - new /obj/item/weapon/gun/m60(src) - new /obj/item/ammo_magazine/m60(src) - new /obj/item/ammo_magazine/m60(src) - new /obj/item/ammo_magazine/m60(src) if(4) //upp if(prob(50)) new /obj/item/weapon/gun/rifle/type71(src) @@ -189,10 +184,9 @@ Non-USCM items, from CLF, UPP, colonies, etc. Mostly combat-related. new /obj/item/ammo_magazine/rifle/mar40/extended(src) new /obj/item/ammo_magazine/rifle/mar40(src) else - new /obj/item/weapon/gun/rifle/m41aMK1/tactical(src) - new /obj/item/ammo_magazine/rifle/m41aMK1/ap(src) - new /obj/item/ammo_magazine/rifle/m41aMK1(src) - new /obj/item/ammo_magazine/rifle/m41aMK1(src) + new /obj/item/weapon/gun/rifle/mar40/lmg(src) + new /obj/item/ammo_magazine/rifle/mar40/lmg(src) + new /obj/item/ammo_magazine/rifle/mar40/lmg(src) /* Misc. Individual Guns */ @@ -262,16 +256,6 @@ Additionally, weapons that are way too good to put in the basically-flavor black containertype = /obj/structure/largecrate/black_market // Shotguns - -/datum/supply_packs/contraband/seized/sawny - name = "Sawn-off Spearhead Rival 78 crate (x1 ammo box included)" - contains = list( - /obj/item/weapon/gun/shotgun/double/damaged, //its not actually sawed off........... get fuked - /obj/item/ammo_magazine/shotgun/buckshot, - ) - dollar_cost = 45 - containertype = /obj/structure/largecrate/black_market - /datum/supply_packs/contraband/seized/custom name = "custom-built shotgun crate (x1 ammo box included)" contains = list( @@ -555,7 +539,6 @@ Primarily made up of things that would be best utilized, well, shipside. Recreat /obj/item/reagent_container/food/drinks/flask/weylandyutani/poison, /obj/item/reagent_container/food/drinks/bottle/holywater/bong, /obj/item/storage/pill_bottle/paracetamol, - /obj/item/storage/pill_bottle/zombie_powder, ) dollar_cost = 25 containertype = /obj/structure/largecrate/black_market @@ -970,7 +953,7 @@ This is where the RO can reclaim their lost honor and purchase the M44 custom, t /datum/supply_packs/contraband/deep_storage/cartridge_bayonet name = "M8 Cartridge Bayonet Kit" - contains = list(/obj/item/storage/box/c02_knife) + contains = list(/obj/item/storage/box/co2_knife) dollar_cost = 10 containertype = /obj/structure/largecrate/black_market @@ -1167,7 +1150,7 @@ Things that don't fit anywhere else. If they're meant for shipside use, they pro new /obj/effect/essentials_set/random/clf_bonus_item(loc) new /obj/effect/essentials_set/random/clf_bonus_item(loc) loot_message = SPAN_NOTICE("It's a bunch of random junk...") - if(51 to 60) + if(51 to 70) new /obj/effect/spawner/random/bomb_supply(loc) new /obj/effect/spawner/random/bomb_supply(loc) new /obj/effect/spawner/random/toolbox(loc) @@ -1175,19 +1158,11 @@ Things that don't fit anywhere else. If they're meant for shipside use, they pro new /obj/effect/spawner/random/tool(loc) new /obj/effect/spawner/random/attachment(loc) if(prob(33)) - new /obj/effect/spawner/random/supply_kit(loc) + new /obj/effect/spawner/random/supply_kit/market(loc) else new /obj/effect/spawner/random/attachment(loc) loot_message = SPAN_NOTICE("Just some old equipment and parts.") - if(61 to 65) - // backpacks - for(var/i in 1 to rand(3, 6)) - var/pack_type = pick(subtypesof(/obj/item/storage/backpack)) - var/obj/item/storage/backpack/pack = new pack_type(loc) - if(pack.max_storage_space > 15) - pack.max_storage_space = 15 - loot_message = SPAN_NOTICE("Some backpacks. They all look empty though...") - if(66 to 70) + if(71 to 75) // CLF corpse!! Why is this here? Don't ask. var/mob/living/carbon/human/corpse = new (loc) corpse.create_hud() //Need to generate hud before we can equip anything apparently... @@ -1196,12 +1171,6 @@ Things that don't fit anywhere else. If they're meant for shipside use, they pro arm_equipment(corpse, corpse_type, TRUE, FALSE) // I didn't choose the shitcode life, the shitcode life chose me loot_message = SPAN_HIGHDANGER("IT'S A CORPSE!!") - if(71 to 75) - // Costumes. - new /obj/effect/landmark/costume/random(loc) - new /obj/effect/landmark/costume/random(loc) - new /obj/effect/landmark/costume/random(loc) - loot_message = SPAN_NOTICE("What the hell is this..?") if(76 to 90) // Random supply garbage. new /obj/effect/spawner/random/tool(loc) diff --git a/code/datums/supply_packs/clothing.dm b/code/datums/supply_packs/clothing.dm index 0e7604ead7c7..1c7241bb253b 100644 --- a/code/datums/supply_packs/clothing.dm +++ b/code/datums/supply_packs/clothing.dm @@ -110,7 +110,7 @@ /datum/supply_packs/officer_outfits//lmao this shit is so hideously out of date contains = list( - /obj/item/clothing/under/rank/ro_suit, + /obj/item/clothing/under/rank/qm_suit, /obj/item/clothing/under/marine/officer/bridge, /obj/item/clothing/under/marine/officer/bridge, /obj/item/clothing/under/marine/officer/exec, diff --git a/code/datums/supply_packs/medical.dm b/code/datums/supply_packs/medical.dm index 76bcdcdb9fca..05cb4d2f34c0 100644 --- a/code/datums/supply_packs/medical.dm +++ b/code/datums/supply_packs/medical.dm @@ -14,7 +14,6 @@ /obj/item/storage/pill_bottle/dexalin, /obj/item/storage/pill_bottle/kelotane, /obj/item/storage/pill_bottle/tramadol, - /obj/item/storage/pill_bottle/quickclot, /obj/item/storage/pill_bottle/peridaxon, /obj/item/storage/box/pillbottles, ) diff --git a/code/datums/supply_packs/operations.dm b/code/datums/supply_packs/operations.dm index cc4408659d09..6d5e5d14756c 100644 --- a/code/datums/supply_packs/operations.dm +++ b/code/datums/supply_packs/operations.dm @@ -94,13 +94,21 @@ group = "Operations" /datum/supply_packs/nuclearbomb - name = "Operational Nuke" + name = "Decrypted Operational Nuke" cost = 0 containertype = /obj/structure/machinery/nuclearbomb buyable = 0 group = "Operations" iteration_needed = null +/datum/supply_packs/technuclearbomb + name = "Encrypted Operational Nuke" + cost = 0 + containertype = /obj/structure/machinery/nuclearbomb/tech + buyable = 0 + group = "Operations" + iteration_needed = null + /datum/supply_packs/spec_kits name = "Weapons Specialist Kits" contains = list( diff --git a/code/datums/supply_packs/restricted_equipment.dm b/code/datums/supply_packs/restricted_equipment.dm index 13b02f3d0f6c..452ef313908a 100644 --- a/code/datums/supply_packs/restricted_equipment.dm +++ b/code/datums/supply_packs/restricted_equipment.dm @@ -11,7 +11,7 @@ containername = "B12 pattern marine armor crate" group = "Restricted Equipment" -/datum/supply_packs/armor_rto +/datum/supply_packs/armor_tl name = "M4 pattern marine armor crate (x1 helmet, x1 armor)" contains = list( /obj/item/clothing/head/helmet/marine/rto, diff --git a/code/datums/tgs_event_handler.dm b/code/datums/tgs_event_handler.dm index 072a0f4d605c..a47d1e95af00 100644 --- a/code/datums/tgs_event_handler.dm +++ b/code/datums/tgs_event_handler.dm @@ -14,13 +14,21 @@ message_admins("TGS: Instance renamed to from [world.TgsInstanceName()] to [args[2]]") if(TGS_EVENT_COMPILE_START) message_admins("TGS: Deployment started, new game version incoming...") + if(world.system_type == UNIX && SSredis.connected) + SSredis.disconnect(TGS_COMPILE) if(TGS_EVENT_COMPILE_CANCELLED) message_admins("TGS: Deployment cancelled!") + if(world.system_type == UNIX && CONFIG_GET(flag/redis_enabled) && !SSredis.connected) + SSredis.reconnect() if(TGS_EVENT_COMPILE_FAILURE) message_admins("TGS: Deployment failed!") + if(world.system_type == UNIX && CONFIG_GET(flag/redis_enabled) && !SSredis.connected) + SSredis.reconnect() if(TGS_EVENT_DEPLOYMENT_COMPLETE) message_admins("TGS: Deployment complete!") to_chat(world, SPAN_BOLDANNOUNCE("Server updated, changes will be applied on the next round...")) + if(world.system_type == UNIX && CONFIG_GET(flag/redis_enabled) && !SSredis.connected) + SSredis.reconnect() if(TGS_EVENT_WATCHDOG_DETACH) message_admins("TGS restarting...") reattach_timer = addtimer(CALLBACK(src, PROC_REF(LateOnReattach)), 1 MINUTES, TIMER_STOPPABLE) diff --git a/code/datums/weather/weather_events/new_varadero.dm b/code/datums/weather/weather_events/new_varadero.dm new file mode 100644 index 000000000000..f2af23c3f10a --- /dev/null +++ b/code/datums/weather/weather_events/new_varadero.dm @@ -0,0 +1,38 @@ +/datum/weather_event/light_rain + name = "Tropical Storm" + display_name = "Tropical Storm" + length = 4 MINUTES + fullscreen_type = /atom/movable/screen/fullscreen/weather/low + + turf_overlay_icon_state = "strata_storm" + turf_overlay_alpha = 40 + + effect_message = null + damage_per_tick = 0 + + has_process = TRUE + lightning_chance = 1 + + ambience = 'sound/ambience/rainforest.ogg' + + fire_smothering_strength = 1 + +/datum/weather_event/monsoon + name = "Monsoon Warning" + display_name = "Monsoon Warning" + length = 6 MINUTES + fullscreen_type = /atom/movable/screen/fullscreen/weather/high + + turf_overlay_icon_state = "strata_storm" + turf_overlay_alpha = 115 + + effect_message = null + damage_per_tick = 0 + + + ambience = 'sound/ambience/varadero_storm.ogg' + + has_process = TRUE + lightning_chance = 6 + + fire_smothering_strength = 4 diff --git a/code/datums/weather/weather_map_holders/new_varadero.dm b/code/datums/weather/weather_map_holders/new_varadero.dm new file mode 100644 index 000000000000..8222001f4739 --- /dev/null +++ b/code/datums/weather/weather_map_holders/new_varadero.dm @@ -0,0 +1,20 @@ +/datum/weather_ss_map_holder/new_varadero + name = "New Varadero Map Holder" + + min_time_between_events = 15 MINUTES + no_weather_turf_icon_state = "strata_clearsky" + + potential_weather_events = list( + /datum/weather_event/light_rain, + /datum/weather_event/monsoon, + ) + +/datum/weather_ss_map_holder/new_varadero/should_affect_area(area/A) + return !CEILING_IS_PROTECTED(A.ceiling, CEILING_GLASS) + +/datum/weather_ss_map_holder/new_varadero/should_start_event() + return prob(PROB_WEATHER_NEW_VARADERO) + +/datum/weather_ss_map_holder/new_varadero/weather_warning() + for (var/obj/structure/machinery/storm_siren/WS in weather_notify_objects) + WS.weather_warning() diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm new file mode 100644 index 000000000000..8d1a55275fc6 --- /dev/null +++ b/code/datums/world_topic.dm @@ -0,0 +1,331 @@ +/datum/world_topic + /// query key + var/key + + /// can be used with anonymous authentication + var/anonymous = FALSE + + var/list/required_params = list() + var/statuscode + var/response + var/data + +/datum/world_topic/proc/CheckParams(list/params) + var/list/missing_params = list() + var/errorcount = 0 + + for(var/param in required_params) + if(!params[param]) + errorcount++ + missing_params += param + + if(errorcount) + statuscode = 400 + response = "Bad Request - Missing parameters" + data = missing_params + return errorcount + +/datum/world_topic/proc/Run(list/input) + // Always returns true; actual details in statuscode, response and data variables + return TRUE + +// API INFO TOPICS + +/datum/world_topic/api_get_authed_functions + key = "api_get_authed_functions" + anonymous = TRUE + +/datum/world_topic/api_get_authed_functions/Run(list/input) + . = ..() + var/list/functions = GLOB.topic_tokens[input["auth"]] + if(functions) + statuscode = 200 + response = "Authorized functions retrieved" + data = functions + else + statuscode = 401 + response = "Unauthorized - No functions found" + data = null + +// TOPICS + +/datum/world_topic/ping + key = "ping" + anonymous = TRUE + +/datum/world_topic/ping/Run(list/input) + . = ..() + statuscode = 200 + response = "Pong!" + data = length(GLOB.clients) + +/datum/world_topic/playing + key = "playing" + anonymous = TRUE + +/datum/world_topic/playing/Run(list/input) + . = ..() + statuscode = 200 + response = "Player count retrieved" + data = length(GLOB.player_list) + +/datum/world_topic/adminwho + key = "adminwho" + +/datum/world_topic/adminwho/Run(list/input) + . = ..() + var/list/admins = list() + for(var/client/admin in GLOB.admins) + admins += list( + "ckey" = admin.ckey, + "key" = admin.key, + "rank" = admin.admin_holder.rank, + "stealth" = admin.admin_holder.fakekey ? TRUE : FALSE, + "afk" = admin.is_afk(), + ) + statuscode = 200 + response = "Admin list fetched" + data = admins + +/datum/world_topic/playerlist + key = "playerlist" + anonymous = TRUE + +/datum/world_topic/playerlist/Run(list/input) + . = ..() + data = list() + for(var/client/C as() in GLOB.clients) + data += C.ckey + statuscode = 200 + response = "Player list fetched" + +/datum/world_topic/status + key = "status" + anonymous = TRUE + +/datum/world_topic/status/Run(list/input) + . = ..() + data = list() + + data["mode"] = GLOB.master_mode + data["vote"] = CONFIG_GET(flag/allow_vote_mode) + data["ai"] = CONFIG_GET(flag/allow_ai) + data["host"] = world.host ? world.host : null + data["round_id"] = text2num(GLOB.round_id) + data["players"] = length(GLOB.clients) + data["revision"] = GLOB.revdata.commit + data["revision_date"] = GLOB.revdata.date + + var/list/adm = get_admin_counts() + var/list/presentmins = adm["present"] + var/list/afkmins = adm["afk"] + data["admins"] = length(presentmins) + length(afkmins) //equivalent to the info gotten from adminwho + data["gamestate"] = SSticker.current_state + + data["map_name"] = SSmapping.configs[GROUND_MAP]?.map_name || "Loading..." + + data["security_level"] = get_security_level() + data["round_duration"] = ROUND_TIME + // Amount of world's ticks in seconds, useful for calculating round duration + + //Time dilation stats. + data["time_dilation_current"] = SStime_track.time_dilation_current + data["time_dilation_avg"] = SStime_track.time_dilation_avg + data["time_dilation_avg_slow"] = SStime_track.time_dilation_avg_slow + data["time_dilation_avg_fast"] = SStime_track.time_dilation_avg_fast + + data["mcpu"] = world.map_cpu + data["cpu"] = world.cpu + + statuscode = 200 + response = "Status retrieved" + +/datum/world_topic/status/authed + key = "status_authed" + anonymous = FALSE + +/datum/world_topic/status/authed/Run(list/input) + . = ..() + // Add on a little extra data for our "special" patrons + data["active_players"] = get_active_player_count() + if(SSticker.HasRoundStarted()) + data["real_mode"] = SSticker.mode.name + +/datum/world_topic/certify + key = "certify" + required_params = list("identifier", "discord_id") + +/datum/world_topic/certify/Run(list/input) + var/identifier = input["identifier"] + var/discord_id = input["discord_id"] + + data = list() + + var/datum/view_record/discord_link/existing_link = locate() in DB_VIEW(/datum/view_record/discord_link, DB_COMP("discord_id", DB_EQUALS, discord_id)) + + if(existing_link) + statuscode = 504 + response = "Discord ID already verified." + return + + var/datum/entity/discord_identifier/id = get_discord_identifier_by_token(identifier) + + if(!id || !id.playerid) + id.delete() + + statuscode = 500 + response = "Database query failed" + return + + if(id.realtime < world.realtime - 4 HOURS) + statuscode = 501 + response = "Authentication timed out." + + var/datum/entity/player/player = DB_ENTITY(/datum/entity/player, id.playerid) + player.sync() + + if(!player.ckey) + statuscode = 500 + response = "Database query failed." + return + + data["ckey"] = player.ckey + data["roles"] = get_whitelisted_roles(player.ckey) + + if(player.discord_link) + statuscode = 503 + response = "Player already authenticated." + return + + var/datum/entity/discord_link/link = DB_EKEY(/datum/entity/discord_link, discord_id) + link.discord_id = discord_id + link.player_id = text2num(player.id) + link.save() + link.sync() + + player.discord_link = link + player.discord_link_id = link.id + player.save() + player.sync() + + id.used = TRUE + id.save() + id.sync() + + statuscode = 200 + response = "Successfully certified." + data["related_ckeys"] = analyze_ckey(player.ckey) + +/datum/world_topic/decertify_by_ckey + key = "decertify_ckey" + required_params = list("ckey") + +/datum/world_topic/decertify_by_ckey/Run(list/input) + data = list() + + var/datum/entity/player/player = get_player_from_key(input["ckey"]) + + if(!player) + statuscode = 500 + response = "Database lookup failed." + return + + if(!player.discord_link) + statuscode = 501 + response = "No linked Discord." + return + + var/discord_id = player.discord_link.discord_id + + player.discord_link.delete() + player.discord_link = null + + player.discord_link_id = null + player.save() + player.sync() + + data["discord_id"] = discord_id + statuscode = 200 + response = "Decertification successful." + +/datum/world_topic/decertify_by_discord_id + key = "decertify_discord_id" + required_params = list("discord_id") + +/datum/world_topic/decertify_by_discord_id/Run(list/input) + data = list() + + var/datum/view_record/discord_link/link = locate() in DB_VIEW(/datum/view_record/discord_link, DB_COMP("discord_id", DB_EQUALS, input["discord_id"])) + + if(!link || !link.player_id) + statuscode = 500 + response = "Database lookup failed." + return + + var/datum/entity/player/player = DB_ENTITY(/datum/entity/player, link.player_id) + player.sync() + + if(!player.discord_link) + statuscode = 501 + response = "No linked Discord." + return + + player.discord_link.delete() + player.discord_link = null + + player.discord_link_id = null + player.save() + player.sync() + + data["discord_id"] = input["discord_id"] + data["ckey"] = player.ckey + statuscode = 200 + response = "Decertification successful." + +/datum/world_topic/lookup_discord_id + key = "lookup_discord_id" + required_params = list("discord_id") + +/datum/world_topic/lookup_discord_id/Run(list/input) + data = list() + + var/datum/view_record/discord_link/link = locate() in DB_VIEW(/datum/view_record/discord_link, DB_COMP("discord_id", DB_EQUALS, input["discord_id"])) + + if(!link || !link.player_id) + statuscode = 500 + response = "Database lookup failed." + return + + var/datum/view_record/players/player = locate() in DB_VIEW(/datum/view_record/players, DB_COMP("id", DB_EQUALS, link.player_id)) + + data["notes"] = get_all_notes(player.ckey) + data["total_minutes"] = get_total_living_playtime(player.id) + data["ckey"] = player.ckey + data["roles"] = get_whitelisted_roles(player.ckey) + statuscode = 200 + response = "Lookup successful." + +/datum/world_topic/lookup_ckey + key = "lookup_ckey" + required_params = list("ckey") + +/datum/world_topic/lookup_ckey/Run(list/input) + data = list() + + var/datum/view_record/players/player = locate() in DB_VIEW(/datum/view_record/players, DB_COMP("ckey", DB_EQUALS, input["ckey"])) + if(!player) + statuscode = 501 + response = "Database lookup failed." + return + + if(player.discord_link_id) + var/datum/view_record/discord_link/link = locate() in DB_VIEW(/datum/view_record/discord_link, DB_COMP("id", DB_EQUALS, player.discord_link_id)) + + if(link && link.discord_id) + data["discord_id"] = link.discord_id + + data["notes"] = get_all_notes(player.ckey) + data["total_minutes"] = get_total_living_playtime(player.id) + data["roles"] = get_whitelisted_roles(player.ckey) + statuscode = 200 + response = "Lookup successful." diff --git a/code/datums/xeno_shields/shield_types/vanguard_shield.dm b/code/datums/xeno_shields/shield_types/vanguard_shield.dm index 410925b7c19f..5b9eebc04ab8 100644 --- a/code/datums/xeno_shields/shield_types/vanguard_shield.dm +++ b/code/datums/xeno_shields/shield_types/vanguard_shield.dm @@ -1,7 +1,7 @@ // Vanguard shields rapidly decay after the first hit. /datum/xeno_shield/vanguard var/hit_yet = FALSE - var/explosive_armor_amount = XENO_EXPOSIVEARMOR_MOD_VERYLARGE + var/explosive_armor_amount = XENO_EXPOSIVEARMOR_MOD_VERY_LARGE amount = 800 /datum/xeno_shield/vanguard/on_hit(damage) diff --git a/code/defines/procs/announcement.dm b/code/defines/procs/announcement.dm index f68f9376e96d..5223d63b8e59 100644 --- a/code/defines/procs/announcement.dm +++ b/code/defines/procs/announcement.dm @@ -30,7 +30,7 @@ //general marine announcement -/proc/marine_announcement(message, title = COMMAND_ANNOUNCE, sound_to_play = sound('sound/misc/notice2.ogg'), faction_to_display = FACTION_MARINE, add_PMCs = TRUE, signature) +/proc/marine_announcement(message, title = COMMAND_ANNOUNCE, sound_to_play = sound('sound/misc/notice2.ogg'), faction_to_display = FACTION_MARINE, add_PMCs = TRUE, signature, logging = ARES_LOG_MAIN) var/list/targets = GLOB.human_mob_list + GLOB.dead_mob_list if(faction_to_display == FACTION_MARINE) for(var/mob/M in targets) @@ -45,6 +45,14 @@ if((H.faction != faction_to_display && !add_PMCs) || (H.faction != faction_to_display && add_PMCs && !(H.faction in FACTION_LIST_WY)) && !(faction_to_display in H.faction_group)) //faction checks targets.Remove(H) + var/datum/ares_link/link = GLOB.ares_link + if(ares_can_log()) + switch(logging) + if(ARES_LOG_MAIN) + link.log_ares_announcement(title, message) + if(ARES_LOG_SECURITY) + link.log_ares_security(title, message) + else if(faction_to_display == "Everyone (-Yautja)") for(var/mob/M in targets) if(isobserver(M)) //observers see everything @@ -82,7 +90,7 @@ announcement_helper(message, title, targets, sound_to_play) //AI announcement that uses talking into comms -/proc/ai_announcement(message, sound_to_play = sound('sound/misc/interference.ogg')) +/proc/ai_announcement(message, sound_to_play = sound('sound/misc/interference.ogg'), logging = ARES_LOG_MAIN) for(var/mob/M in (GLOB.human_mob_list + GLOB.dead_mob_list)) if(isobserver(M) || ishuman(M) && is_mainship_level(M.z)) playsound_client(M.client, sound_to_play, M, vol = 45) @@ -90,6 +98,14 @@ for(var/mob/living/silicon/decoy/ship_ai/AI in ai_mob_list) INVOKE_ASYNC(AI, TYPE_PROC_REF(/mob/living/silicon/decoy/ship_ai, say), message) + var/datum/ares_link/link = GLOB.ares_link + if(ares_can_log()) + switch(logging) + if(ARES_LOG_MAIN) + link.log_ares_announcement("[MAIN_AI_SYSTEM] Comms Update", message) + if(ARES_LOG_SECURITY) + link.log_ares_security("[MAIN_AI_SYSTEM] Security Update", message) + /proc/ai_silent_announcement(message, channel_prefix, bypass_cooldown = FALSE) if(!message) return @@ -119,10 +135,14 @@ if(!isnull(signature)) message += "

Signed by,
[signature]
" + var/datum/ares_link/link = GLOB.ares_link + if(link.interface && !(link.interface.inoperable())) + link.log_ares_announcement(title, message) announcement_helper(message, title, targets, sound_to_play) + //Subtype of AI shipside announcement for "All Hands On Deck" alerts (COs and SEAs joining the game) -/proc/all_hands_on_deck(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/sound_misc_boatswain.ogg'), signature) +/proc/all_hands_on_deck(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/sound_misc_boatswain.ogg')) var/list/targets = GLOB.human_mob_list + GLOB.dead_mob_list for(var/mob/T in targets) if(isobserver(T)) @@ -130,6 +150,10 @@ if(!ishuman(T) || isyautja(T) || !is_mainship_level(T.z)) targets.Remove(T) + var/datum/ares_link/link = GLOB.ares_link + if(ares_can_log()) + link.log_ares_announcement("[title] Shipwide Update", message) + announcement_helper(message, title, targets, sound_to_play) //the announcement proc that handles announcing for each mob in targets list @@ -140,5 +164,5 @@ if(istype(T, /mob/new_player)) continue - to_chat_spaced(T, html = "[SPAN_ANNOUNCEMENT_HEADER(title)]

[SPAN_ANNOUNCEMENT_BODY(message)]") + to_chat_spaced(T, html = "[SPAN_ANNOUNCEMENT_HEADER(title)]

[SPAN_ANNOUNCEMENT_BODY(message)]", type = MESSAGE_TYPE_RADIO) playsound_client(T.client, sound_to_play, T, vol = 45) diff --git a/code/game/area/BigRed.dm b/code/game/area/BigRed.dm index cf1b235842cb..59d7c40cd56f 100644 --- a/code/game/area/BigRed.dm +++ b/code/game/area/BigRed.dm @@ -325,6 +325,9 @@ is_resin_allowed = FALSE soundscape_playlist = SCAPE_PL_DESERT_STORM +/area/bigredv2/outside/nw/ceiling + ceiling = CEILING_GLASS + /area/bigredv2/outside/c name = "\improper Central Colony Grounds" icon_state = "purple" @@ -485,7 +488,7 @@ /area/bigredv2/outside/space_port name = "\improper Space Port" icon_state = "green" - ceiling = CEILING_NONE + ceiling = CEILING_GLASS is_resin_allowed = FALSE is_landing_zone = TRUE diff --git a/code/game/area/IceColony.dm b/code/game/area/IceColony.dm index 2582bf3a0350..2c7bbee2969c 100644 --- a/code/game/area/IceColony.dm +++ b/code/game/area/IceColony.dm @@ -46,7 +46,6 @@ /area/ice_colony/exterior/surface name = "\improper Ice Colony - Exterior Surface" - fake_zlevel = 1 // above ground soundscape_playlist = SCAPE_PL_WIND //Equivalent of space. None of this area should be accessible. If these are valleys, make separate areas @@ -153,7 +152,6 @@ name = "\improper Ice Colony - Exterior Underground" icon_state = "cave" ceiling = CEILING_DEEP_UNDERGROUND - fake_zlevel = 2 // underground ambience_exterior = null // // Caves @@ -189,7 +187,6 @@ name = "\improper Ice Colony - Built Surface" icon_state = "clear" ceiling = CEILING_METAL - fake_zlevel = 1 // above ground /* * Surface - Bar @@ -485,7 +482,6 @@ name = "\improper Ice Colony - Built Underground" icon_state = "explored" ceiling = CEILING_DEEP_UNDERGROUND_METAL - fake_zlevel = 2 // underground ambience_exterior = AMBIENCE_ALMAYER ceiling_muffle = FALSE sound_environment = SOUND_ENVIRONMENT_ROOM diff --git a/code/game/area/LV522_Chances_Claim.dm b/code/game/area/LV522_Chances_Claim.dm index f2838f6ffb3b..3d15d49c3df7 100644 --- a/code/game/area/LV522_Chances_Claim.dm +++ b/code/game/area/LV522_Chances_Claim.dm @@ -28,6 +28,10 @@ is_resin_allowed = FALSE flags_area = AREA_NOTUNNEL +/area/lv522/oob/w_y_vault + name = "LV522 - Weyland Secure Vault" + icon_state = "blue" + //Landing Zone 1 /area/lv522/landing_zone_1 @@ -409,10 +413,12 @@ /area/lv522/atmos/east_reactor/north name = "Atmospheric Processor - Outer East Reactor - North" icon_state = "yellow" + ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS /area/lv522/atmos/east_reactor/south name = "Atmospheric Processor - Outer East Reactor - south" icon_state = "red" + ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS /area/lv522/atmos/east_reactor/south/cas ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS @@ -420,10 +426,13 @@ /area/lv522/atmos/east_reactor/east name = "Atmospheric Processor - Outer East Reactor - east" icon_state = "green" + ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS /area/lv522/atmos/east_reactor/west name = "Atmospheric Processor - Outer East Reactor - west" icon_state = "purple" + ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS + /area/lv522/atmos/west_reactor name = "Atmospheric Processor - Western Reactor" icon_state = "blue" @@ -441,8 +450,24 @@ /area/lv522/atmos/north_command_centre name = "Atmospheric Processor - North Command Centre Checkpoint" icon_state = "green" + ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS /area/lv522/atmos/filt name = "Atmospheric Processor - Filtration System" icon_state = "mechbay" ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS + +/area/lv522/atmos/way_in_command_centre + name = "Atmospheric Processor - North Corpo Reactor Entrance" + icon_state = "blue" + ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS + +/area/lv522/atmos/sewer + name = "Atmospheric Processor - Sewer" + icon_state = "red" + ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS + +/area/lv522/atmos/reactor_garage + name = "Atmospheric Processor - Garage" + icon_state = "green" + ceiling = CEILING_UNDERGROUND_METAL_BLOCK_CAS diff --git a/code/game/area/LV624.dm b/code/game/area/LV624.dm index 0b839bca98a3..505387f8e52b 100644 --- a/code/game/area/LV624.dm +++ b/code/game/area/LV624.dm @@ -30,11 +30,17 @@ icon_state = "southwest" //ambience = list('sound/ambience/jungle_amb1.ogg') +/area/lv624/ground/jungle/south_west_jungle/ceiling + ceiling = CEILING_GLASS + /area/lv624/ground/jungle/west_jungle name ="\improper Western Jungle" icon_state = "west" //ambience = list('sound/ambience/jungle_amb1.ogg') +/area/lv624/ground/jungle/west_jungle/ceiling + ceiling = CEILING_GLASS + /area/lv624/ground/jungle/east_jungle name ="\improper Eastern Jungle" icon_state = "east" @@ -82,11 +88,17 @@ icon_state = "west" //ambience = list('sound/ambience/ambimine.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambisin4.ogg') +/area/lv624/ground/barrens/west_barrens/ceiling + ceiling = CEILING_GLASS + /area/lv624/ground/barrens/east_barrens name = "\improper Eastern Barrens" icon_state = "east" //ambience = list('sound/ambience/ambimine.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambisin4.ogg') +/area/lv624/ground/barrens/east_barrens/ceiling + ceiling = CEILING_GLASS + /area/lv624/ground/barrens/containers name = "\improper Containers" icon_state = "blue-red" @@ -97,6 +109,9 @@ icon_state = "northeast" //ambience = list('sound/ambience/ambimine.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambisin4.ogg') +/area/lv624/ground/barrens/north_east_barrens/ceiling + ceiling = CEILING_GLASS + /area/lv624/ground/barrens/south_west_barrens name = "\improper South Western Barrens" icon_state = "southwest" diff --git a/code/game/area/Sulaco.dm b/code/game/area/Sulaco.dm index a8e0cc8961c1..851025e1b63a 100644 --- a/code/game/area/Sulaco.dm +++ b/code/game/area/Sulaco.dm @@ -13,6 +13,7 @@ is_resin_allowed = FALSE flags_area = AREA_NOTUNNEL is_landing_zone = TRUE + ceiling = CEILING_REINFORCED_METAL /area/shuttle/drop1/Enter(atom/movable/O, atom/oldloc) if(istype(O, /obj/structure/barricade)) @@ -69,6 +70,7 @@ is_resin_allowed = FALSE flags_area = AREA_NOTUNNEL is_landing_zone = TRUE + ceiling = CEILING_REINFORCED_METAL /area/shuttle/drop2/sulaco name = "\improper Dropship Normandy" diff --git a/code/game/area/admin_level.dm b/code/game/area/admin_level.dm index 3a79546d177d..501047c46d08 100644 --- a/code/game/area/admin_level.dm +++ b/code/game/area/admin_level.dm @@ -110,9 +110,25 @@ /area/adminlevel/ert_station name = "ERT Station" icon_state = "green" - requires_power = 0 + requires_power = FALSE flags_area = AREA_NOTUNNEL +/area/adminlevel/ert_station/upp_station + name = "UPP Station" + icon_state = "green" + +/area/adminlevel/ert_station/clf_station + name = "CLF Station" + icon_state = "white" + +/area/adminlevel/ert_station/weyland_station + name = "Weyland-Yutani Station" + icon_state = "red" + +/area/adminlevel/ert_station/freelancer_station + name = "Freelancer Station" + icon_state = "yellow" + /area/adminlevel/ert_station/shuttle_dispatch name = "Shuttle Dispatch Station" soundscape_playlist = SCAPE_PL_ELEVATOR_MUSIC diff --git a/code/game/area/almayer.dm b/code/game/area/almayer.dm index a23f84323301..6ced81a22b15 100644 --- a/code/game/area/almayer.dm +++ b/code/game/area/almayer.dm @@ -77,17 +77,20 @@ fake_zlevel = 1 // upperdeck soundscape_playlist = SCAPE_PL_ARES soundscape_interval = 120 - flags_area = AREA_NOTUNNEL + flags_area = AREA_NOTUNNEL|AREA_UNWEEDABLE + can_build_special = FALSE + is_resin_allowed = FALSE + resin_construction_allowed = FALSE /area/almayer/command/securestorage name = "\improper Secure Storage" icon_state = "corporatespace" - fake_zlevel = 1 // upperdeck + fake_zlevel = 2 // lowerdeck /area/almayer/command/computerlab name = "\improper Computer Lab" icon_state = "ceroom" - fake_zlevel = 1 // upperdeck + fake_zlevel = 2 // lowerdeck /area/almayer/command/telecomms name = "\improper Telecommunications" @@ -181,6 +184,11 @@ icon_state = "astronavigation" fake_zlevel = 2 // lowerdeck +/area/almayer/shipboard/panic + name = "\improper Hangar Panic Room" + icon_state = "brig" + fake_zlevel = 2 // lowerdeck + /area/almayer/shipboard/starboard_missiles name = "\improper Missile Tubes Starboard" icon_state = "starboardmissile" @@ -309,6 +317,11 @@ icon_state = "livingspace" fake_zlevel = 2 +/area/almayer/living/auxiliary_officer_office + name = "\improper Auxiliary Support Officer office" + icon_state = "livingspace" + fake_zlevel = 2 + /area/almayer/squads/tankdeliveries name = "\improper Vehicle ASRS" icon_state = "req" diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 0e9560aeeea2..73fcd936fe25 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -1,6 +1,10 @@ // Areas.dm // === + +///define used to mute an area base_muffle = AREA_MUTED +#define AREA_MUTED -10000 + /area var/atmosalm = 0 var/poweralm = 1 @@ -98,6 +102,8 @@ active_areas += src all_areas += src reg_in_areas_in_z() + if(is_mainship_level(z)) + GLOB.ship_areas += src if(!is_ground_level(z)) return diff --git a/code/game/area/shuttles.dm b/code/game/area/shuttles.dm index 084dfc2ac97d..f61f13097d12 100644 --- a/code/game/area/shuttles.dm +++ b/code/game/area/shuttles.dm @@ -45,6 +45,27 @@ icon = 'icons/turf/area_almayer.dmi' icon_state = "lifeboat" +/area/shuttle/trijent_shuttle + name = "Trijent Elevator" + icon = 'icons/turf/area_almayer.dmi' + icon_state = "lifeboat" + +/area/shuttle/trijent_shuttle/elevator + requires_power = TRUE + lighting_use_dynamic = FALSE + powernet_name = "ground" + +/area/shuttle/trijent_shuttle/lz1 + name = "Trijent LZ1" + +/area/shuttle/trijent_shuttle/lz2 + name = "Trijent LZ2" + +/area/shuttle/trijent_shuttle/engi + name = "Trijent Engineering" + +/area/shuttle/trijent_shuttle/omega + name = "Trijent Omega" /area/shuttle/escape_pod icon = 'icons/turf/area_almayer.dmi' icon_state = "lifeboat" diff --git a/code/game/area/space_station_13_areas.dm b/code/game/area/space_station_13_areas.dm index 1d49735c1c2f..226ca555cd57 100644 --- a/code/game/area/space_station_13_areas.dm +++ b/code/game/area/space_station_13_areas.dm @@ -27,6 +27,9 @@ NOTE: there are two lists of areas in the end of this file: centcom and station flags_area = AREA_NOTUNNEL weather_enabled = FALSE + //fix for issue https://github.com/cmss13-devs/cmss13/issues/2191 + base_muffle = AREA_MUTED + /area/engine //ambience = list('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg') diff --git a/code/game/area/strata.dm b/code/game/area/strata.dm index 3049a28c15aa..1cf0eac58d1c 100644 --- a/code/game/area/strata.dm +++ b/code/game/area/strata.dm @@ -27,16 +27,9 @@ EXTERIOR is FUCKING FREEZING, and refers to areas out in the open and or exposed lighting_use_dynamic = 0 minimap_color = MINIMAP_AREA_LZ - -/*A WHOLE BUNCH OF PARENT ENTITIES -fake_zlevel = 1 or 2. 1 is 'above' 2 is 'below', however ladders are flipped and think that 1 is below, and 2 is above. -But, players don't actually care where they are so long as the ladders look correct going up and down. They shouldn't notice. -However, this might break the tacmap. This entire system might be replaced by Slywater's fake-Z smooth transition anyway.*/ - /area/strata/ag name = "Above Ground Area" icon_state = "ag" - fake_zlevel = 1 //'Above' ground fake Z /area/strata/ag/exterior name = "Exterior Above Ground Area" @@ -57,6 +50,10 @@ However, this might break the tacmap. This entire system might be replaced by Sl temperature = T20C //Nice and room temp ceiling = CEILING_METAL +/area/strata/ag/interior/mountain + name = "Outside mountain" + icon_state = "ag_e" + /area/strata/ag/interior/restricted is_resin_allowed = FALSE flags_area = AREA_NOTUNNEL @@ -67,7 +64,6 @@ However, this might break the tacmap. This entire system might be replaced by Sl /area/strata/ug name = "Under Ground Area" icon_state = "ug" - fake_zlevel = 2 //'Underground', because numbers are fun ceiling = CEILING_UNDERGROUND_ALLOW_CAS /area/strata/ug/interior diff --git a/code/game/area/varadero.dm b/code/game/area/varadero.dm index a0d005d4aa1d..09b082f2acd6 100644 --- a/code/game/area/varadero.dm +++ b/code/game/area/varadero.dm @@ -4,8 +4,7 @@ /area/varadero name = "New Varadero" icon = 'icons/turf/area_varadero.dmi' - ambience_exterior = AMBIENCE_LV624 - sound_environment = SOUND_ENVIRONMENT_MOUNTAINS + ambience_exterior = AMBIENCE_NV icon_state = "varadero" can_build_special = TRUE //T-Comms structure temperature = TROPICAL_TEMP @@ -36,49 +35,44 @@ /area/varadero/exterior name = "New Varadero - Exterior" ceiling = CEILING_NONE - ambience_exterior = AMBIENCE_LV624 + lighting_use_dynamic = TRUE + ambience_exterior = AMBIENCE_NV //soundscape_playlist - sound_environment = SOUND_ENVIRONMENT_MOUNTAINS /area/varadero/interior name = "New Varadero - Interior" - ceiling = CEILING_UNDERGROUND_ALLOW_CAS + ceiling = CEILING_GLASS ambience_exterior = AMBIENCE_PRISON //soundscape_playlist sound_environment = SOUND_ENVIRONMENT_ROOM /area/varadero/interior_protected name = "New Varadero - Interior" - ceiling = CEILING_DEEP_UNDERGROUND - icon_state = "NV_no_OB" + ceiling = CEILING_UNDERGROUND_BLOCK_CAS + sound_environment = SOUND_ENVIRONMENT_AUDITORIUM + icon_state = "NV_no_CAS" /area/varadero/interior/comms1 name = "New Varadero - Cargo Generator" + is_resin_allowed = FALSE icon_state = "comms1" + minimap_color = MINIMAP_AREA_ENGI_CAVE /area/varadero/interior/comms2 name = "New Varadero - Communications Project Site" - is_resin_allowed = FALSE icon_state = "comms2" + minimap_color = MINIMAP_AREA_ENGI_CAVE /area/varadero/interior/comms3 - name = "New Varadero - Fishing Hole" - is_resin_allowed = FALSE + name = "New Varadero - Engineering Communications" icon_state = "comms3" + minimap_color = MINIMAP_AREA_ENGI_CAVE /area/varadero/exterior/comms4 name = "New Varadero - Walkway Extension" - icon_state = "comms4" - -/area/varadero/exterior/eastbeach - name = "New Varadero - East Beach" - icon_state = "varadero1" - -/area/varadero/exterior/eastocean - name = "New Varadero - East Ocean" is_resin_allowed = FALSE - flags_area = AREA_NOTUNNEL - icon_state = "varadero2" + icon_state = "comms4" + minimap_color = MINIMAP_AREA_ENGI_CAVE /area/varadero/interior/oob name = "New Varadero - Out Of Bounds" @@ -119,9 +113,57 @@ name = "New Varadero - Rockabilly Beach" icon_state = "varadero0" is_resin_allowed = FALSE + minimap_color = MINIMAP_AREA_JUNGLE + +/area/varadero/exterior/eastbeach + name = "New Varadero - East Beach" + is_resin_allowed = FALSE + icon_state = "varadero1" + lighting_use_dynamic = TRUE + minimap_color = MINIMAP_AREA_JUNGLE + +/area/varadero/exterior/monsoon + name = "New Varadero - Monsoon" + icon_state = "varadero1" + minimap_color = MINIMAP_AREA_JUNGLE + +/area/varadero/exterior/pool + name = "New Varadero - Interior Pool" + icon_state = "varadero1" + lighting_use_dynamic = TRUE + minimap_color = MINIMAP_AREA_COMMAND_CAVE + +/area/varadero/exterior/eastocean + name = "New Varadero - East Ocean" + is_resin_allowed = FALSE + flags_area = AREA_NOTUNNEL + icon_state = "varadero2" + minimap_color = MINIMAP_AREA_CONTESTED_ZONE + +/area/varadero/exterior/farocean + name = "New Varadero - Far Ocean" + is_resin_allowed = FALSE + flags_area = AREA_NOTUNNEL + icon_state = "varadero3" + minimap_color = MINIMAP_AREA_CONTESTED_ZONE //interior areas + +/area/varadero/interior/beach_bar + name = "New Varadero - Beach Bar" + icon_state = "varadero4" + is_resin_allowed = FALSE + minimap_color = MINIMAP_AREA_JUNGLE + sound_environment = SOUND_ENVIRONMENT_ROOM + +/area/varadero/interior/dock_control + name = "New Varadero - Dock Control" + icon_state = "varadero3" + is_resin_allowed = FALSE + minimap_color = MINIMAP_AREA_JUNGLE + sound_environment = SOUND_ENVIRONMENT_ROOM + /area/varadero/interior/cargo name = "New Varadero - Cargo" icon_state = "req0" @@ -145,15 +187,18 @@ name = "New Vardero - Chapel" icon_state = "offices1" is_resin_allowed = FALSE + minimap_color = MINIMAP_AREA_COMMAND_CAVE /area/varadero/interior/morgue name = "New Varadero - Morgue" icon_state = "offices0" is_resin_allowed = FALSE + minimap_color = MINIMAP_AREA_MEDBAY_CAVE /area/varadero/interior/medical name = "New Varadero - Medical" icon_state = "offices2" + minimap_color = MINIMAP_AREA_MEDBAY /area/varadero/interior/maintenance name = "New Varadero - Central Maintenance" @@ -167,10 +212,12 @@ /area/varadero/interior/maintenance/research name = "New Varadero - Research Maintenance" icon_state = "tunnels1" + minimap_color = MINIMAP_AREA_RESEARCH_CAVE /area/varadero/interior/maintenance/security name = "New Varadero - Security Maintenance" icon_state = "tunnels2" + minimap_color = MINIMAP_AREA_SEC_CAVE /area/varadero/interior/research name = "New Varadero - Research Offices" @@ -180,6 +227,7 @@ /area/varadero/interior/electrical name = "New Varadero - Electrical Annex" icon_state = "req4" + minimap_color = MINIMAP_AREA_ENGI /area/varadero/interior/toilets name = "New Varadero - Restrooms" @@ -188,6 +236,7 @@ /area/varadero/interior/technical_storage name = "New Varadero - Technical Storage" icon_state = "req3" + minimap_color = MINIMAP_AREA_ENGI /area/varadero/interior/laundry name = "New Varadero - Laundry" @@ -196,31 +245,38 @@ /area/varadero/interior/disposals name = "New Varadero - Disposals" icon_state = "offices4" + minimap_color = MINIMAP_AREA_ENGI /area/varadero/interior/administration name = "New Varadero - Administrative Offices" icon_state = "offices2" + minimap_color = MINIMAP_AREA_COMMAND /area/varadero/interior/library name = "New Varadero - Library" icon_state = "offices0" is_resin_allowed = FALSE + minimap_color = MINIMAP_AREA_COMMAND_CAVE /area/varadero/interior/court name = "New Varadero - Basketball Court" icon_state = "req4" + minimap_color = MINIMAP_AREA_COMMAND_CAVE /area/varadero/interior/mess name = "New Varadero - Mess Hall" icon_state = "req2" + minimap_color = MINIMAP_AREA_COMMAND_CAVE /area/varadero/interior/bunks name = "New Varadero - Level 1 Quarters" icon_state = "req3" + minimap_color = MINIMAP_AREA_JUNGLE /area/varadero/interior/security name = "New Varadero - Security Offices" icon_state = "offices0" + minimap_color = MINIMAP_AREA_SEC /area/varadero/interior/records name = "New Varadero - Records" @@ -238,12 +294,12 @@ power_environ = FALSE luminosity = 0 lighting_use_dynamic = 1 + sound_environment = SOUND_ENVIRONMENT_AUDITORIUM minimap_color = MINIMAP_AREA_CAVES /area/varadero/interior/caves/north_research name = "New Varadero - North Research Caves" icon_state = "tunnels4" - minimap_color = MINIMAP_AREA_RESEARCH_CAVE /area/varadero/interior/caves/east name = "New Varadero - Beach Caves" @@ -257,20 +313,25 @@ power_environ = FALSE luminosity = 0 lighting_use_dynamic = 1 - minimap_color = MINIMAP_AREA_RESEARCH_CAVE /area/varadero/interior_protected/caves/central name = "New Varadero - Grass Caves" icon_state = "deepcaves2" + minimap_color = MINIMAP_AREA_CAVES /area/varadero/interior_protected/caves/digsite name = "New Varadero - Dig Site" icon_state = "deepcaves3" +/area/varadero/interior_protected/caves/swcaves + name = "New Varadero - Southwest Caves" + icon_state = "deepcaves3" + /area/varadero/interior_protected/maintenance/south name = "New Varadero - Southern Maintenance" icon_state = "deepcaves4" + minimap_color = MINIMAP_AREA_CAVES /area/varadero/interior_protected/vessel name = "New Varadero - Unknown Vessel" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index eb82917b575d..d2cad09edc83 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -439,7 +439,7 @@ Parameters are passed from New. return TRUE if(href_list["desc_lore"]) - show_browser(usr, "[replacetext(desc_lore, "\n", "
")]
", name, name, "size=500x200") + show_browser(usr, "[replacetext(desc_lore, "\n", "
")]
", name, name, "size=500x500") onclose(usr, "[name]") ///This proc is called on atoms when they are loaded into a shuttle @@ -580,7 +580,7 @@ Parameters are passed from New. if(!ismovable(src)) var/turf/curturf = get_turf(src) if(curturf) - . += "" + . += "" VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRANSFORM, "Modify Transform") VV_DROPDOWN_OPTION(VV_HK_ADD_REAGENT, "Add Reagent") VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse") @@ -625,10 +625,10 @@ Parameters are passed from New. log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to [src]") message_admins(SPAN_NOTICE("[key_name(usr)] has added [amount] units of [chosen_id] to [src]")) - if(href_list[VV_HK_TRIGGER_EXPLOSION] && check_rights(R_EVENT)) + if(href_list[VV_HK_TRIGGER_EXPLOSION] && check_rights(R_ADMIN)) usr.client.handle_bomb_drop(src) - if(href_list[VV_HK_TRIGGER_EMP] && check_rights(R_EVENT)) + if(href_list[VV_HK_TRIGGER_EMP] && check_rights(R_ADMIN)) usr.client.cmd_admin_emp(src) if(href_list[VV_HK_MODIFY_TRANSFORM] && check_rights(R_VAREDIT)) @@ -660,7 +660,7 @@ Parameters are passed from New. SEND_SIGNAL(src, COMSIG_ATOM_VV_MODIFY_TRANSFORM) if(href_list[VV_HK_AUTO_RENAME] && check_rights(R_VAREDIT)) - var/newname = tgui_input_text(usr, "What do you want to rename this to?", "Automatic Rename", name) + var/newname = tgui_input_text(usr, "What do you want to rename this to?", "Automatic Rename", name, encode = FALSE) if(newname) name = newname diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 6b980136bc9e..17b37ce76630 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -74,6 +74,23 @@ var/client/C = usr.client C?.open_particle_editor(src) +/atom/movable/vv_edit_var(var_name, var_value) + var/static/list/banned_edits = list(NAMEOF_STATIC(src, step_x) = TRUE, NAMEOF_STATIC(src, step_y) = TRUE, NAMEOF_STATIC(src, step_size) = TRUE, NAMEOF_STATIC(src, bounds) = TRUE) + var/static/list/careful_edits = list(NAMEOF_STATIC(src, bound_x) = TRUE, NAMEOF_STATIC(src, bound_y) = TRUE, NAMEOF_STATIC(src, bound_width) = TRUE, NAMEOF_STATIC(src, bound_height) = TRUE) + var/static/list/not_falsey_edits = list(NAMEOF_STATIC(src, bound_width) = TRUE, NAMEOF_STATIC(src, bound_height) = TRUE) + if(banned_edits[var_name]) + return FALSE //PLEASE no. + if(careful_edits[var_name] && (var_value % world.icon_size) != 0) + return FALSE + if(not_falsey_edits[var_name] && !var_value) + return FALSE + + if(!isnull(.)) + datum_flags |= DF_VAR_EDITED + return + + return ..() + //when a mob interact with something that gives them a special view, //check_eye() is called to verify that they're still eligible. //if they are not check_eye() usually reset the mob's view. diff --git a/code/game/bioscans.dm b/code/game/bioscans.dm index d7ec445607b8..62c801a02d29 100644 --- a/code/game/bioscans.dm +++ b/code/game/bioscans.dm @@ -36,7 +36,7 @@ GLOBAL_DATUM_INIT(bioscan_data, /datum/bioscan_data, new) /datum/bioscan_data/proc/get_scan_data() clear_data() /// All larva on all hives - var/larva = 0 + larva = 0 /// Count all larva across all hives @@ -94,45 +94,72 @@ GLOBAL_DATUM_INIT(bioscan_data, /datum/bioscan_data, new) var/marine_planet_location_string = "[marine_planet_location ? ", including one in [marine_planet_location]." : "."]" var/marine_ship_location_string = "[marine_ship_location ? ", including one in [marine_ship_location]." : "."]" + var/ghost_scan = SPAN_ALERT("[xenos_on_planet] xenos on planet, with [larva] larva.\n[xenos_on_ship] xenos on the ship.\n[marines_on_planet] humans on the planet.\n[marines_on_ship] humans on the ship.") + var/yautja_scan = SPAN_ALERT("[xenos_on_planet] serpents present in the hunting ground[xeno_planet_location_string], with [larva] larva.\n[xenos_on_ship] serpents present on the human ship[xeno_ship_location_string]\n[marines_on_planet] humans present in the hunting ground[marine_planet_location_string]\n[marines_on_ship] humans present on the human ship[marine_ship_location_string]") + log_game("BIOSCAN: A Yautja/Ghost bioscan has completed. [ghost_scan]") + //Announce the numbers to Yautja, they have good scanners for(var/mob/living/carbon/human/yautja as anything in GLOB.yautja_mob_list) to_chat(yautja, "

Bioscan complete

") - to_chat(yautja, SPAN_ALERT("[xenos_on_planet] serpents present in the hunting ground[xeno_planet_location_string], with [larva] larva.\n[xenos_on_ship] serpents present on the human ship[xeno_ship_location_string]\n[marines_on_planet] humans present in the hunting ground[marine_planet_location_string]\n[marines_on_ship] humans present on the human ship[marine_ship_location_string]")) + to_chat(yautja, yautja_scan) //Let the ghosts know what's up, they also get good numbers for(var/mob/dead/observer/ghost as anything in GLOB.observer_list) to_chat(ghost, "

Bioscan complete

") - to_chat(ghost, SPAN_ALERT("[xenos_on_planet] xenos on planet, with [larva] larva.\n[xenos_on_ship] xenos on the ship.\n[marines_on_planet] humans on the planet.\n[marines_on_ship] humans on the ship.")) + to_chat(ghost, ghost_scan) /// This will do something after Project ARES. -/datum/bioscan_data/proc/can_ares_bioscan() - return TRUE +/datum/bioscan_data/proc/ares_can_bioscan() + var/datum/ares_link/link = GLOB.ares_link + if(!istype(link)) + return FALSE + if(link.p_bioscan && !link.p_bioscan.inoperable()) + return TRUE + return FALSE /// The announcement to all Humans. Slightly off for the planet and elsewhere, accurate for the ship. /datum/bioscan_data/proc/ares_bioscan(forced = FALSE, variance = 2) - if(!forced && !can_ares_bioscan()) + var/datum/ares_link/link = GLOB.ares_link + if(!forced && !ares_can_bioscan()) message_admins("An ARES Bioscan has failed.") + var/name = "[MAIN_AI_SYSTEM] Bioscan Status" + var/input = "Bioscan failed. \n\nInvestigation into Bioscan subsystem recommended." + if(ares_can_log()) + link.log_ares_bioscan(name, input) + if(ares_can_interface()) + marine_announcement(input, name, 'sound/misc/interference.ogg', logging = ARES_LOG_NONE) return - //Adjust the randomness there so everyone gets the same thing var/fake_xenos_on_planet = max(0, xenos_on_planet + rand(-variance, variance)) - var/name = "[MAIN_AI_SYSTEM] Bioscan Status" var/input = "Bioscan complete.\n\nSensors indicate [xenos_on_ship_uncontained ? "[xenos_on_ship_uncontained]" : "no"] unknown lifeform signature[!xenos_on_ship_uncontained || xenos_on_ship_uncontained > 1 ? "s":""] present on the ship[xenos_on_ship_uncontained && xenos_ship_location ? ", including one in [xenos_ship_location]," : ""] and [fake_xenos_on_planet ? "approximately [fake_xenos_on_planet]" : "no"] signature[!fake_xenos_on_planet || fake_xenos_on_planet > 1 ? "s":""] located elsewhere[fake_xenos_on_planet && xenos_planet_location ? ", including one in [xenos_planet_location]":""]." - marine_announcement(input, name, 'sound/AI/bioscan.ogg') + + log_game("BIOSCAN: ARES bioscan completed. [input]") + + if(forced || ares_can_log()) + link.log_ares_bioscan(name, input) //if interface is down, bioscan still logged, just have to go read it. + if(forced || ares_can_interface()) + marine_announcement(input, name, 'sound/AI/bioscan.ogg', logging = ARES_LOG_NONE) + else + message_admins("An ARES Bioscan has succeeded, but was not announced.") /// The announcement to all Xenos. Slightly off for the human ship, accurate otherwise. /datum/bioscan_data/proc/qm_bioscan(variance = 2) /// Adjust the randomness there so everyone gets the same thing var/fake_marines_on_ship = max(0, marines_on_ship + rand(-variance, variance)) + var/metalhive_hosts = "[fake_marines_on_ship ? "approximately [fake_marines_on_ship]":"no"]" + var/plural = "[!fake_marines_on_ship || fake_marines_on_ship > 1 ? "s":""]" + var/metalhive_location = "[fake_marines_on_ship && marine_ship_location?", including one in [marine_ship_location]," : ""]" + var/planet_hosts = "[marines_on_planet ? "[marines_on_planet]" : "none"]" + var/planet_location = "[marines_on_planet && marine_planet_location ? ", including one in [marine_planet_location]" : ""]" + + var/title = SPAN_XENOANNOUNCE("The Queen Mother reaches into your mind from worlds away.") + var/content = SPAN_XENOANNOUNCE("To my children and their Queen. I sense [metalhive_hosts] host[plural] in the metal hive [metalhive_location] and [planet_hosts] scattered elsewhere[planet_location].") + + log_game("BIOSCAN: Queen Mother bioscan completed. [content]") /// Shout it at everyone for(var/mob/current_mob as anything in GLOB.living_xeno_list) current_mob << sound(get_sfx("queen"), wait = 0, volume = 50) - to_chat(current_mob, SPAN_XENOANNOUNCE("The Queen current_mobother reaches into your mind from worlds away.")) - var/metalhive_hosts = "[fake_marines_on_ship ? "approximately [fake_marines_on_ship]":"no"]" - var/plural = "[!fake_marines_on_ship || fake_marines_on_ship > 1 ? "s":""]" - var/metalhive_location = "[fake_marines_on_ship&&marine_ship_location?", including one in [marine_ship_location],":""]" - var/planet_hosts = "[marines_on_planet ? "[marines_on_planet]" : "none"]" - var/planet_location = "[marines_on_planet && marine_planet_location ? ", including one in [marine_planet_location]" : ""]" - to_chat(current_mob, SPAN_XENOANNOUNCE("To my children and their Queen. I sense [metalhive_hosts] host[plural] in the metal hive [metalhive_location] and [planet_hosts] scattered elsewhere[planet_location].")) + to_chat(current_mob, title) + to_chat(current_mob, content) diff --git a/code/game/cas_manager/datums/cas_fire_envelope.dm b/code/game/cas_manager/datums/cas_fire_envelope.dm index a2c2aa9cdf6b..450fe8e6a82b 100644 --- a/code/game/cas_manager/datums/cas_fire_envelope.dm +++ b/code/game/cas_manager/datums/cas_fire_envelope.dm @@ -26,6 +26,10 @@ ..() missions = list() +/datum/cas_fire_envelope/Destroy(force, ...) + linked_console = null + return ..() + /datum/cas_fire_envelope/proc/get_total_duration() return grace_period+flyto_period+flyoff_period @@ -124,7 +128,7 @@ if(target_turf && target_turf.signal_loc) var/turf/TT = get_turf(target_turf.signal_loc) if(TT && TT.z) - msg_admin_niche("[key_name(usr)] launching Fire Mission '[mission.name]' onto [target_turf.name] at ([TT.x],[TT.y],[TT.z]) (JMP LOC)") + msg_admin_niche("[key_name(usr)] launching Fire Mission '[mission.name]' onto [target_turf.name] at ([TT.x],[TT.y],[TT.z]) [ADMIN_JMP(TT)]") //actual firemission code execute_firemission_unsafe(target_turf, offset, dir, mission) return 1 @@ -349,6 +353,7 @@ return firemission_envelope.mission_error return "OK" +// Used in the simulation room for firemission testing. /obj/structure/machinery/computer/dropship_weapons/proc/execute_firemission(obj/location, offset, dir, mission_id) var/result = firemission_envelope.execute_firemission(get_turf(location), offset, dir, mission_id) if(result<1) diff --git a/code/game/cas_manager/datums/cas_fire_mission.dm b/code/game/cas_manager/datums/cas_fire_mission.dm index 9b4973293e66..42f5b4bd8655 100644 --- a/code/game/cas_manager/datums/cas_fire_mission.dm +++ b/code/game/cas_manager/datums/cas_fire_mission.dm @@ -96,7 +96,7 @@ /datum/cas_fire_mission/proc/execute_firemission(obj/structure/machinery/computer/dropship_weapons/linked_console, turf/initial_turf, direction = NORTH, steps = 12, step_delay = 3, datum/cas_fire_envelope/envelope = null) if(initial_turf == null || check(linked_console) != FIRE_MISSION_ALL_GOOD) - return -1 + return FIRE_MISSION_NOT_EXECUTABLE var/relative_dir for(var/mob/M in range(15, initial_turf)) @@ -128,8 +128,8 @@ ds_identifier = "DROPSHIP" M.show_message( \ - SPAN_HIGHDANGER("A [ds_identifier] FIRES TO YOUR [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), 1, \ - SPAN_HIGHDANGER("YOU HEAR SOMETHING FIRE TO YOUR [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), 2 \ + SPAN_HIGHDANGER("A [ds_identifier] FIRES [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), 1, \ + SPAN_HIGHDANGER("YOU HEAR SOMETHING FIRE [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), 2 \ ) var/turf/current_turf = initial_turf @@ -172,3 +172,61 @@ sleep(step_delay) if(envelope) envelope.change_current_loc(null) + + +/** + * Used only in the simulation room, proper tracking is done in the add_user_to_tracking envelop. + * This shouldn't be used in any other procs. + */ +/datum/cas_fire_mission/proc/add_user_to_sim_tracking(mob/living/user, obj/effect/firemission_guidance/guidance) + + var/mob/tracked_user = user + if(!tracked_user.client || !guidance) + return + + tracked_user.reset_view(guidance) + if(!(user in guidance.users)) + guidance.users += tracked_user + +// Used only in the simulator room for testing firemissions. Seemed better to just to copy here. +/datum/cas_fire_mission/proc/simulate_execute_firemission(obj/structure/machinery/computer/dropship_weapons/linked_console, turf/initial_turf, mob/living/user, direction = NORTH, steps = 12, step_delay = 3) + if(!initial_turf) + return FIRE_MISSION_NOT_EXECUTABLE + + var/obj/effect/firemission_guidance/guidance = new() + + guidance.forceMove(locate(initial_turf.x,initial_turf.y, initial_turf.z)) + + add_user_to_sim_tracking(user, guidance) + var/turf/current_turf = initial_turf + var/tally_step = steps / mission_length //how much shots we need before moving to next turf + var/next_step = tally_step //when we move to next turf + var/sx = 0 + var/sy = 0 //perpendicular multiplication + + switch(direction) + if(NORTH) //default direction + sx = 1 + sy = 0 + if(SOUTH) + sx = -1 + sy = 0 + if(EAST) + sx = 0 + sy = -1 + if(WEST) + sx = 0 + sy = 1 + for(var/step in 1 to steps) + if(step > next_step) + current_turf = get_step(current_turf,direction) + next_step += tally_step + var/datum/cas_fire_mission_record/item + for(item in records) + if(length(item.offsets) < step || item.offsets[step] == null || item.offsets[step] == "-") + continue + var/offset = item.offsets[step] + var/turf/shootloc = locate(current_turf.x + sx*offset, current_turf.y + sy*offset, current_turf.z) + item.weapon.open_simulated_fire_firemission(shootloc) + guidance.forceMove(locate(initial_turf.x,initial_turf.y + step, initial_turf.z)) + sleep(step_delay) diff --git a/code/game/cas_manager/datums/cas_signal.dm b/code/game/cas_manager/datums/cas_signal.dm index dd68ade3d20a..d45bcf142dc0 100644 --- a/code/game/cas_manager/datums/cas_signal.dm +++ b/code/game/cas_manager/datums/cas_signal.dm @@ -11,6 +11,7 @@ /datum/cas_signal/Destroy() QDEL_NULL(linked_cam) + signal_loc = null . = ..() /datum/cas_signal/proc/get_name() diff --git a/code/game/gamemodes/cm_initialize.dm b/code/game/gamemodes/cm_initialize.dm index 0f9dabf7ac68..becee89adb6d 100644 --- a/code/game/gamemodes/cm_initialize.dm +++ b/code/game/gamemodes/cm_initialize.dm @@ -46,7 +46,8 @@ Additional game mode variables. var/datum/mind/CO_survivor = null var/datum/mind/hellhounds[] = list() //Hellhound spawning is not supported at round start. var/list/dead_queens // A list of messages listing the dead queens - var/predators = list() + var/list/predators = list() + var/list/joes = list() var/xeno_required_num = 0 //We need at least one. You can turn this off in case we don't care if we spawn or don't spawn xenos. var/xeno_starting_num = 0 //To clamp starting xenos. @@ -67,7 +68,6 @@ Additional game mode variables. var/round_checkwin = 0 var/round_finished var/round_started = 5 //This is a simple timer so we don't accidently check win conditions right in post-game - var/list/round_fog = list() //List of the fog locations. var/list/round_toxic_river = list() //List of all toxic river locations var/round_time_lobby //Base time for the lobby, for fog dispersal. var/round_time_river @@ -100,7 +100,7 @@ Additional game mode variables. /datum/game_mode/proc/get_roles_list() - return ROLES_REGULAR_ALL + return ROLES_USCM //===================================================\\ @@ -214,6 +214,8 @@ Additional game mode variables. log_debug("Null client attempted to transform_predator") return + pred_candidate.client.prefs.find_assigned_slot(JOB_PREDATOR) // Probably does not do anything relevant, predator preferences are not tied to specific slot. + var/clan_id = CLAN_SHIP_PUBLIC var/datum/entity/clan_player/clan_info = pred_candidate?.client?.clan_info clan_info?.sync() @@ -331,28 +333,33 @@ Additional game mode variables. /datum/game_mode/proc/check_xeno_late_join(mob/xeno_candidate) if(jobban_isbanned(xeno_candidate, JOB_XENOMORPH)) // User is jobbanned to_chat(xeno_candidate, SPAN_WARNING("You are banned from playing aliens and cannot spawn as a xenomorph.")) - return - return 1 + return FALSE + return TRUE -/datum/game_mode/proc/attempt_to_join_as_xeno(mob/xeno_candidate, instant_join = 0) +/datum/game_mode/proc/attempt_to_join_as_xeno(mob/xeno_candidate, instant_join = FALSE) var/list/available_xenos = list() var/list/available_xenos_non_ssd = list() - for(var/mob/living/carbon/xenomorph/X in GLOB.living_xeno_list) - var/area/A = get_area(X) - if(is_admin_level(X.z) && (!A || !(A.flags_area & AREA_ALLOW_XENO_JOIN)) || X.aghosted) - continue //xenos on admin z level and aghosted ones don't count - if(istype(X) && ((!islarva(X) && (XENO_LEAVE_TIMER - X.away_timer < XENO_AVAILABLE_TIMER)) || (islarva(X) && (XENO_LEAVE_TIMER_LARVA - X.away_timer < XENO_AVAILABLE_TIMER)))) - if(!X.client) - available_xenos += X - else - available_xenos_non_ssd += X - + for(var/mob/living/carbon/xenomorph/cur_xeno as anything in GLOB.living_xeno_list) + if(cur_xeno.aghosted) + continue //aghosted xenos don't count + var/area/area = get_area(cur_xeno) + if(is_admin_level(cur_xeno.z) && (!area || !(area.flags_area & AREA_ALLOW_XENO_JOIN))) + continue //xenos on admin z level don't count + if(!istype(cur_xeno)) + continue + var/required_time = islarva(cur_xeno) ? XENO_LEAVE_TIMER_LARVA - cur_xeno.away_timer : XENO_LEAVE_TIMER - cur_xeno.away_timer + if(required_time > XENO_AVAILABLE_TIMER) + continue + if(!cur_xeno.client) + available_xenos += cur_xeno + else + available_xenos_non_ssd += cur_xeno var/datum/hive_status/hive for(var/hivenumber in GLOB.hive_datum) hive = GLOB.hive_datum[hivenumber] - if(!hive.hardcore && hive.stored_larva && (hive.hive_location || (world.time < 30 MINUTES + SSticker.round_start_time))) + if(!hive.hardcore && hive.stored_larva && (hive.hive_location || (world.time < XENO_BURIED_LARVA_TIME_LIMIT + SSticker.round_start_time))) if(SSticker.mode && (SSticker.mode.flags_round_type & MODE_RANDOM_HIVE)) available_xenos |= "any buried larva" LAZYADD(available_xenos["any buried larva"], hive) @@ -362,7 +369,34 @@ Additional game mode variables. available_xenos[larva_option] = list(hive) if(!available_xenos.len || (instant_join && !available_xenos_non_ssd.len)) - to_chat(xeno_candidate, SPAN_WARNING("There aren't any available xenomorphs or burrowed larvae. You can try getting spawned as a chestburster larva by toggling your Xenomorph candidacy in Preferences -> Toggle SpecialRole Candidacy.")) + if(!xeno_candidate.client || !xeno_candidate.client.prefs || !(xeno_candidate.client.prefs.be_special & BE_ALIEN_AFTER_DEATH)) + to_chat(xeno_candidate, SPAN_WARNING("There aren't any available xenomorphs or burrowed larvae. You can try getting spawned as a chestburster larva by toggling your Xenomorph candidacy in Preferences -> Toggle SpecialRole Candidacy.")) + return FALSE + to_chat(xeno_candidate, SPAN_WARNING("There aren't any available xenomorphs or burrowed larvae.")) + + // Give the player a cached message of their queue status if they are an observer + var/mob/dead/observer/candidate_observer = xeno_candidate + if(istype(candidate_observer)) + if(candidate_observer.larva_queue_cached_message) + to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) + return FALSE + + // No cache, lets check now then + message_alien_candidates(get_alien_candidates(), dequeued = 0, cache_only = TRUE) + if(candidate_observer.larva_queue_cached_message) + var/datum/hive_status/cur_hive + for(var/hive_num in GLOB.hive_datum) + cur_hive = GLOB.hive_datum[hive_num] + for(var/mob_name in cur_hive.banished_ckeys) + if(cur_hive.banished_ckeys[mob_name] == xeno_candidate.ckey) + candidate_observer.larva_queue_cached_message += "\n" + SPAN_WARNING("NOTE: You are banished from the [cur_hive] and you may not rejoin unless the Queen re-admits you or dies. Your queue number won't update until there is a hive you aren't banished from.") + break + to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) + return FALSE + + // We aren't in queue yet, lets teach them about the queue then + candidate_observer.larva_queue_cached_message = SPAN_XENONOTICE("You are currently awaiting assignment in the larva queue. The ordering is based on your time of death or the time you joined. When you have been dead long enough and are not inactive, you will periodically receive messages where you are in the queue relative to other currently valid xeno candidates. Your current position will shift as others change their preferences or go inactive, but your relative position compared to all observers is the same. Note: Playing as a facehugger or in the thunderdome will not alter your time of death. This means you won't lose your relative place in queue if you step away, disconnect, play as a facehugger, or play in the thunderdome.") + to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) return FALSE var/mob/living/carbon/xenomorph/new_xeno @@ -375,11 +409,11 @@ Additional game mode variables. if(!xeno_bypass_timer) var/deathtime = world.time - xeno_candidate.timeofdeath if(isnewplayer(xeno_candidate)) - deathtime = 2.5 MINUTES //so new players don't have to wait to latejoin as xeno in the round's first 5 mins. - if(deathtime < 2.5 MINUTES && !check_client_rights(xeno_candidate.client, R_ADMIN, FALSE)) + deathtime = XENO_JOIN_DEAD_LARVA_TIME //so new players don't have to wait to latejoin as xeno in the round's first 5 mins. + if(deathtime < XENO_JOIN_DEAD_LARVA_TIME && !check_client_rights(xeno_candidate.client, R_ADMIN, FALSE)) var/message = SPAN_WARNING("You have been dead for [DisplayTimeText(deathtime)].") to_chat(xeno_candidate, message) - to_chat(xeno_candidate, SPAN_WARNING("You must wait 2.5 minutes before rejoining the game as a buried larva!")) + to_chat(xeno_candidate, SPAN_WARNING("You must wait 2 minutes and 30 seconds before rejoining the game as a buried larva!")) return FALSE for(var/mob_name in picked_hive.banished_ckeys) @@ -391,7 +425,7 @@ Additional game mode variables. noob.close_spawn_windows() if(picked_hive.hive_location) picked_hive.hive_location.spawn_burrowed_larva(xeno_candidate) - else if((world.time < 30 MINUTES + SSticker.round_start_time)) + else if((world.time < XENO_BURIED_LARVA_TIME_LIMIT + SSticker.round_start_time)) picked_hive.do_buried_larva_spawn(xeno_candidate) else to_chat(xeno_candidate, SPAN_WARNING("Seems like something went wrong. Try again?")) @@ -415,8 +449,8 @@ Additional game mode variables. if(!xeno_bypass_timer) var/deathtime = world.time - xeno_candidate.timeofdeath if(istype(xeno_candidate, /mob/new_player)) - deathtime = 5 MINUTES //so new players don't have to wait to latejoin as xeno in the round's first 5 mins. - if(deathtime < 5 MINUTES && !check_client_rights(xeno_candidate.client, R_ADMIN, FALSE)) + deathtime = XENO_JOIN_DEAD_TIME //so new players don't have to wait to latejoin as xeno in the round's first 5 mins. + if(deathtime < XENO_JOIN_DEAD_TIME && !check_client_rights(xeno_candidate.client, R_ADMIN, FALSE)) var/message = "You have been dead for [DisplayTimeText(deathtime)]." message = SPAN_WARNING("[message]") to_chat(xeno_candidate, message) @@ -514,6 +548,43 @@ Additional game mode variables. return TRUE +/datum/game_mode/proc/attempt_to_join_as_lesser_drone(mob/xeno_candidate) + var/list/active_hives = list() + var/datum/hive_status/hive + var/last_active_hive = 0 + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(hive.totalXenos.len <= 0) + continue + active_hives[hive.name] = hive.hivenumber + last_active_hive = hive.hivenumber + + if(active_hives.len <= 0) + to_chat(xeno_candidate, SPAN_WARNING("There aren't any Hives active at this point for you to join.")) + return FALSE + + if(active_hives.len > 1) + var/hive_picked = tgui_input_list(xeno_candidate, "Select which Hive to attempt joining.", "Hive Choice", active_hives, theme="hive_status") + if(!hive_picked) + to_chat(xeno_candidate, SPAN_ALERT("Hive choice error. Aborting.")) + return + hive = GLOB.hive_datum[active_hives[hive_picked]] + else + hive = GLOB.hive_datum[last_active_hive] + + if(!hive.hive_location) + to_chat(xeno_candidate, SPAN_WARNING("The selected hive does not have a hive core to spawn from!")) + return + + for(var/mob_name in hive.banished_ckeys) + if(hive.banished_ckeys[mob_name] == xeno_candidate.ckey) + to_chat(xeno_candidate, SPAN_WARNING("You are banished from the [hive], you may not rejoin unless the Queen re-admits you or dies.")) + return + + hive.hive_location.spawn_lesser_drone(xeno_candidate) + + return TRUE + /datum/game_mode/proc/transfer_xeno(xeno_candidate, mob/living/new_xeno) if(!xeno_candidate || !isxeno(new_xeno) || QDELETED(new_xeno)) return FALSE @@ -653,8 +724,8 @@ Additional game mode variables. //creates soft caps for survivor variants, if there are more than the maximum of your preference you get a completely random variant which can include your preference, should minimize stacking while allowing for interesting randomness var/preferred_variant = ANY_SURVIVOR - if(equipping_human.client?.prefs?.preferred_survivor_variant != ANY_SURVIVOR) - preferred_variant = equipping_human.client?.prefs?.preferred_survivor_variant + if(equipping_human.client?.prefs?.pref_special_job_options[JOB_SURVIVOR] != ANY_SURVIVOR) + preferred_variant = equipping_human.client?.prefs?.pref_special_job_options[JOB_SURVIVOR] if(MAX_SURVIVOR_PER_TYPE[preferred_variant] != -1 && survivors_by_type_amounts[preferred_variant] && survivors_by_type_amounts[preferred_variant] >= MAX_SURVIVOR_PER_TYPE[preferred_variant]) preferred_variant = ANY_SURVIVOR @@ -830,3 +901,85 @@ Additional game mode variables. /datum/game_mode/proc/get_escape_menu() return "On the [SSmapping.configs[SHIP_MAP].map_name], orbiting..." + + +//===================================================\\ + + //JOE INITIALIZE\\ + +//===================================================\\ + +/datum/game_mode/proc/initialize_joe(mob/living/carbon/human/joe) + joes += joe.ckey + +/datum/game_mode/proc/attempt_to_join_as_joe(mob/joe_candidate) + var/mob/living/carbon/human/new_joe = transform_joe(joe_candidate) //Initialized and ready. + if(!new_joe) + return + + msg_admin_niche("Ghost ([new_joe.key]) has joined as Working Joe, [new_joe.real_name].") + + if(joe_candidate) + joe_candidate.moveToNullspace() //Nullspace it for garbage collection later. + +/datum/game_mode/proc/check_joe_late_join(mob/joe_candidate, show_warning = 1) + + if(!joe_candidate.client) + return + + var/datum/job/joe_job = RoleAuthority.roles_by_name[JOB_WORKING_JOE] + + if(!joe_job) + if(show_warning) + to_chat(joe_candidate, SPAN_WARNING("Something went wrong!")) + return + + if(!(RoleAuthority.roles_whitelist[joe_candidate.ckey] & WHITELIST_JOE)) + if(show_warning) + to_chat(joe_candidate, SPAN_WARNING("You are not whitelisted! You may apply on the forums to be whitelisted as a synth.")) + return + + if(joe_candidate.ckey in joes) + if(show_warning) + to_chat(joe_candidate, SPAN_WARNING("You already were a Working Joe this round!")) + return + + // council doesn't count towards this conditional. + if(joe_job.get_whitelist_status(RoleAuthority.roles_whitelist, joe_candidate.client) == WHITELIST_NORMAL) + var/joe_max = joe_job.total_positions + if(joe_job.current_positions >= joe_max) + if(show_warning) + to_chat(joe_candidate, SPAN_WARNING("Only [joe_max] Working Joes may spawn per round.")) + return + + if(!enter_allowed) + if(show_warning) + to_chat(joe_candidate, SPAN_WARNING("There is an administrative lock from entering the game.")) + return + + if(show_warning && tgui_alert(joe_candidate, "Confirm joining as a Working Joe.", "Confirmation", list("Yes", "No"), 10 SECONDS) != "Yes") + return + + return TRUE + +/datum/game_mode/proc/transform_joe(mob/joe_candidate) + set waitfor = FALSE + + if(!joe_candidate.client) // Legacy - probably due to spawn code sync sleeps + log_debug("Null client attempted to transform_joe") + return + + var/turf/spawn_point = get_turf(pick(GLOB.latejoin_by_job[JOB_WORKING_JOE])) + var/mob/living/carbon/human/synthetic/new_joe = new(spawn_point) + joe_candidate.mind.transfer_to(new_joe, TRUE) + var/datum/job/joe_job = RoleAuthority.roles_by_name[JOB_WORKING_JOE] + + if(!joe_job) + qdel(new_joe) + return + // This is usually done in assign_role, a proc which is not executed in this case, since check_joe_late_join is running its own checks. + joe_job.current_positions++ + RoleAuthority.equip_role(new_joe, joe_job, new_joe.loc) + GLOB.data_core.manifest_inject(new_joe) + SSticker.minds += new_joe.mind + return new_joe diff --git a/code/game/gamemodes/cm_process.dm b/code/game/gamemodes/cm_process.dm index 476d10a003fd..33377f7dc6fd 100644 --- a/code/game/gamemodes/cm_process.dm +++ b/code/game/gamemodes/cm_process.dm @@ -58,18 +58,18 @@ of predators), but can be added to include variant game modes (like humans vs. h if(LAZYLEN(xenomorphs) || LAZYLEN(dead_queens)) var/dat = "
" dat += SPAN_ROUNDBODY("
The xenomorph Queen(s) were:") - var/mob/M + var/mob/living/carbon/xenomorph/xeno_mob for (var/msg in dead_queens) dat += msg - for(var/datum/mind/X in xenomorphs) - if(!istype(X)) + for(var/datum/mind/xeno_mind in xenomorphs) + if(!istype(xeno_mind)) continue - M = X.current - if(!M || !M.loc) - M = X.original - if(M && M.loc && isqueen(M) && M.stat != DEAD) // Dead queens handled separately - dat += "
[X.key] was [M] [SPAN_BOLDNOTICE("(SURVIVED)")]" + xeno_mob = xeno_mind.current + if(!xeno_mob || !xeno_mob.loc) + xeno_mob = xeno_mind.original + if(xeno_mob && xeno_mob.loc && isqueen(xeno_mob) && xeno_mob.stat != DEAD) // Dead queens handled separately + dat += "
[xeno_mob.full_designation] was [xeno_mob] [SPAN_BOLDNOTICE("(SURVIVED)")]" to_world("[dat]") @@ -131,17 +131,6 @@ of predators), but can be added to include variant game modes (like humans vs. h SPAN_XENODANGER("You burrow out of the ground and awaken from your slumber. For the Hive!")) new_xeno << sound('sound/effects/xeno_newlarva.ogg') -//Disperses fog, doing so gradually. -/datum/game_mode/proc/disperse_fog() - set waitfor = 0 - flags_round_type &= ~MODE_FOG_ACTIVATED - var/i - for(i in round_fog) - round_fog -= i - qdel(i) - CHECK_TICK - round_fog = null - // Open podlocks with the given ID if they aren't already opened. // DO NOT USE THIS WITH ID's CORRESPONDING TO SHUTTLES OR THEY WILL BREAK! /datum/game_mode/proc/open_podlocks(podlock_id) @@ -255,6 +244,34 @@ GLOBAL_VAR_INIT(next_admin_bioscan, 30 MINUTES) return num_marines +/datum/game_mode/proc/count_per_faction(list/z_levels = SSmapping.levels_by_any_trait(list(ZTRAIT_GROUND, ZTRAIT_RESERVED, ZTRAIT_MARINE_MAIN_SHIP))) + var/num_marines = 0 + var/num_WY = 0 + var/num_UPP = 0 + var/num_CLF = 0 + var/num_headcount = 0 + + for(var/mob/living/carbon/human/current_human as anything in GLOB.alive_human_list) + if(!(current_human.z && (current_human.z in z_levels) && !istype(current_human.loc, /turf/open/space))) + continue + if(current_human.faction in FACTION_LIST_WY || current_human.job == "Corporate Liaison") //The CL is assigned the USCM faction for gameplay purposes + num_WY++ + num_headcount++ + continue + if(current_human.faction == FACTION_UPP) + num_UPP++ + num_headcount++ + continue + if(current_human.faction == FACTION_CLF) + num_CLF++ + num_headcount++ + continue + if(current_human.faction == FACTION_MARINE) + num_marines++ + num_headcount++ + continue + num_headcount++ + return list("marine_headcount" = num_marines,"WY_headcount" = num_WY,"UPP_headcount" = num_UPP,"CLF_headcount" = num_CLF,"total_headcount" = num_headcount) /* #undef QUEEN_DEATH_COUNTDOWN diff --git a/code/game/gamemodes/cm_self_destruct.dm b/code/game/gamemodes/cm_self_destruct.dm index 8defdb3429b6..8c022fd0d916 100644 --- a/code/game/gamemodes/cm_self_destruct.dm +++ b/code/game/gamemodes/cm_self_destruct.dm @@ -256,17 +256,18 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi ship_status = 0 //Destroyed. break - var/L1[] = new //Everyone who will be destroyed on the zlevel(s). - var/L2[] = new //Everyone who only needs to see the cinematic. - var/mob/M - var/turf/T - for(M in GLOB.player_list) //This only does something cool for the people about to die, but should prove pretty interesting. - if(!M || !M.loc) continue //In case something changes when we sleep(). - if(M.stat == DEAD) - L2 |= M - else if(M.z in z_levels) - L1 |= M - shake_camera(M, 110, 4) + var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s). + var/list/dead_mobs = list() //Everyone who only needs to see the cinematic. + for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting. + if(!current_mob || !current_mob.loc) + continue //In case something changes when we sleep(). + if(current_mob.stat == DEAD) + dead_mobs |= current_mob + continue + var/turf/current_turf = get_turf(current_mob) + if(current_turf.z in z_levels) + alive_mobs |= current_mob + shake_camera(current_mob, 110, 4) sleep(100) @@ -275,23 +276,23 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi var/atom/movable/screen/cinematic/explosion/C = new if(play_anim) - for(M in L1 + L2) - if(M && M.loc && M.client) - M.client.screen |= C //They may have disconnected in the mean time. + for(var/mob/current_mob as anything in alive_mobs + dead_mobs) + if(current_mob && current_mob.loc && current_mob.client) + current_mob.client.screen |= C //They may have disconnected in the mean time. sleep(15) //Extra 1.5 seconds to look at the ship. flick(override ? "intro_override" : "intro_nuke", C) sleep(35) - for(M in L1) - if(M && M.loc) //Who knows, maybe they escaped, or don't exist anymore. - T = get_turf(M) - if(T.z in z_levels) - if(istype(M.loc, /obj/structure/closet/secure_closet/freezer/fridge)) + for(var/mob/current_mob in alive_mobs) + if(current_mob && current_mob.loc) //Who knows, maybe they escaped, or don't exist anymore. + var/turf/current_mob_turf = get_turf(current_mob) + if(current_mob_turf.z in z_levels) + if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge)) continue - M.death(create_cause_data("nuclear explosion")) + current_mob.death(create_cause_data("nuclear explosion")) else if(play_anim) - M.client.screen -= C //those who managed to escape the z level at last second shouldn't have their view obstructed. + current_mob.client.screen -= C //those who managed to escape the z level at last second shouldn't have their view obstructed. if(play_anim) flick(ship_status ? "ship_spared" : "ship_destroyed", C) C.icon_state = ship_status ? "summary_spared" : "summary_destroyed" @@ -326,6 +327,8 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi //Generic parent base for the self_destruct items. /obj/structure/machinery/self_destruct icon = 'icons/obj/structures/machinery/self_destruct.dmi' + icon_state = "console_1" + var/base_icon_state = "console" use_power = USE_POWER_NONE //Runs unpowered, may need to change later. density = FALSE anchored = TRUE //So it doesn't go anywhere. @@ -337,7 +340,7 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi /obj/structure/machinery/self_destruct/Initialize(mapload, ...) . = ..() - icon_state += "_1" + icon_state = "[base_icon_state]_1" /obj/structure/machinery/self_destruct/Destroy() . = ..() @@ -356,17 +359,18 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi /obj/structure/machinery/self_destruct/proc/lock_or_unlock(lock) set waitfor = 0 in_progress = 1 - flick(initial(icon_state) + (lock? "_5" : "_2"),src) + flick("[base_icon_state]" + (lock? "_5" : "_2"),src) sleep(9) mouse_opacity = !mouse_opacity - icon_state = initial(icon_state) + (lock? "_1" : "_3") + icon_state = "[base_icon_state]" + (lock? "_1" : "_3") in_progress = 0 active_state = active_state > SELF_DESTRUCT_MACHINE_INACTIVE ? SELF_DESTRUCT_MACHINE_INACTIVE : SELF_DESTRUCT_MACHINE_ACTIVE /obj/structure/machinery/self_destruct/console name = "self-destruct control panel" - icon_state = "console" - req_one_access = list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_SENIOR) + icon_state = "console_1" + base_icon_state = "console" + req_one_access = list(ACCESS_MARINE_CO, ACCESS_MARINE_SENIOR) /obj/structure/machinery/self_destruct/console/Destroy() . = ..() @@ -435,7 +439,8 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi /obj/structure/machinery/self_destruct/rod name = "self-destruct control rod" desc = "It is part of a complicated self-destruct sequence, but relatively simple to operate. Twist to arm or disarm." - icon_state = "rod" + icon_state = "rod_1" + base_icon_state = "rod" layer = BELOW_OBJ_LAYER var/activate_time diff --git a/code/game/gamemodes/colonialmarines/colonialmarines.dm b/code/game/gamemodes/colonialmarines/colonialmarines.dm index c6a8a02a9ba2..cf2b7819a596 100644 --- a/code/game/gamemodes/colonialmarines/colonialmarines.dm +++ b/code/game/gamemodes/colonialmarines/colonialmarines.dm @@ -1,4 +1,5 @@ #define HIJACK_EXPLOSION_COUNT 5 +#define MARINE_MAJOR_ROUND_END_DELAY 3 MINUTES /datum/game_mode/colonialmarines name = "Distress Signal" @@ -27,26 +28,38 @@ /datum/game_mode/colonialmarines/announce() to_chat_spaced(world, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDHEADER("The current map is - [SSmapping.configs[GROUND_MAP].map_name]!")) +/datum/game_mode/colonialmarines/get_roles_list() + return ROLES_DISTRESS_SIGNAL + //////////////////////////////////////////////////////////////////////////////////////// //Temporary, until we sort this out properly. /obj/effect/landmark/lv624 - icon = 'icons/old_stuff/mark.dmi' + icon = 'icons/landmarks.dmi' /obj/effect/landmark/lv624/fog_blocker name = "fog blocker" - icon_state = "spawn_event" + icon_state = "fog" + + var/time_to_dispel = 25 MINUTES + +/obj/effect/landmark/lv624/fog_blocker/short + time_to_dispel = 15 MINUTES /obj/effect/landmark/lv624/fog_blocker/Initialize(mapload, ...) . = ..() - GLOB.fog_blockers += src -/obj/effect/landmark/lv624/fog_blocker/Destroy() - GLOB.fog_blockers -= src - return ..() + return INITIALIZE_HINT_ROUNDSTART + +/obj/effect/landmark/lv624/fog_blocker/LateInitialize() + if(!(SSticker.mode.flags_round_type & MODE_FOG_ACTIVATED) || !SSmapping.configs[GROUND_MAP].environment_traits[ZTRAIT_FOG]) + return + + new /obj/structure/blocker/fog(loc, time_to_dispel) + qdel(src) /obj/effect/landmark/lv624/xeno_tunnel name = "xeno tunnel" - icon_state = "spawn_event" + icon_state = "xeno_tunnel" /obj/effect/landmark/lv624/xeno_tunnel/Initialize(mapload, ...) . = ..() @@ -60,11 +73,6 @@ /* Pre-setup */ /datum/game_mode/colonialmarines/pre_setup() - for(var/i in GLOB.fog_blockers) - var/obj/effect/landmark/lv624/fog_blocker/FB = i - round_fog += new /obj/structure/blocker/fog(FB.loc) - qdel(FB) - QDEL_LIST(GLOB.hunter_primaries) QDEL_LIST(GLOB.hunter_secondaries) QDEL_LIST(GLOB.crap_items) @@ -78,11 +86,6 @@ qdel(i) new type_to_spawn(T) - if(!round_fog.len) - round_fog = null //No blockers? - else - flags_round_type |= MODE_FOG_ACTIVATED - //desert river test if(!round_toxic_river.len) round_toxic_river = null //No tiles? @@ -115,8 +118,6 @@ if(SSmapping.configs[GROUND_MAP].environment_traits[ZTRAIT_BASIC_RT]) flags_round_type |= MODE_BASIC_RT - round_time_lobby = world.time - addtimer(CALLBACK(src, PROC_REF(ares_online)), 5 SECONDS) addtimer(CALLBACK(src, PROC_REF(map_announcement)), 20 SECONDS) @@ -140,20 +141,19 @@ var/monkey_to_spawn = pick(monkey_types) new monkey_to_spawn(T) -/datum/game_mode/colonialmarines/proc/ares_online() - var/name = "ARES Online" - var/input = "ARES. Online. Good morning, marines." - shipwide_ai_announcement(input, name, 'sound/AI/ares_online.ogg') - /datum/game_mode/colonialmarines/proc/map_announcement() if(SSmapping.configs[GROUND_MAP].announce_text) var/rendered_announce_text = replacetext(SSmapping.configs[GROUND_MAP].announce_text, "###SHIPNAME###", MAIN_SHIP_NAME) marine_announcement(rendered_announce_text, "[MAIN_SHIP_NAME]") +/datum/game_mode/colonialmarines/proc/ares_conclude() + ai_silent_announcement("Bioscan complete. No unknown lifeform signature detected.", ".V") + ai_silent_announcement("Saving operational report to archive.", ".V") + ai_silent_announcement("Commencing final systems scan in 3 minutes.", ".V") + //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// -#define FOG_DELAY_INTERVAL (25 MINUTES) #define PODLOCKS_OPEN_WAIT (45 MINUTES) // CORSAT pod doors drop at 12:45 //This is processed each tick, but check_win is only checked 5 ticks, so we don't go crazy with scanning for mobs. @@ -164,6 +164,7 @@ if(is_in_endgame) check_hijack_explosions() + check_ground_humans() if(next_research_allocation < world.time) chemical_data.update_credits(chemical_data.research_allocation_amount) @@ -188,8 +189,6 @@ bioscan_current_interval += bioscan_ongoing_interval //Add to the interval based on our set interval time. if(++round_checkwin >= 5) //Only check win conditions every 5 ticks. - if(flags_round_type & MODE_FOG_ACTIVATED && SSmapping.configs[GROUND_MAP].environment_traits[ZTRAIT_FOG] && world.time >= (FOG_DELAY_INTERVAL + SSticker.round_start_time)) - disperse_fog() //Some RNG thrown in. if(!(round_status_flags & ROUNDSTATUS_PODDOORS_OPEN)) if(SSmapping.configs[GROUND_MAP].environment_traits[ZTRAIT_LOCKDOWN]) if(world.time >= (PODLOCKS_OPEN_WAIT + round_time_lobby)) @@ -243,6 +242,35 @@ addtimer(CALLBACK(src, PROC_REF(shake_ship)), 5 SECONDS) TIMER_COOLDOWN_START(src, COOLDOWN_HIJACK_BARRAGE, 15 SECONDS) +#define GROUNDSIDE_XENO_MULTIPLIER 1.0 + +///Checks for humans groundside after hijack, spawns forsaken if requirements met +/datum/game_mode/colonialmarines/proc/check_ground_humans() + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_HIJACK_GROUND_CHECK)) + return + + var/groundside_humans = 0 + var/groundside_xenos = 0 + + for(var/mob/current_mob in GLOB.player_list) + if(!is_ground_level(current_mob.z) || !current_mob.client || current_mob.stat == DEAD) + continue + + if(ishuman_strict(current_mob)) + groundside_humans++ + continue + + if(isxeno(current_mob)) + groundside_xenos++ + continue + + if(groundside_humans > (groundside_xenos * GROUNDSIDE_XENO_MULTIPLIER)) + SSticker.mode.get_specific_call("Xenomorphs Groundside (Forsaken)", FALSE, FALSE, announce_dispatch_message = FALSE) + + TIMER_COOLDOWN_START(src, COOLDOWN_HIJACK_GROUND_CHECK, 1 MINUTES) + +#undef GROUNDSIDE_XENO_MULTIPLIER + /** * Makes the mainship shake, along with playing a klaxon sound effect. */ @@ -254,7 +282,6 @@ playsound_z(SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP)), 'sound/effects/double_klaxon.ogg', volume = 10) -#undef FOG_DELAY_INTERVAL #undef PODLOCKS_OPEN_WAIT // Resource Towers @@ -287,7 +314,10 @@ if(SSticker.mode && SSticker.mode.is_in_endgame) round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place. else + SSticker.roundend_check_paused = TRUE round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs. + ares_conclude() + addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY) else if(!num_humans && !num_xenos) round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed. @@ -317,6 +347,8 @@ ////////////////////////////////////////////////////////////////////// //Announces the end of the game with all relevant information stated// ////////////////////////////////////////////////////////////////////// +#define MAJORITY 0.5 // What percent do we consider a 'majority?' + /datum/game_mode/colonialmarines/declare_completion() announce_ending() var/musical_track @@ -335,7 +367,20 @@ round_statistics.current_map.total_marine_victories++ round_statistics.current_map.total_marine_majors++ if(MODE_INFESTATION_X_MINOR) - musical_track = pick('sound/theme/neutral_melancholy1.ogg','sound/theme/neutral_melancholy2.ogg') + var/list/living_player_list = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels()) + if(living_player_list[1] && !living_player_list[2]) // If Xeno Minor but Xenos are dead and Humans are alive, see which faction is the last standing + var/headcount = count_per_faction() + var/living = headcount["total_headcount"] + if ((headcount["WY_headcount"] / living) > MAJORITY) + musical_track = pick('sound/theme/lastmanstanding_wy.ogg') + else if ((headcount["UPP_headcount"] / living) > MAJORITY) + musical_track = pick('sound/theme/lastmanstanding_upp.ogg') + else if ((headcount["CLF_headcount"] / living) > MAJORITY) + musical_track = pick('sound/theme/lastmanstanding_clf.ogg') + else if ((headcount["marine_headcount"] / living) > MAJORITY) + musical_track = pick('sound/theme/neutral_melancholy2.ogg') //This is the theme song for Colonial Marines the game, fitting + else + musical_track = pick('sound/theme/neutral_melancholy1.ogg') end_icon = "xeno_minor" if(round_statistics && round_statistics.current_map) round_statistics.current_map.total_xeno_victories++ @@ -346,7 +391,7 @@ round_statistics.current_map.total_marine_victories++ if(MODE_INFESTATION_DRAW_DEATH) end_icon = "draw" - musical_track = pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg') + musical_track = 'sound/theme/neutral_hopeful2.ogg' if(round_statistics && round_statistics.current_map) round_statistics.current_map.total_draws++ var/sound/S = sound(musical_track, channel = SOUND_CHANNEL_LOBBY) @@ -369,6 +414,7 @@ declare_completion_announce_medal_awards() declare_fun_facts() + add_current_round_status_to_end_results("Round End") handle_round_results_statistics_output() @@ -400,7 +446,7 @@ //organize our jobs in a readable and standard way for(var/job in ROLES_MARINES) counted_humans["Squad Marines"][job] = 0 - for(var/job in ROLES_REGULAR_ALL - ROLES_XENO - ROLES_MARINES - ROLES_WHITELISTED - ROLES_SPECIAL) + for(var/job in ROLES_USCM - ROLES_MARINES) counted_humans["Auxiliary Marines"][job] = 0 for(var/job in ROLES_SPECIAL) counted_humans["Non-Standard Humans"][job] = 0 @@ -542,3 +588,5 @@ incrementer++ #undef HIJACK_EXPLOSION_COUNT +#undef MARINE_MAJOR_ROUND_END_DELAY +#undef MAJORITY diff --git a/code/game/gamemodes/colonialmarines/huntergames.dm b/code/game/gamemodes/colonialmarines/huntergames.dm index 23cf4b32d3c5..c8c90fa51c0c 100644 --- a/code/game/gamemodes/colonialmarines/huntergames.dm +++ b/code/game/gamemodes/colonialmarines/huntergames.dm @@ -167,7 +167,6 @@ var/waiting_for_drop_votes = 0 for(var/i in GLOB.good_items) place_drop(get_turf(i), "good") - QDEL_LIST(GLOB.fog_blockers) QDEL_LIST(GLOB.xeno_tunnels) for(var/G in GLOB.gun_list) @@ -423,6 +422,7 @@ var/waiting_for_drop_votes = 0 round_statistics.log_round_statistics() + return 1 /datum/game_mode/proc/auto_declare_completion_huntergames() diff --git a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm index b45514c3423d..e172939c847f 100644 --- a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm +++ b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm @@ -87,6 +87,7 @@ return 1 /datum/game_mode/whiskey_outpost/pre_setup() + SSticker.mode.toggleable_flags ^= MODE_HARDCORE_PERMA for(var/obj/effect/landmark/whiskey_outpost/xenospawn/X) xeno_spawns += X.loc for(var/obj/effect/landmark/whiskey_outpost/supplydrops/S) @@ -303,6 +304,7 @@ calculate_end_statistics() + return 1 /datum/game_mode/proc/auto_declare_completion_whiskey_outpost() @@ -662,8 +664,8 @@ /obj/item/ammo_magazine/rocket/wp) if(2) //Smartgun supplies spawnitems = list( - /obj/item/cell/high, - /obj/item/cell/high, + /obj/item/smartgun_battery, + /obj/item/smartgun_battery, /obj/item/ammo_magazine/smartgun, /obj/item/ammo_magazine/smartgun, /obj/item/ammo_magazine/smartgun, diff --git a/code/game/gamemodes/colonialmarines/whiskey_outpost/equipping.dm b/code/game/gamemodes/colonialmarines/whiskey_outpost/equipping.dm index 2822cafe9cd6..eb3e46a2686b 100644 --- a/code/game/gamemodes/colonialmarines/whiskey_outpost/equipping.dm +++ b/code/game/gamemodes/colonialmarines/whiskey_outpost/equipping.dm @@ -152,6 +152,10 @@ Treat the wounded, guide triage, and survive for as long as possible."} /datum/job/civilian/doctor/whiskey title = JOB_WO_DOCTOR gear_preset = /datum/equipment_preset/wo/doctor + job_options = null //Does not inherit regular doctor's variants, uses unique preset instead. + +/datum/job/civilian/doctor/whiskey/handle_job_options() + return /datum/job/civilian/doctor/whiskey/generate_entry_message(mob/living/carbon/human/H) . = {"You volunteered to assist ground-side with medical duties. That may have been a mistake. diff --git a/code/game/gamemodes/colonialmarines/xenovsxeno.dm b/code/game/gamemodes/colonialmarines/xenovsxeno.dm index 7001d8048775..a0d555acd2fb 100644 --- a/code/game/gamemodes/colonialmarines/xenovsxeno.dm +++ b/code/game/gamemodes/colonialmarines/xenovsxeno.dm @@ -37,6 +37,9 @@ /datum/game_mode/xenovs/announce() to_chat_spaced(world, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDHEADER("The current map is - [SSmapping.configs[GROUND_MAP].map_name]!")) +/datum/game_mode/xenovs/get_roles_list() + return ROLES_XENO + /* Pre-setup */ /datum/game_mode/xenovs/pre_setup() monkey_types = SSmapping.configs[GROUND_MAP].monkey_types @@ -258,7 +261,7 @@ /datum/game_mode/xenovs/declare_completion() announce_ending() var/musical_track - musical_track = pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg') + musical_track = pick('sound/theme/neutral_melancholy1.ogg', 'sound/theme/neutral_melancholy2.ogg') var/sound/S = sound(musical_track, channel = SOUND_CHANNEL_LOBBY) S.status = SOUND_STREAM @@ -274,6 +277,7 @@ calculate_end_statistics() declare_fun_facts() + return TRUE /datum/game_mode/xenovs/announce_ending() diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm index cd55ebc5675a..f00125cc8f0f 100644 --- a/code/game/gamemodes/extended/extended.dm +++ b/code/game/gamemodes/extended/extended.dm @@ -1,6 +1,6 @@ /datum/game_mode/extended - name = "extended" - config_tag = "extended" + name = "Extended" + config_tag = "Extended" required_players = 0 latejoin_larva_drop = 0 votable = FALSE @@ -11,10 +11,8 @@ /datum/game_mode/announce() to_world("The current game mode is - Extended!") -/datum/game_mode/extended/pre_setup() - roles_to_roll = RoleAuthority.roles_for_mode - (RoleAuthority.roles_for_mode & (ROLES_XENO|ROLES_WHITELISTED|ROLES_SPECIAL)) - - return ..() +/datum/game_mode/extended/get_roles_list() + return ROLES_USCM /datum/game_mode/extended/post_setup() initialize_post_marine_gear_list() @@ -50,4 +48,6 @@ calculate_end_statistics() declare_completion_announce_predators() declare_completion_announce_medal_awards() + + return TRUE diff --git a/code/game/gamemodes/extended/extended_nospawn.dm b/code/game/gamemodes/extended/extended_nospawn.dm index 2f75e076f6d4..6835671ace85 100644 --- a/code/game/gamemodes/extended/extended_nospawn.dm +++ b/code/game/gamemodes/extended/extended_nospawn.dm @@ -1,6 +1,6 @@ /datum/game_mode/extended/nospawn - name = "extended no spawn" - config_tag = "extended - no spawn" + name = "Extended - No Spawn" + config_tag = "Extended - No Spawn" flags_round_type = MODE_NO_LATEJOIN|MODE_NO_SPAWN votable = FALSE diff --git a/code/game/gamemodes/extended/infection.dm b/code/game/gamemodes/extended/infection.dm index 8c30bd943173..04e0545361aa 100644 --- a/code/game/gamemodes/extended/infection.dm +++ b/code/game/gamemodes/extended/infection.dm @@ -14,6 +14,9 @@ to_world("If you die as a zombie, you come back. NO MATTER HOW MUCH DAMAGE.") to_world("Don't ahelp asking for specific details, you won't get them.") +/datum/game_mode/infection/get_roles_list() + return ROLES_USCM + /datum/game_mode/infection/pre_setup() return ..() @@ -22,17 +25,25 @@ initialize_post_marine_gear_list() for(var/mob/new_player/np in GLOB.new_player_list) np.new_player_panel_proc() - spawn(50) - marine_announcement("We've lost contact with the Weyland-Yutani's research facility, [name]. The [MAIN_SHIP_NAME] has been dispatched to assist.", "[MAIN_SHIP_NAME]") + + addtimer(CALLBACK(src, PROC_REF(ares_online)), 5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(map_announcement)), 20 SECONDS) return ..() +/datum/game_mode/infection/proc/map_announcement() + if(SSmapping.configs[GROUND_MAP].infection_announce_text) + var/rendered_announce_text = replacetext(SSmapping.configs[GROUND_MAP].infection_announce_text, "###SHIPNAME###", MAIN_SHIP_NAME) + marine_announcement(rendered_announce_text, "[MAIN_SHIP_NAME]") + else if(SSmapping.configs[GROUND_MAP].announce_text) //if we missed a infection text for above, or just don't need a special one, we just use default announcement + var/rendered_announce_text = replacetext(SSmapping.configs[GROUND_MAP].announce_text, "###SHIPNAME###", MAIN_SHIP_NAME) + marine_announcement(rendered_announce_text, "[MAIN_SHIP_NAME]") + /datum/game_mode/infection/proc/initialize_post_survivor_list() if(synth_survivor) transform_survivor(synth_survivor, TRUE) for(var/datum/mind/survivor in survivors) if(transform_survivor(survivor) == 1) survivors -= survivor - tell_survivor_story() /datum/game_mode/infection/can_start() initialize_starting_survivor_list() @@ -118,4 +129,6 @@ declare_completion_announce_xenomorphs() declare_completion_announce_predators() declare_completion_announce_medal_awards() + + return 1 diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 7b9e583c2a2e..5b007d275c32 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -82,7 +82,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki return ///Triggered when the dropship first lands. -/datum/game_mode/proc/ds_first_landed(obj/docking_port/mobile/marine_dropship) +/datum/game_mode/proc/ds_first_landed(obj/docking_port/stationary/marine_dropship) SHOULD_CALL_PARENT(TRUE) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_DS_FIRST_LANDED) return @@ -103,17 +103,18 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki for(var/mob/new_player/np in GLOB.new_player_list) np.new_player_panel_proc() + round_time_lobby = world.time log_game("Round started at [time2text(world.realtime)]") if(SSticker.mode) log_game("Game mode set to [SSticker.mode]") log_game("Server IP: [world.internet_address]:[world.port]") - return 1 + return TRUE ///process() ///Called by the gameticker /datum/game_mode/process() - return 0 + return FALSE /datum/game_mode/proc/check_finished() //to be called by ticker @@ -159,6 +160,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki if(surviving_total > 0) log_game("Round end - total: [surviving_total]") + return 0 /datum/game_mode/proc/calculate_end_statistics() @@ -247,6 +249,15 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki var/mob/living/carbon/human/M = new /mob/living/carbon/human(spawnpoint) M.create_hud() //Need to generate hud before we can equip anything apparently... arm_equipment(M, spawner.equip_path, TRUE, FALSE) + for(var/obj/structure/bed/nest/found_nest in spawnpoint) + for(var/turf/the_turf in list(get_step(found_nest, NORTH),get_step(found_nest, EAST),get_step(found_nest, WEST))) + if(the_turf.density) + found_nest.dir = get_dir(found_nest, the_turf) + found_nest.pixel_x = found_nest.buckling_x["[found_nest.dir]"] + found_nest.pixel_y = found_nest.buckling_y["[found_nest.dir]"] + M.dir = get_dir(the_turf,found_nest) + if(!found_nest.buckled_mob) + found_nest.do_buckle(M,M) gamemode_spawn_corpse.Remove(spawner) /datum/game_mode/proc/spawn_static_comms() diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index e39ad487f60e..0d10b06d5fef 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -2,17 +2,28 @@ //returns FALSE otherwise /obj/proc/allowed(mob/M) //check if it doesn't require any access at all - if(check_access()) return TRUE - if(isRemoteControlling(M)) return TRUE //AI can do whatever he wants + if(check_access() || isRemoteControlling(M)) + return TRUE - else if(ishuman(M)) + if(ishuman(M)) var/mob/living/carbon/human/H = M //if they are holding or wearing a card that has access, that works - if(check_access(H.get_active_hand()) || check_access(H.wear_id)) return TRUE - else if(istype(M, /mob/living/carbon/xenomorph)) + if(check_access(H.get_active_hand()) || check_access(H.wear_id)) + return TRUE + return check_yautja_access(H) + if(istype(M, /mob/living/carbon/xenomorph)) var/mob/living/carbon/C = M - if(check_access(C.get_active_hand())) return TRUE - return FALSE + if(check_access(C.get_active_hand())) + return TRUE + return FALSE + +/obj/proc/check_yautja_access(mob/living/carbon/human/yautja) + if(!istype(yautja)) + return FALSE + var/obj/item/clothing/gloves/yautja/hunter/bracer = yautja.gloves + if(!istype(bracer) || !bracer.embedded_id || !check_access(bracer.embedded_id)) + return FALSE + return TRUE /obj/item/proc/GetAccess() return list() @@ -82,105 +93,244 @@ return return 1 -/proc/get_centcom_access(job) - return get_all_centcom_access() - -/proc/get_all_accesses() - return get_all_marine_access() + get_all_civilian_accesses() - -/proc/get_all_civilian_accesses() - return list( - ACCESS_CIVILIAN_PUBLIC, - ACCESS_CIVILIAN_RESEARCH, - ACCESS_CIVILIAN_ENGINEERING, - ACCESS_CIVILIAN_LOGISTICS, - ACCESS_CIVILIAN_BRIG, - ACCESS_CIVILIAN_MEDBAY, - ACCESS_CIVILIAN_COMMAND, - ) - -/proc/get_all_marine_access() - return list( - ACCESS_MARINE_CAPTAIN, - ACCESS_MARINE_SENIOR, - ACCESS_MARINE_DATABASE, - ACCESS_MARINE_COMMAND, - ACCESS_MARINE_CMP, - ACCESS_MARINE_BRIG, - ACCESS_MARINE_ARMORY, - ACCESS_MARINE_CMO, - ACCESS_MARINE_MEDBAY, - ACCESS_MARINE_CHEMISTRY, - ACCESS_MARINE_MORGUE, - ACCESS_MARINE_RESEARCH, - ACCESS_MARINE_CE, - ACCESS_MARINE_ENGINEERING, - ACCESS_MARINE_MAINT, - ACCESS_MARINE_OT, - ACCESS_MARINE_RO, - ACCESS_MARINE_CARGO, - ACCESS_MARINE_PREP, - ACCESS_MARINE_MEDPREP, - ACCESS_MARINE_ENGPREP, - ACCESS_MARINE_SMARTPREP, - ACCESS_MARINE_LEADER, - ACCESS_MARINE_SPECPREP, - ACCESS_MARINE_RTO_PREP, - ACCESS_MARINE_ALPHA, - ACCESS_MARINE_BRAVO, - ACCESS_MARINE_CHARLIE, - ACCESS_MARINE_DELTA, - ACCESS_MARINE_PILOT, - ACCESS_MARINE_DROPSHIP, - ACCESS_MARINE_SEA, - ACCESS_MARINE_KITCHEN, - ACCESS_MARINE_SYNTH, - ACCESS_PRESS, - ) - -/proc/get_all_centcom_access() - return list(ACCESS_WY_PMC_GREEN, ACCESS_WY_PMC_ORANGE, ACCESS_WY_PMC_RED, ACCESS_WY_PMC_BLACK, ACCESS_WY_PMC_WHITE, ACCESS_WY_CORPORATE) - -/proc/get_all_syndicate_access() - return list(ACCESS_ILLEGAL_PIRATE) - -/proc/get_antagonist_access() - return get_all_accesses() + get_all_syndicate_access() - -/proc/get_antagonist_pmc_access() - return get_antagonist_access() - -/proc/get_freelancer_access() - return list(ACCESS_MARINE_COMMAND, ACCESS_MARINE_CARGO, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS) + +/proc/get_access(access_list = ACCESS_LIST_GLOBAL) + switch(access_list) + if(ACCESS_LIST_GLOBAL) + return list(ACCESS_ILLEGAL_PIRATE) + get_access(ACCESS_LIST_MARINE_ALL) + get_access(ACCESS_LIST_WY_ALL) + get_access(ACCESS_LIST_COLONIAL_ALL) + get_access(ACCESS_LIST_CLF_ALL) + get_access(ACCESS_LIST_UPP_ALL) + if(ACCESS_LIST_MARINE_MAIN) + return list( + ACCESS_MARINE_SENIOR, + ACCESS_MARINE_DATABASE, + ACCESS_MARINE_COMMAND, + ACCESS_MARINE_CMP, + ACCESS_MARINE_BRIG, + ACCESS_MARINE_ARMORY, + ACCESS_MARINE_CMO, + ACCESS_MARINE_MEDBAY, + ACCESS_MARINE_CHEMISTRY, + ACCESS_MARINE_MORGUE, + ACCESS_MARINE_RESEARCH, + ACCESS_MARINE_CE, + ACCESS_MARINE_ENGINEERING, + ACCESS_MARINE_MAINT, + ACCESS_MARINE_OT, + ACCESS_MARINE_RO, + ACCESS_MARINE_CARGO, + ACCESS_MARINE_PREP, + ACCESS_MARINE_MEDPREP, + ACCESS_MARINE_ENGPREP, + ACCESS_MARINE_SMARTPREP, + ACCESS_MARINE_LEADER, + ACCESS_MARINE_SPECPREP, + ACCESS_MARINE_TL_PREP, + ACCESS_MARINE_ALPHA, + ACCESS_MARINE_BRAVO, + ACCESS_MARINE_CHARLIE, + ACCESS_MARINE_DELTA, + ACCESS_MARINE_PILOT, + ACCESS_MARINE_DROPSHIP, + ACCESS_MARINE_SEA, + ACCESS_MARINE_KITCHEN, + ACCESS_MARINE_SYNTH, + ACCESS_MARINE_ASO, + ACCESS_MARINE_CHAPLAIN, + ACCESS_PRESS, + ) + + if(ACCESS_LIST_MARINE_ALL) + return list( + ACCESS_MARINE_CO, + ACCESS_MARINE_AI, + ACCESS_MARINE_AI_TEMP, + ) + get_access(ACCESS_LIST_MARINE_MAIN) + + if(ACCESS_LIST_EMERGENCY_RESPONSE) + return list( + ACCESS_MARINE_MAINT, + ACCESS_MARINE_MEDBAY, + ACCESS_MARINE_KITCHEN, + ACCESS_PRESS, + ) + + if(ACCESS_LIST_UA) + return get_access(ACCESS_LIST_MARINE_MAIN) + get_access(ACCESS_LIST_COLONIAL_ALL) + + if(ACCESS_LIST_MARINE_LIAISON) + return list( + ACCESS_WY_GENERAL, + ACCESS_WY_COLONIAL, + ACCESS_WY_FLIGHT, + ACCESS_WY_RESEARCH, + ACCESS_WY_EXEC, + ACCESS_MARINE_COMMAND, + ACCESS_MARINE_RESEARCH, + ACCESS_MARINE_MEDBAY, + ) + get_access(ACCESS_LIST_COLONIAL_ALL) + + if(ACCESS_LIST_COLONIAL_ALL) + return list( + ACCESS_CIVILIAN_PUBLIC, + ACCESS_CIVILIAN_RESEARCH, + ACCESS_CIVILIAN_ENGINEERING, + ACCESS_CIVILIAN_LOGISTICS, + ACCESS_CIVILIAN_BRIG, + ACCESS_CIVILIAN_MEDBAY, + ACCESS_CIVILIAN_COMMAND, + ) + + if(ACCESS_LIST_CIVIL_LIAISON) + return list( + ACCESS_WY_GENERAL, + ACCESS_WY_COLONIAL, + ACCESS_WY_RESEARCH, + ACCESS_WY_EXEC, + ) + get_access(ACCESS_LIST_COLONIAL_ALL) + + if(ACCESS_LIST_DELIVERY) + return list( + ACCESS_MARINE_COMMAND, + ACCESS_MARINE_CARGO, + ACCESS_CIVILIAN_PUBLIC, + ACCESS_CIVILIAN_RESEARCH, + ACCESS_CIVILIAN_ENGINEERING, + ACCESS_CIVILIAN_LOGISTICS, + ) + + + if(ACCESS_LIST_WY_ALL) + return list( + ACCESS_WY_GENERAL, + ACCESS_WY_COLONIAL, + ACCESS_WY_MEDICAL, + ACCESS_WY_SECURITY, + ACCESS_WY_ENGINEERING, + ACCESS_WY_FLIGHT, + ACCESS_WY_RESEARCH, + ACCESS_WY_EXEC, + ACCESS_WY_PMC, + ACCESS_WY_PMC_TL, + ACCESS_WY_ARMORY, + ACCESS_WY_SECRETS, + ACCESS_WY_LEADERSHIP, + ACCESS_WY_SENIOR_LEAD, + ) + get_access(ACCESS_LIST_COLONIAL_ALL) + + if(ACCESS_LIST_WY_BASE) + return list( + ACCESS_WY_GENERAL, + ACCESS_WY_COLONIAL, + ACCESS_WY_MEDICAL, + ) + + if(ACCESS_LIST_WY_SENIOR) + return list( + ACCESS_WY_GENERAL, + ACCESS_WY_COLONIAL, + ACCESS_WY_MEDICAL, + ACCESS_WY_SECURITY, + ACCESS_WY_ENGINEERING, + ACCESS_WY_FLIGHT, + ACCESS_WY_RESEARCH, + ACCESS_WY_EXEC, + ACCESS_WY_PMC, + ACCESS_WY_PMC_TL, + ACCESS_WY_ARMORY, + ACCESS_WY_LEADERSHIP, + ACCESS_WY_SENIOR_LEAD, + ) + get_access(ACCESS_LIST_COLONIAL_ALL) + + if(ACCESS_LIST_WY_GOON) + return list( + ACCESS_WY_GENERAL, + ACCESS_WY_COLONIAL, + ACCESS_WY_MEDICAL, + ACCESS_WY_SECURITY, + ACCESS_WY_RESEARCH, + ACCESS_WY_ARMORY, + ) + get_access(ACCESS_LIST_COLONIAL_ALL) + get_access(ACCESS_LIST_EMERGENCY_RESPONSE) + + if(ACCESS_LIST_WY_PMC) + return list( + ACCESS_WY_PMC, + ACCESS_WY_ENGINEERING, + ACCESS_WY_FLIGHT, + ) + get_access(ACCESS_LIST_WY_GOON) + + if(ACCESS_LIST_CLF_ALL) + return list( + ACCESS_CLF_SECURITY, + ACCESS_CLF_ARMORY, + ACCESS_CLF_LEADERSHIP, + ACCESS_CLF_SENIOR_LEAD, + ) + get_access(ACCESS_LIST_CLF_BASE) + + if(ACCESS_LIST_CLF_BASE) + return list( + ACCESS_CLF_GENERAL, + ACCESS_CLF_MEDICAL, + ACCESS_CLF_ENGINEERING, + ) + get_access(ACCESS_LIST_COLONIAL_ALL) + get_access(ACCESS_LIST_EMERGENCY_RESPONSE) + + if(ACCESS_LIST_UPP_ALL) + return list( + ACCESS_UPP_GENERAL, + ACCESS_UPP_MEDICAL, + ACCESS_UPP_ENGINEERING, + ACCESS_UPP_SECURITY, + ACCESS_UPP_ARMORY, + ACCESS_UPP_FLIGHT, + ACCESS_UPP_RESEARCH, + ACCESS_UPP_COMMANDO, + ACCESS_UPP_LEADERSHIP, + ACCESS_UPP_SENIOR_LEAD, + ) + get_access(ACCESS_LIST_COLONIAL_ALL) + get_access(ACCESS_LIST_EMERGENCY_RESPONSE) /proc/get_region_accesses(code) switch(code) - if(0) - return get_all_accesses() - if(1) - return list(ACCESS_MARINE_CMP, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY) // Security - if(2) - return list(ACCESS_MARINE_CMO, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_MORGUE, ACCESS_MARINE_CHEMISTRY) // Medbay - if(3) - return list(ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_MORGUE) // Research - if(4) - return list(ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_OT, ACCESS_MARINE_MAINT) // Engineering - if(5) - return list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_SENIOR, ACCESS_MARINE_DATABASE, ACCESS_MARINE_COMMAND, ACCESS_MARINE_RO, ACCESS_MARINE_CARGO, ACCESS_MARINE_SEA, ACCESS_MARINE_SYNTH) // Command - if(6) - return list(ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP, ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_SPECPREP, ACCESS_MARINE_RTO_PREP, ACCESS_MARINE_KITCHEN)//spess mahreens - if(7) - return list(ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA) // Squads - if(8) + if(0)//Everything + return get_access(ACCESS_LIST_COLONIAL_ALL) + get_access(ACCESS_LIST_MARINE_MAIN) + if(1)//Security + return list(ACCESS_MARINE_CMP, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY) + if(2)//Medbay + return list(ACCESS_MARINE_CMO, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_MORGUE, ACCESS_MARINE_CHEMISTRY) + if(3)//Research + return list(ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_MORGUE) + if(4)//Engineering + return list(ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_OT, ACCESS_MARINE_MAINT) + if(5)//Command return list( - ACCESS_CIVILIAN_PUBLIC, - ACCESS_CIVILIAN_RESEARCH, - ACCESS_CIVILIAN_ENGINEERING, - ACCESS_CIVILIAN_LOGISTICS, - ACCESS_CIVILIAN_BRIG, - ACCESS_CIVILIAN_MEDBAY, - ACCESS_CIVILIAN_COMMAND, - ) //Civilian + ACCESS_MARINE_SENIOR, + ACCESS_MARINE_DATABASE, + ACCESS_MARINE_COMMAND, + ACCESS_MARINE_RO, + ACCESS_MARINE_CARGO, + ACCESS_MARINE_SEA, + ACCESS_MARINE_SYNTH, + ) + if(6)//Marines + return list( + ACCESS_MARINE_PREP, + ACCESS_MARINE_MEDPREP, + ACCESS_MARINE_ENGPREP, + ACCESS_MARINE_SMARTPREP, + ACCESS_MARINE_LEADER, + ACCESS_MARINE_SPECPREP, + ACCESS_MARINE_TL_PREP, + ACCESS_MARINE_KITCHEN, + ) + if(7)//Squads + return list(ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA) + if(8)//Civilian + return list( + ACCESS_CIVILIAN_PUBLIC, + ACCESS_CIVILIAN_RESEARCH, + ACCESS_CIVILIAN_ENGINEERING, + ACCESS_CIVILIAN_LOGISTICS, + ACCESS_CIVILIAN_BRIG, + ACCESS_CIVILIAN_MEDBAY, + ACCESS_CIVILIAN_COMMAND, + ) /proc/get_region_accesses_name(code) switch(code) @@ -205,54 +355,124 @@ /proc/get_access_desc(A) switch(A) - if(ACCESS_MARINE_CMP) return "CMP's Office" - if(ACCESS_MARINE_BRIG) return "Brig" - if(ACCESS_MARINE_ARMORY) return "Armory" - if(ACCESS_MARINE_CMO) return "CMO's Office" - if(ACCESS_MARINE_MEDBAY) return "[MAIN_SHIP_NAME] Medbay" - if(ACCESS_MARINE_RESEARCH) return "[MAIN_SHIP_NAME] Research" - if(ACCESS_MARINE_CHEMISTRY) return "[MAIN_SHIP_NAME] Chemistry" - if(ACCESS_MARINE_MORGUE) return "[MAIN_SHIP_NAME] Morgue" - if(ACCESS_MARINE_CE) return "CE's Office" - if(ACCESS_MARINE_RO) return "RO's Office" - if(ACCESS_MARINE_ENGINEERING) return "[MAIN_SHIP_NAME] Engineering" - if(ACCESS_MARINE_OT) return "[MAIN_SHIP_NAME] Ordnance Workshop" - if(ACCESS_MARINE_SENIOR) return "[MAIN_SHIP_NAME] Senior Command" - if(ACCESS_MARINE_CAPTAIN) return "Commander's Quarters" - if(ACCESS_MARINE_DATABASE) return "[MAIN_SHIP_NAME]'s Database" - if(ACCESS_MARINE_COMMAND) return "[MAIN_SHIP_NAME] Command" - if(ACCESS_MARINE_CREWMAN) return "Vehicle Crewman" - if(ACCESS_MARINE_PREP) return "Marine Prep" - if(ACCESS_MARINE_ENGPREP) return "Marine Squad Engineering" - if(ACCESS_MARINE_MEDPREP) return "Marine Squad Medical" - if(ACCESS_MARINE_SPECPREP) return "Marine Weapons Specialist" - if(ACCESS_MARINE_SMARTPREP) return "Marine Smartgunner" - if(ACCESS_MARINE_RTO_PREP) return "Marine Radio Telephone Operator" - if(ACCESS_MARINE_LEADER) return "Marine Leader" - if(ACCESS_MARINE_ALPHA) return "Alpha Squad" - if(ACCESS_MARINE_BRAVO) return "Bravo Squad" - if(ACCESS_MARINE_CHARLIE) return "Charlie Squad" - if(ACCESS_MARINE_DELTA) return "Delta Squad" - if(ACCESS_MARINE_CARGO) return "Requisitions" - if(ACCESS_MARINE_DROPSHIP) return "Dropship Piloting" - if(ACCESS_MARINE_PILOT) return "Pilot Gear" - if(ACCESS_MARINE_MAINT) return "[MAIN_SHIP_NAME] Maintenance" - if(ACCESS_CIVILIAN_RESEARCH) return "Civilian Research" - if(ACCESS_CIVILIAN_COMMAND) return "Civilian Command" - if(ACCESS_CIVILIAN_MEDBAY) return "Civilian Medbay" - if(ACCESS_CIVILIAN_LOGISTICS) return "Civilian Logistics" - if(ACCESS_CIVILIAN_ENGINEERING) return "Civilian Engineering" - if(ACCESS_CIVILIAN_BRIG) return "Civilian Brig" - if(ACCESS_CIVILIAN_PUBLIC) return "Civilian" - if(ACCESS_MARINE_SEA) return "SEA's Office" - if(ACCESS_MARINE_KITCHEN) return "Kitchen" - if(ACCESS_MARINE_SYNTH) return "Synthetic Storage" - -/proc/get_centcom_access_desc(A) + if(ACCESS_MARINE_CMP) + return "CMP's Office" + if(ACCESS_MARINE_BRIG) + return "Brig" + if(ACCESS_MARINE_ARMORY) + return "Armory" + if(ACCESS_MARINE_CMO) + return "CMO's Office" + if(ACCESS_MARINE_MEDBAY) + return "[MAIN_SHIP_NAME] Medbay" + if(ACCESS_MARINE_RESEARCH) + return "[MAIN_SHIP_NAME] Research" + if(ACCESS_MARINE_CHEMISTRY) + return "[MAIN_SHIP_NAME] Chemistry" + if(ACCESS_MARINE_MORGUE) + return "[MAIN_SHIP_NAME] Morgue" + if(ACCESS_MARINE_CE) + return "CE's Office" + if(ACCESS_MARINE_RO) + return "RO's Office" + if(ACCESS_MARINE_ENGINEERING) + return "[MAIN_SHIP_NAME] Engineering" + if(ACCESS_MARINE_OT) + return "[MAIN_SHIP_NAME] Ordnance Workshop" + if(ACCESS_MARINE_SENIOR) + return "[MAIN_SHIP_NAME] Senior Command" + if(ACCESS_MARINE_CO) + return "Commander's Quarters" + if(ACCESS_MARINE_DATABASE) + return "[MAIN_SHIP_NAME]'s Database" + if(ACCESS_MARINE_COMMAND) + return "[MAIN_SHIP_NAME] Command" + if(ACCESS_MARINE_CREWMAN) + return "Vehicle Crewman" + if(ACCESS_MARINE_PREP) + return "Marine Prep" + if(ACCESS_MARINE_ENGPREP) + return "Marine Squad Engineering" + if(ACCESS_MARINE_MEDPREP) + return "Marine Squad Medical" + if(ACCESS_MARINE_SPECPREP) + return "Marine Weapons Specialist" + if(ACCESS_MARINE_SMARTPREP) + return "Marine Smartgunner" + if(ACCESS_MARINE_TL_PREP) + return "Marine Team Leader" + if(ACCESS_MARINE_LEADER) + return "Marine Leader" + if(ACCESS_MARINE_ALPHA) + return "Alpha Squad" + if(ACCESS_MARINE_BRAVO) + return "Bravo Squad" + if(ACCESS_MARINE_CHARLIE) + return "Charlie Squad" + if(ACCESS_MARINE_DELTA) + return "Delta Squad" + if(ACCESS_MARINE_CARGO) + return "Requisitions" + if(ACCESS_MARINE_DROPSHIP) + return "Dropship Piloting" + if(ACCESS_MARINE_PILOT) + return "Pilot Gear" + if(ACCESS_MARINE_MAINT) + return "[MAIN_SHIP_NAME] Maintenance" + if(ACCESS_CIVILIAN_RESEARCH) + return "Civilian Research" + if(ACCESS_CIVILIAN_COMMAND) + return "Civilian Command" + if(ACCESS_CIVILIAN_MEDBAY) + return "Civilian Medbay" + if(ACCESS_CIVILIAN_LOGISTICS) + return "Civilian Logistics" + if(ACCESS_CIVILIAN_ENGINEERING) + return "Civilian Engineering" + if(ACCESS_CIVILIAN_BRIG) + return "Civilian Brig" + if(ACCESS_CIVILIAN_PUBLIC) + return "Civilian" + if(ACCESS_MARINE_SEA) + return "SEA's Office" + if(ACCESS_MARINE_KITCHEN) + return "Kitchen" + if(ACCESS_MARINE_SYNTH) + return "Synthetic Storage" + if(ACCESS_MARINE_AI) + return "AI Core" + if(ACCESS_MARINE_AI_TEMP) + return "AI Access" + if(ACCESS_ARES_DEBUG) + return "AI Debug" + +/proc/get_weyland_access_desc(A) switch(A) - if(ACCESS_WY_PMC_GREEN) return "Wey-Yu PMC Green" - if(ACCESS_WY_PMC_ORANGE) return "Wey-Yu PMC Orange" - if(ACCESS_WY_PMC_RED) return "Wey-Yu PMC Red" - if(ACCESS_WY_PMC_BLACK) return "Wey-Yu PMC Black" - if(ACCESS_WY_PMC_WHITE) return "Wey-Yu PMC White" - if(ACCESS_WY_CORPORATE) return "Wey-Yu Executive" + if(ACCESS_WY_GENERAL) + return "Wey-Yu General" + if(ACCESS_WY_COLONIAL) + return "Wey-Yu Colony" + if(ACCESS_WY_MEDICAL) + return "Wey-Yu Medical" + if(ACCESS_WY_SECURITY) + return "Wey-Yu Security" + if(ACCESS_WY_ENGINEERING) + return "Wey-Yu Engineering" + if(ACCESS_WY_FLIGHT) + return "Wey-Yu Flight Control" + if(ACCESS_WY_RESEARCH) + return "Wey-Yu Research" + if(ACCESS_WY_EXEC) + return "Wey-Yu Corporate" + if(ACCESS_WY_PMC) + return "Wey-Yu PMC" + if(ACCESS_WY_PMC_TL) + return "Wey-Yu PMC Lead" + if(ACCESS_WY_ARMORY) + return "Wey-Yu Armory" + if(ACCESS_WY_SECRETS) + return "Wey-Yu HighSec" + if(ACCESS_WY_LEADERSHIP) + return "Wey-Yu Leadership" + if(ACCESS_WY_SENIOR_LEAD) + return "Wey-Yu Senior Leadership" diff --git a/code/game/jobs/job/antag/xeno/xenomorph.dm b/code/game/jobs/job/antag/xeno/xenomorph.dm index c7ea4fbae272..53b06147e28c 100644 --- a/code/game/jobs/job/antag/xeno/xenomorph.dm +++ b/code/game/jobs/job/antag/xeno/xenomorph.dm @@ -25,14 +25,14 @@ transform_to_xeno(H, XENO_HIVE_NORMAL) -/datum/job/antag/xenos/proc/transform_to_xeno(mob/living/carbon/human/H, hive_index) - var/datum/mind/new_xeno = H.mind +/datum/job/antag/xenos/proc/transform_to_xeno(mob/living/carbon/human/human_to_transform, hive_index) + var/datum/mind/new_xeno = human_to_transform.mind new_xeno.setup_xeno_stats() var/datum/hive_status/hive = GLOB.hive_datum[hive_index] - H.first_xeno = TRUE - H.set_stat(UNCONSCIOUS) - H.forceMove(get_turf(pick(GLOB.xeno_spawns))) + human_to_transform.first_xeno = TRUE + human_to_transform.set_stat(UNCONSCIOUS) + human_to_transform.forceMove(get_turf(pick(GLOB.xeno_spawns))) var/list/survivor_types = list( /datum/equipment_preset/survivor/scientist, @@ -40,26 +40,64 @@ /datum/equipment_preset/survivor/security, /datum/equipment_preset/survivor/engineer ) - arm_equipment(H, pick(survivor_types), FALSE, FALSE) + arm_equipment(human_to_transform, pick(survivor_types), FALSE, FALSE) - for(var/obj/item/device/radio/radio in H.contents_recursive()) + for(var/obj/item/device/radio/radio in human_to_transform.contents_recursive()) radio.listening = FALSE - H.job = title - H.apply_damage(50, BRUTE) - H.spawned_corpse = TRUE + human_to_transform.job = title + human_to_transform.apply_damage(50, BRUTE) + human_to_transform.spawned_corpse = TRUE - var/obj/structure/bed/nest/start_nest = new /obj/structure/bed/nest(H.loc) //Create a new nest for the host - H.statistic_exempt = TRUE - H.buckled = start_nest - H.setDir(start_nest.dir) - H.update_canmove() - start_nest.buckled_mob = H - start_nest.afterbuckle(H) + //placing the nests on walls logic + var/count = 0 + var/obj/structure/bed/nest/start_nest + var/list/turf/list_to_search = list(get_turf(human_to_transform)) + while(isnull(start_nest)) + count++ + var/list/turf/new_entries = list() + for(var/turf/turf_to_search in list_to_search) + new_entries |= list(get_step(turf_to_search, NORTH), get_step(turf_to_search, SOUTH), get_step(turf_to_search, EAST), get_step(turf_to_search, WEST)) + var/list/turf/bad_entries = list() + for(var/turf/open/found_open_turf in new_entries) + for(var/obj/found_object in found_open_turf) + if(istype(found_object, /obj/structure/window/framed) || found_object.density) + bad_entries |= found_open_turf + for(var/turf/closed/wall/wall_in_range in new_entries) + var/list/turf/neighbor_turfs = list(get_step(wall_in_range, SOUTH), get_step(wall_in_range, EAST), get_step(wall_in_range, WEST)) + for(var/turf/open/ground_in_range in neighbor_turfs) + var/area/in_range_area = get_area(ground_in_range) + if(in_range_area.flags_area & AREA_NOTUNNEL) + continue + var/finish_proc = TRUE + for(var/obj/found_object in ground_in_range) + if(istype(found_object, /obj/structure/bed/nest/) || found_object.density) + finish_proc = FALSE + break + if(finish_proc) + human_to_transform.forceMove(ground_in_range) + start_nest = new /obj/structure/bed/nest(human_to_transform.loc) //Create a new nest for the host + start_nest.dir = get_dir(human_to_transform,wall_in_range) + break + bad_entries |= wall_in_range //no viable turfs found for this wall; we remove it + new_entries -= bad_entries + list_to_search = new_entries + if(count > 20) // we dont got all day, we got a game to play baby! + start_nest = new /obj/structure/bed/nest(human_to_transform.loc) + start_nest.dir = NORTH + break - var/obj/item/alien_embryo/embryo = new /obj/item/alien_embryo(H) //Put the initial larva in a host + human_to_transform.statistic_exempt = TRUE + human_to_transform.buckled = start_nest + human_to_transform.setDir(start_nest.dir) + human_to_transform.update_canmove() + start_nest.buckled_mob = human_to_transform + start_nest.afterbuckle(human_to_transform) + + var/obj/item/alien_embryo/embryo = new /obj/item/alien_embryo(human_to_transform) //Put the initial larva in a host embryo.stage = 5 //Give the embryo a head-start (make the larva burst instantly) embryo.hivenumber = hive.hivenumber + /datum/job/antag/xenos/equip_job(mob/living/M) return diff --git a/code/game/jobs/job/civilians/other/mess_seargent.dm b/code/game/jobs/job/civilians/other/mess_seargent.dm index 37e0b01ad711..615df24ecb47 100644 --- a/code/game/jobs/job/civilians/other/mess_seargent.dm +++ b/code/game/jobs/job/civilians/other/mess_seargent.dm @@ -4,7 +4,7 @@ spawn_positions = 1 selection_class = "job_ot" flags_startup_parameters = ROLE_ADD_TO_DEFAULT - supervisors = "the acting commanding officer" + supervisors = "the auxiliary support officer" gear_preset = /datum/equipment_preset/uscm_ship/chef entry_message_body = "Your job is to service the marines with excellent food, drinks and entertaining the shipside crew when needed. You have a lot of freedom and it is up to you, to decide what to do with it. Good luck!" diff --git a/code/game/jobs/job/civilians/other/reporter.dm b/code/game/jobs/job/civilians/other/reporter.dm index d9762c66289c..c681768f93bc 100644 --- a/code/game/jobs/job/civilians/other/reporter.dm +++ b/code/game/jobs/job/civilians/other/reporter.dm @@ -1,5 +1,5 @@ -#define MILITARY_VARIANT "Mil" -#define CIVILIAN_VARIANT "Civ" +#define MILITARY_VARIANT "Military Correspondent" +#define CIVILIAN_VARIANT "Civilian Correspondent" /datum/job/civilian/reporter title = JOB_COMBAT_REPORTER @@ -11,7 +11,7 @@ flags_startup_parameters = ROLE_ADD_TO_DEFAULT selection_class = "job_cl" - job_options = list(CIVILIAN_VARIANT, MILITARY_VARIANT) + job_options = list(CIVILIAN_VARIANT = "Civ", MILITARY_VARIANT = "Mil") /// If this job is a military variant of the reporter role var/military = FALSE @@ -25,9 +25,9 @@ /datum/job/civilian/reporter/generate_entry_message(mob/living/carbon/human/H) if(military) - . = {"The USCM has assigned you to the USS Almayer to better handle messaging on how things run in the Neroid Sector. Get out there and show the universe that the USCM is doing great things!"} + . = {"The USCM has assigned you to the [MAIN_SHIP_NAME] to better handle messaging on how things run in the Neroid Sector. Get out there and show the universe that the USCM is doing great things!"} else - . = {"What a scoop! You've been assigned to the USS Almayer to see what kinda mischief they'd get into and it seems trouble is here! + . = {"What a scoop! You've been assigned to the [MAIN_SHIP_NAME] to see what kinda mischief they'd get into and it seems trouble is here! This could be the story of the sector! 'Brave Marines responding to dangerous distress signal!' It'd surely get Mr. Parkerson to notice you in the office if you brought him a story like this!"} /obj/effect/landmark/start/reporter diff --git a/code/game/jobs/job/civilians/other/survivors.dm b/code/game/jobs/job/civilians/other/survivors.dm index e3ea0c9e521d..ff2d7d229fba 100644 --- a/code/game/jobs/job/civilians/other/survivors.dm +++ b/code/game/jobs/job/civilians/other/survivors.dm @@ -7,6 +7,7 @@ total_positions = 8 flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_CUSTOM_SPAWN late_joinable = FALSE + job_options = SURVIVOR_VARIANT_LIST var/intro_text var/story_text @@ -107,8 +108,8 @@ arm_equipment(equipping_human, picked_spawner.equipment, FALSE, TRUE) else var/preferred_variant = ANY_SURVIVOR - if(equipping_human.client?.prefs?.preferred_survivor_variant != ANY_SURVIVOR) - preferred_variant = equipping_human.client?.prefs?.preferred_survivor_variant + if(equipping_human.client?.prefs?.pref_special_job_options[JOB_SURVIVOR] != ANY_SURVIVOR) + preferred_variant = equipping_human.client?.prefs?.pref_special_job_options[JOB_SURVIVOR] if(MAX_SURVIVOR_PER_TYPE[preferred_variant] != -1 && SSticker.mode.survivors_by_type_amounts[preferred_variant] && SSticker.mode.survivors_by_type_amounts[preferred_variant] >= MAX_SURVIVOR_PER_TYPE[preferred_variant]) preferred_variant = ANY_SURVIVOR @@ -130,6 +131,7 @@ AddTimelock(/datum/job/civilian/survivor, list( flags_whitelist = WHITELIST_SYNTHETIC total_positions = 1 spawn_positions = 1 + job_options = null /datum/job/civilian/survivor/synth/set_spawn_positions(count) return spawn_positions @@ -139,8 +141,8 @@ AddTimelock(/datum/job/civilian/survivor, list( arm_equipment(equipping_human, picked_spawner.synth_equipment, FALSE, TRUE) else var/preferred_variant = ANY_SURVIVOR - if(equipping_human.client?.prefs?.preferred_survivor_variant != ANY_SURVIVOR) - preferred_variant = equipping_human.client?.prefs?.preferred_survivor_variant + if(equipping_human.client?.prefs?.pref_special_job_options[JOB_SURVIVOR] != ANY_SURVIVOR) + preferred_variant = equipping_human.client?.prefs?.pref_special_job_options[JOB_SURVIVOR] if(MAX_SURVIVOR_PER_TYPE[preferred_variant] != -1 && SSticker.mode.survivors_by_type_amounts[preferred_variant] && SSticker.mode.survivors_by_type_amounts[preferred_variant] >= MAX_SURVIVOR_PER_TYPE[preferred_variant]) preferred_variant = ANY_SURVIVOR @@ -156,6 +158,7 @@ AddTimelock(/datum/job/civilian/survivor, list( flags_whitelist = WHITELIST_COMMANDER total_positions = 0 spawn_positions = 0 + job_options = null /datum/job/civilian/survivor/commanding_officer/set_spawn_positions() var/list/CO_survivor_types = SSmapping.configs[GROUND_MAP].CO_survivor_types diff --git a/code/game/jobs/job/civilians/support/doctor.dm b/code/game/jobs/job/civilians/support/doctor.dm index 4de4b53c0a59..587c4727690f 100644 --- a/code/game/jobs/job/civilians/support/doctor.dm +++ b/code/game/jobs/job/civilians/support/doctor.dm @@ -1,3 +1,8 @@ +//job options for doctors surgeon pharmacy technician(preparation of medecine and distribution) + +#define DOCTOR_VARIANT "Doctor" +#define SURGEON_VARIANT "Surgeon" + // Doctor /datum/job/civilian/doctor title = JOB_DOCTOR @@ -9,7 +14,27 @@ selection_class = "job_doctor" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/doctor - entry_message_body = "You're a commissioned officer of the USCM, though you are not in the ship's chain of command. You are tasked with keeping the marines healthy and strong, usually in the form of surgery. You are also an expert when it comes to medication and treatment. If you do not know what you are doing, mentorhelp so a mentor can assist you." + + // job option + job_options = list(DOCTOR_VARIANT = "Doc", SURGEON_VARIANT = "Sur") + /// If this job is a doctor variant of the doctor role + var/doctor = TRUE + +//check the job option. and change the gear preset +/datum/job/civilian/doctor/handle_job_options(option) + if(option != SURGEON_VARIANT) + doctor = TRUE + gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/doctor + else + doctor = FALSE + gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/doctor/surgeon + +//check what job option you took and generate the corresponding the good texte. +/datum/job/civilian/doctor/generate_entry_message(mob/living/carbon/human/H) + if(doctor) + . = {"You're a commissioned officer of the USCM, though you are not in the ship's chain of command. You are a doctor and tasked with keeping the marines healthy and strong, usually in the form of surgery. You are a jack of all trades in medicine: you can medicate, perform surgery and produce pharmaceuticals. If you do not know what you are doing, mentorhelp so a mentor can assist you."} + else + . = {"You're a commissioned officer of the USCM, though you are not in the ship's chain of command. You are a surgeon and tasked with keeping the marines healthy and strong, usually in the form of surgery. You are a doctor that specializes in surgery, but you are also very capable in pharmacy and triage. If you do not know what you are doing, mentorhelp so a mentor can assist you."} /datum/job/civilian/doctor/set_spawn_positions(count) spawn_positions = doc_slot_formula(count) diff --git a/code/game/jobs/job/civilians/support/nurse.dm b/code/game/jobs/job/civilians/support/nurse.dm index f510548c8a95..034421d799aa 100644 --- a/code/game/jobs/job/civilians/support/nurse.dm +++ b/code/game/jobs/job/civilians/support/nurse.dm @@ -6,7 +6,7 @@ selection_class = "job_doctor" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/nurse - entry_message_body = "You are tasked with keeping the Marines healthy and strong. You are also an expert when it comes to medication and treatment, but you do not know anything about surgery. Focus on assisting doctors and triaging wounded marines." + entry_message_body = "You are tasked with keeping the Marines healthy and strong. You are also an expert when it comes to medication and treatment, and can do minor surgical procedures. Focus on assisting doctors and triaging wounded marines." /obj/effect/landmark/start/nurse name = JOB_NURSE diff --git a/code/game/jobs/job/civilians/support/working_joe.dm b/code/game/jobs/job/civilians/support/working_joe.dm index d9d12d1db925..d4b575f324f2 100644 --- a/code/game/jobs/job/civilians/support/working_joe.dm +++ b/code/game/jobs/job/civilians/support/working_joe.dm @@ -1,20 +1,62 @@ +#define STANDARD_VARIANT "Working Joe" +#define HAZMAT_VARIANT "Hazmat Joe" + /datum/job/civilian/working_joe title = JOB_WORKING_JOE - total_positions = 8 - spawn_positions = 8 - allow_additional = 1 - supervisors = "ARES and the acting commanding officer" + total_positions = 6 + spawn_positions = 6 + allow_additional = TRUE + scaled = TRUE + supervisors = "ARES and APOLLO" selection_class = "job_working_joe" flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_WHITELISTED|ROLE_CUSTOM_SPAWN flags_whitelist = WHITELIST_JOE gear_preset = /datum/equipment_preset/synth/working_joe - entry_message_body = "You are a Working Joe! You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Synthetic Rules. Failure to do so may result in your White-list Removal. Your primary job is to maintain the cleanliness of the ship, putting things in their proper place. Your capacities are limited, but you have all the equipment you need, and the central AI has a plan!" + + job_options = list(STANDARD_VARIANT = "JOE", HAZMAT_VARIANT = "HAZ") + var/standard = TRUE + +/datum/job/civilian/working_joe/handle_job_options(option) + if(option != HAZMAT_VARIANT) + standard = TRUE + gear_preset = /datum/equipment_preset/synth/working_joe + else + standard = FALSE + gear_preset = /datum/equipment_preset/synth/working_joe/engi + +/datum/job/civilian/working_joe/set_spawn_positions(count) + spawn_positions = working_joe_slot_formula(count) + +/datum/job/civilian/working_joe/get_total_positions(latejoin = 0) + var/positions = spawn_positions + if(latejoin) + positions = working_joe_slot_formula(get_total_marines()) + if(positions <= total_positions_so_far) + positions = total_positions_so_far + else + total_positions_so_far = positions + else + total_positions_so_far = positions + return positions + +/datum/job/civilian/working_joe/generate_entry_message(mob/living/carbon/human/H) + if(standard) + . = {"You are a Working Joe. You are held to a higher standard and are required to obey not only the Server Rules but Marine Law, Roleplay Expectations and Synthetic Rules. Your primary task is to maintain the cleanliness of the ship, putting things in their proper place. Alternatively, your primary task may be to assist with manual labor in limited capacity, or clerical duties. Your capacities are limited, but you have all the equipment you need, and the central AI has a plan! Stay in character at all times. Use the APOLLO link to communicate with your uplink!"} + else + . = {"You are a Working Joe for Hazardous Environments! You are held to a higher standard and are required to obey not only the Server Rules but Marine Law, Roleplay Expectations and Synthetic Rules. You are a variant of the Working Joe built for tougher environments and fulfill the specific duty of dangerous repairs or maintenance. Your primary task is to maintain the reactor, SMES and AI Core. Your secondary task is to respond to hazardous environments, such as an atmospheric breach or biohazard spill, and assist with repairs when ordered to by either an AI Mainframe, or a Commisioned Officer. You should not be seen outside of emergencies besides in Engineering and the AI Core! Stay in character at all times. Use the APOLLO link to communicate with your uplink!"} + /datum/job/civilian/working_joe/announce_entry_message(mob/living/carbon/human/H) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ai_announcement), "[H.real_name] has been deployed to help with operations."), 1.5 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ai_announcement), "[H.real_name] has been activated."), 1.5 SECONDS) return ..() /obj/effect/landmark/start/working_joe name = JOB_WORKING_JOE icon_state = "wj_spawn" job = /datum/job/civilian/working_joe + +/datum/job/civilian/working_joe/generate_entry_conditions(mob/living/M, whitelist_status) + . = ..() + + if(SSticker.mode) + SSticker.mode.initialize_joe(M) diff --git a/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm b/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm new file mode 100644 index 000000000000..262ba271edbf --- /dev/null +++ b/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm @@ -0,0 +1,26 @@ +/datum/job/command/auxiliary_officer + title = JOB_AUXILIARY_OFFICER + total_positions = 1 + spawn_positions = 1 + allow_additional = TRUE + flags_startup_parameters = ROLE_ADD_TO_DEFAULT + gear_preset = /datum/equipment_preset/uscm_ship/auxiliary_officer + entry_message_body = "Your job is to oversee the hangar crew, the intel officers, the engineering department, and requisition department. You have many responsibilities and a few plates to keep spinning but your subordinates are mostly self-reliant. Assist where you can and make sure command personnel are confident the auxiliary departments are operating at peak efficiency." + +AddTimelock(/datum/job/command/auxiliary_officer, list( + JOB_SQUAD_ROLES = 5 HOURS, + JOB_REQUISITION_ROLES = 5 HOURS, + JOB_ENGINEER_ROLES = 5 HOURS, + JOB_AUXILIARY_ROLES = 5 HOURS, +)) + +/obj/effect/landmark/start/auxiliary_officer + name = JOB_AUXILIARY_OFFICER + job = /datum/job/command/auxiliary_officer + +/datum/timelock/auxiliary + name = "Auxiliary Roles" + +/datum/timelock/auxiliary/New(name, time_required, list/roles) + . = ..() + src.roles = JOB_AUXILIARY_ROLES_LIST diff --git a/code/game/jobs/job/command/auxiliary/crew_chief.dm b/code/game/jobs/job/command/auxiliary/crew_chief.dm index 3bf7f0bcd33e..5f846bf6581e 100644 --- a/code/game/jobs/job/command/auxiliary/crew_chief.dm +++ b/code/game/jobs/job/command/auxiliary/crew_chief.dm @@ -4,6 +4,7 @@ spawn_positions = 2 allow_additional = TRUE scaled = TRUE + supervisors = "the pilot officers" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/dcc entry_message_body = "Your job is to assist the pilot officer maintain the ship's dropship. You have authority only on the dropship, but you are expected to maintain order, as not to disrupt the pilot." diff --git a/code/game/jobs/job/command/auxiliary/intel.dm b/code/game/jobs/job/command/auxiliary/intel.dm index f30bb62e8d72..10b8381c417e 100644 --- a/code/game/jobs/job/command/auxiliary/intel.dm +++ b/code/game/jobs/job/command/auxiliary/intel.dm @@ -5,6 +5,7 @@ spawn_positions = 3 allow_additional = 1 scaled = 1 + supervisors = "the auxiliary support officer" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = "USCM Intelligence Officer (IO) (Cryo)" entry_message_body = "Your job is to assist the marines in collecting intelligence related to the current operation to better inform command of their opposition. You are in charge of gathering any data disks, folders, and notes you may find on the operational grounds and decrypt them to grant the USCM additional resources." diff --git a/code/game/jobs/job/command/auxiliary/pilot.dm b/code/game/jobs/job/command/auxiliary/pilot.dm index b7c9d15fa366..57495fe8be28 100644 --- a/code/game/jobs/job/command/auxiliary/pilot.dm +++ b/code/game/jobs/job/command/auxiliary/pilot.dm @@ -4,6 +4,7 @@ spawn_positions = 2 allow_additional = TRUE scaled = TRUE + supervisors = "the auxiliary support officer" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/po entry_message_body = "Your job is to fly, protect, and maintain the ship's dropship. While you are an officer, your authority is limited to the dropship, where you have authority over the enlisted personnel. If you are not piloting, there is an autopilot fallback for command, but don't leave the dropship without reason." diff --git a/code/game/jobs/job/command/auxiliary/senior.dm b/code/game/jobs/job/command/auxiliary/senior.dm index 51b3f1138d5b..68b9a99e4c4f 100644 --- a/code/game/jobs/job/command/auxiliary/senior.dm +++ b/code/game/jobs/job/command/auxiliary/senior.dm @@ -5,7 +5,7 @@ gear_preset = /datum/equipment_preset/uscm_ship/sea entry_message_body = "You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Standard Operating Procedure. Failure to do so may result in your Mentorship Removal. Your primary job is to teach others the game and its mechanics, and offer advice to all USCM Departments and Personnel on-board." - job_options = list("ME7", "ME8", "ME8E", "ME9", "ME9E") + job_options = list("Gunnery Sergeant" = "GySGT", "Master Sergeant" = "MSgt", "First Sergeant" = "1Sgt", "Master Gunnery Sergeant" = "MGySgt", "Sergeant Major" = "SgtMaj") /datum/job/command/senior/announce_entry_message(mob/living/carbon/human/H) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(all_hands_on_deck), "Attention all hands, [H.get_paygrade(0)] [H.real_name] on deck!"), 1.5 SECONDS) diff --git a/code/game/jobs/job/command/cic/captain.dm b/code/game/jobs/job/command/cic/captain.dm index 23084d0c5f72..4049554f7799 100644 --- a/code/game/jobs/job/command/cic/captain.dm +++ b/code/game/jobs/job/command/cic/captain.dm @@ -6,7 +6,6 @@ flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADMIN_NOTIFY|ROLE_WHITELISTED flags_whitelist = WHITELIST_COMMANDER gear_preset = /datum/equipment_preset/uscm_ship/commander - entry_message_body = "You are the Commanding Officer of the USS Almayer as well as the operation. Your goal is to lead the Marines on their mission as well as protect and command the ship and her crew. Your job involves heavy roleplay and requires you to behave like a high-ranking officer and to stay in character at all times. As the Commanding Officer your only superior is High Command itself. You must abide by the Commanding Officer Code of Conduct. Failure to do so may result in punitive action against you. Godspeed." /datum/job/command/commander/New() . = ..() @@ -16,6 +15,10 @@ "[JOB_CO][WHITELIST_LEADER]" = /datum/equipment_preset/uscm_ship/commander/council/plus ) +/datum/job/command/commander/generate_entry_message() + entry_message_body = "You are the Commanding Officer of the [MAIN_SHIP_NAME] as well as the operation. Your goal is to lead the Marines on their mission as well as protect and command the ship and her crew. Your job involves heavy roleplay and requires you to behave like a high-ranking officer and to stay in character at all times. As the Commanding Officer your only superior is High Command itself. You must abide by the Commanding Officer Code of Conduct. Failure to do so may result in punitive action against you. Godspeed." + return ..() + /datum/job/command/commander/get_whitelist_status(list/roles_whitelist, client/player) . = ..() if(!.) diff --git a/code/game/jobs/job/command/cic/executive.dm b/code/game/jobs/job/command/cic/executive.dm index d8691e1df4cf..cc9b4f65e624 100644 --- a/code/game/jobs/job/command/cic/executive.dm +++ b/code/game/jobs/job/command/cic/executive.dm @@ -3,9 +3,9 @@ title = JOB_XO flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADMIN_NOTIFY gear_preset = /datum/equipment_preset/uscm_ship/xo - entry_message_body = "You are second in command aboard the ship, and are in next in the chain of command after the commanding officer. You may need to fill in for other duties if areas are understaffed, and you are given access to do so. Make the USCM proud!" /datum/job/command/executive/generate_entry_message(mob/living/carbon/human/H) + entry_message_body = "You are second in command aboard the [MAIN_SHIP_NAME], and are in next in the chain of command after the Commanding Officer. Where applicable, you must abide by the Commanding Officer Code of Conduct. You may need to fill in for other duties if areas are understaffed, and you are given access to do so. Make the USCM proud!" return ..() /datum/job/command/executive/generate_entry_conditions(mob/living/M, whitelist_status) diff --git a/code/game/jobs/job/command/police/warden.dm b/code/game/jobs/job/command/police/warden.dm index 08e1f7fab02a..851b43debd3c 100644 --- a/code/game/jobs/job/command/police/warden.dm +++ b/code/game/jobs/job/command/police/warden.dm @@ -3,6 +3,7 @@ title = JOB_WARDEN selection_class = "job_mp" flags_startup_parameters = ROLE_ADD_TO_DEFAULT + supervisors = "the Chief MP" gear_preset = /datum/equipment_preset/uscm_ship/uscm_police/warden entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the mainting security records and overwatching any prisoners in Brig." diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 0ca1ac044bfe..74d0495ea4b0 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -34,7 +34,8 @@ /// When set to true, SSticker won't call spawn_in_player, instead calling the job's spawn_and_equip proc var/handle_spawn_and_equip = FALSE - /// When set you will be able to choose between the different job options when selecting your role, try to keep the job option string small to not offset the menu + /// When set you will be able to choose between the different job options when selecting your role. + /// Associated list. Main list elements - actual options, associated values - shorthands for job preferences menu (keep those short). var/job_options /datum/job/New() @@ -220,7 +221,7 @@ var/mob/living/carbon/human/new_character = new(NP.loc) new_character.lastarea = get_area(NP.loc) - NP.client.prefs.copy_all_to(new_character) + NP.client.prefs.copy_all_to(new_character, title) if (NP.client.prefs.be_random_body) var/datum/preferences/TP = new() @@ -287,6 +288,8 @@ join_turf = get_turf(pick(GLOB.spawns_by_job[type])) else if(assigned_squad && GLOB.latejoin_by_squad[assigned_squad]) join_turf = get_turf(pick(GLOB.latejoin_by_squad[assigned_squad])) + else if(GLOB.latejoin_by_job[title]) + join_turf = get_turf(pick(GLOB.latejoin_by_job[title])) else join_turf = get_turf(pick(GLOB.latejoin)) human.forceMove(join_turf) diff --git a/code/game/jobs/job/logistics/cargo/chief_req.dm b/code/game/jobs/job/logistics/cargo/chief_req.dm index ffdb04da3421..3b6fb7262a80 100644 --- a/code/game/jobs/job/logistics/cargo/chief_req.dm +++ b/code/game/jobs/job/logistics/cargo/chief_req.dm @@ -1,9 +1,8 @@ -//Requisitions Officer /datum/job/logistics/requisition title = JOB_CHIEF_REQUISITION - selection_class = "job_ro" + selection_class = "job_qm" flags_startup_parameters = ROLE_ADD_TO_DEFAULT - gear_preset = /datum/equipment_preset/uscm_ship/ro + gear_preset = /datum/equipment_preset/uscm_ship/qm entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Your cargo techs can help you out, but you have final say in your department. Make sure they're not goofing off. While you may request paperwork for supplies, do not go out of your way to screw with marines, unless you want to get deposed. A happy ship is a well-functioning ship." AddTimelock(/datum/job/logistics/requisition, list( diff --git a/code/game/jobs/job/logistics/logistics.dm b/code/game/jobs/job/logistics/logistics.dm index 6c0a2d0447e1..ef4364354067 100644 --- a/code/game/jobs/job/logistics/logistics.dm +++ b/code/game/jobs/job/logistics/logistics.dm @@ -1,5 +1,5 @@ /datum/job/logistics - supervisors = "the acting commanding officer" + supervisors = "the auxiliary support officer" total_positions = 1 spawn_positions = 1 diff --git a/code/game/jobs/job/marine/marine.dm b/code/game/jobs/job/marine/marine.dm index a64701b8bfc7..e07c1edd3138 100644 --- a/code/game/jobs/job/marine/marine.dm +++ b/code/game/jobs/job/marine/marine.dm @@ -5,15 +5,15 @@ spawn_positions = 8 allow_additional = 1 -/datum/job/marine/generate_entry_message(mob/living/carbon/human/H) - if(H.assigned_squad) - entry_message_intro = "You are a [title]!
You have been assigned to: [lowertext(H.assigned_squad.name)] squad.[Check_WO() ? "" : " Make your way to the cafeteria for some post-cryosleep chow, and then get equipped in your squad's prep room." ]" +/datum/job/marine/generate_entry_message(mob/living/carbon/human/current_human) + if(current_human.assigned_squad) + entry_message_intro = "You are a [title]!
You have been assigned to: [lowertext(current_human.assigned_squad.name)] squad.[Check_WO() ? "" : " Make your way to the cafeteria for some post-cryosleep chow, and then get equipped in your squad's prep room." ]" return ..() -/datum/job/marine/generate_entry_conditions(mob/living/carbon/human/H) +/datum/job/marine/generate_entry_conditions(mob/living/carbon/human/current_human) ..() if(!Check_WO()) - H.nutrition = rand(NUTRITION_VERYLOW, NUTRITION_LOW) //Start hungry for the default marine. + current_human.nutrition = rand(NUTRITION_VERYLOW, NUTRITION_LOW) //Start hungry for the default marine. /datum/timelock/squad name = "Squad Roles" diff --git a/code/game/jobs/job/marine/squad/rto.dm b/code/game/jobs/job/marine/squad/rto.dm deleted file mode 100644 index d7d55ec5cde6..000000000000 --- a/code/game/jobs/job/marine/squad/rto.dm +++ /dev/null @@ -1,37 +0,0 @@ -/datum/job/marine/rto - title = JOB_SQUAD_RTO - total_positions = 8 - spawn_positions = 8 - allow_additional = 1 - flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD - gear_preset = /datum/equipment_preset/uscm/rto - entry_message_body = "You are the Radio Telephone Operator.Your task is to work as a forward observer for overwatch, dropship pilots and mortar operators to provide fire support, and facilitate communications between groundside marines and shipside departments such as CIC and Requisitions." - -/datum/job/marine/rto/generate_entry_conditions(mob/living/carbon/human/H) - . = ..() - H.important_radio_channels += JTAC_FREQ - -AddTimelock(/datum/job/marine/rto, list( - JOB_SQUAD_ROLES = 8 HOURS -)) - -/obj/effect/landmark/start/marine/rto - name = JOB_SQUAD_RTO - icon_state = "rto_spawn" - job = /datum/job/marine/rto - -/obj/effect/landmark/start/marine/rto/alpha - icon_state = "rto_spawn_alpha" - squad = SQUAD_MARINE_1 - -/obj/effect/landmark/start/marine/rto/bravo - icon_state = "rto_spawn_bravo" - squad = SQUAD_MARINE_2 - -/obj/effect/landmark/start/marine/rto/charlie - icon_state = "rto_spawn_charlie" - squad = SQUAD_MARINE_3 - -/obj/effect/landmark/start/marine/rto/delta - icon_state = "rto_spawn_delta" - squad = SQUAD_MARINE_4 diff --git a/code/game/jobs/job/marine/squad/tl.dm b/code/game/jobs/job/marine/squad/tl.dm new file mode 100644 index 000000000000..f6c58cce3e0d --- /dev/null +++ b/code/game/jobs/job/marine/squad/tl.dm @@ -0,0 +1,37 @@ +/datum/job/marine/tl + title = JOB_SQUAD_TEAM_LEADER + total_positions = 8 + spawn_positions = 8 + allow_additional = 1 + flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD + gear_preset = /datum/equipment_preset/uscm/tl + entry_message_body = "You are the Team Leader.Your task is to assist the squad leader in leading the squad as well as utilize ordnance such as orbital bombardments, CAS, and mortar as well as coordinating resupply with Requisitions and CIC. If the squad leader dies, you are expected to lead in their place." + +/datum/job/marine/tl/generate_entry_conditions(mob/living/carbon/human/spawning_human) + . = ..() + spawning_human.important_radio_channels += JTAC_FREQ + +AddTimelock(/datum/job/marine/tl, list( + JOB_SQUAD_ROLES = 8 HOURS +)) + +/obj/effect/landmark/start/marine/tl + name = JOB_SQUAD_TEAM_LEADER + icon_state = "tl_spawn" + job = /datum/job/marine/tl + +/obj/effect/landmark/start/marine/tl/alpha + icon_state = "tl_spawn_alpha" + squad = SQUAD_MARINE_1 + +/obj/effect/landmark/start/marine/tl/bravo + icon_state = "tl_spawn_bravo" + squad = SQUAD_MARINE_2 + +/obj/effect/landmark/start/marine/tl/charlie + icon_state = "tl_spawn_charlie" + squad = SQUAD_MARINE_3 + +/obj/effect/landmark/start/marine/tl/delta + icon_state = "tl_spawn_delta" + squad = SQUAD_MARINE_4 diff --git a/code/game/jobs/job/marine/squad_info.dm b/code/game/jobs/job/marine/squad_info.dm index 325aff5f4922..7e7dfcc0229a 100644 --- a/code/game/jobs/job/marine/squad_info.dm +++ b/code/game/jobs/job/marine/squad_info.dm @@ -17,7 +17,7 @@ update_squad_leader() var/list/data = squad_info_data.Copy() data["squad"] = name - data["squad_color"] = squad_colors[color] + data["squad_color"] = equipment_color data["is_lead"] = get_leadership(user) data["objective"] = list( "primary" = primary_objective, @@ -169,8 +169,8 @@ rank = "SG" if(JOB_SQUAD_SPECIALIST) rank = "Spc" - if(JOB_SQUAD_RTO) - rank = "RTO" + if(JOB_SQUAD_TEAM_LEADER) + rank = "TL" if(JOB_SQUAD_LEADER) rank = "SL" else @@ -246,8 +246,8 @@ rank = "SG" if(JOB_SQUAD_SPECIALIST) rank = "Spc" - if(JOB_SQUAD_RTO) - rank = "RTO" + if(JOB_SQUAD_TEAM_LEADER) + rank = "TL" if(JOB_SQUAD_LEADER) rank = "SL" else @@ -293,8 +293,8 @@ rank = "SG" if(JOB_SQUAD_SPECIALIST) rank = "Spc" - if(JOB_SQUAD_RTO) - rank = "RTO" + if(JOB_SQUAD_TEAM_LEADER) + rank = "TL" if(JOB_SQUAD_LEADER) rank = "SL" else diff --git a/code/game/jobs/job/marine/squads.dm b/code/game/jobs/job/marine/squads.dm index bbd0d36c7e94..10cfc7ca8513 100644 --- a/code/game/jobs/job/marine/squads.dm +++ b/code/game/jobs/job/marine/squads.dm @@ -25,29 +25,51 @@ sub_leader = "Strike Leader" /datum/squad - var/name //Name of the squad + /// Name of the squad + var/name + /// Squads ID that is set on New() var/tracking_id = null //Used for the tracking subsystem - var/max_positions = -1 //Maximum number allowed in a squad. Defaults to infinite - var/color = 0 //Color for helmets, etc. - var/list/access = list() //Which special access do we grant them - var/omni_squad_vendor = FALSE /// Can use any squad vendor regardless of squad connection - var/max_engineers = 3 //maximum # of engineers allowed in squad - var/max_medics = 4 //Ditto, squad medics + /// Maximum number allowed in a squad. Defaults to infinite + var/max_positions = -1 + /// Color for the squad marines gear overlays + var/equipment_color = "#FFFFFF" + /// The alpha for the armor overlay used by equipment color + var/armor_alpha = 125 + /// Color for the squad marines langchat + var/chat_color = "#FFFFFF" + /// Which special access do we grant them + var/list/access = list() + /// Can use any squad vendor regardless of squad connection + var/omni_squad_vendor = FALSE + /// maximum # of engineers allowed in the squad + var/max_engineers = 3 + /// maximum # of squad medics allowed in the squad + var/max_medics = 4 + /// maximum # of specs allowed in the squad var/max_specialists = 1 - var/max_rto = 2 + /// maximum # of fireteam leaders allowed in the suqad + var/max_tl = 2 + /// maximum # of smartgunners allowed in the squad var/max_smartgun = 1 + /// maximum # of squad leaders allowed in the squad var/max_leaders = 1 - var/radio_freq = 1461 //Squad radio headset frequency. - - ///Variables for showing up in various places - var/usable = FALSE //Is it used in-game? - var/roundstart = TRUE /// Whether this squad can be picked at roundstart - var/locked = FALSE //Is it available for squad management? - var/active = FALSE //Is it visible in overwatch? - var/faction = FACTION_MARINE //What faction runs the squad? - - ///Squad Type Specifics + /// Squad headsets default radio frequency + var/radio_freq = 1461 + + /// Whether this squad can be used by marines + var/usable = FALSE + /// Whether this squad can be picked at roundstart + var/roundstart = TRUE + // Whether the squad is available for squad management + var/locked = FALSE + /// Whether it is visible in overwatch + var/active = FALSE + /// Which faction the squad is in + var/faction = FACTION_MARINE + + /// What will the assistant squad leader be called var/squad_type = "Squad" //Referenced for aSL details. Squad/Team/Cell etc. + /// Squad leaders icon var/lead_icon //Referenced for SL's 'L' icon. If nulled, won't override icon for aSLs. //vvv Do not set these in squad defines @@ -69,7 +91,7 @@ var/num_leaders = 0 var/num_smartgun = 0 var/num_specialists = 0 - var/num_rto = 0 + var/num_tl = 0 var/count = 0 //Current # in the squad var/list/marines_list = list() // list of mobs (or name, not always a mob ref) in that squad. @@ -96,35 +118,40 @@ /datum/squad/marine/alpha name = SQUAD_MARINE_1 - color = 1 + equipment_color = "#e61919" + chat_color = "#e67d7d" access = list(ACCESS_MARINE_ALPHA) radio_freq = ALPHA_FREQ minimap_color = MINIMAP_SQUAD_ALPHA /datum/squad/marine/bravo name = SQUAD_MARINE_2 - color = 2 + equipment_color = "#ffc32d" + chat_color = "#ffe650" access = list(ACCESS_MARINE_BRAVO) radio_freq = BRAVO_FREQ minimap_color = MINIMAP_SQUAD_BRAVO /datum/squad/marine/charlie name = SQUAD_MARINE_3 - color = 3 + equipment_color = "#c864c8" + chat_color = "#ff96ff" access = list(ACCESS_MARINE_CHARLIE) radio_freq = CHARLIE_FREQ minimap_color = MINIMAP_SQUAD_CHARLIE /datum/squad/marine/delta name = SQUAD_MARINE_4 - color = 4 + equipment_color = "#4148c8" + chat_color = "#828cff" access = list(ACCESS_MARINE_DELTA) radio_freq = DELTA_FREQ minimap_color = MINIMAP_SQUAD_DELTA /datum/squad/marine/echo name = SQUAD_MARINE_5 - color = 5 + equipment_color = "#67d692" + chat_color = "#67d692" access = list(ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA) radio_freq = ECHO_FREQ omni_squad_vendor = TRUE @@ -136,7 +163,8 @@ /datum/squad/marine/cryo name = SQUAD_MARINE_CRYO - color = 6 + equipment_color = "#c47a50" + chat_color = "#c47a50" access = list(ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA) minimap_color = MINIMAP_SQUAD_FOXTROT @@ -149,7 +177,8 @@ /datum/squad/marine/sof name = SQUAD_SOF - color = 7 + equipment_color = "#400000" + chat_color = "#400000" radio_freq = SOF_FREQ squad_type = "Team" lead_icon = "soctl" @@ -168,23 +197,28 @@ /datum/squad/upp/one name = "UPPS1" - color = 1 + equipment_color = "#e61919" + chat_color = "#e67d7d" /datum/squad/upp/twp name = "UPPS2" - color = 2 + equipment_color = "#ffc32d" + chat_color = "#ffe650" /datum/squad/upp/three name = "UPPS3" - color = 3 + equipment_color = "#c864c8" + chat_color = "#ff96ff" /datum/squad/upp/four name = "UPPS4" - color = 4 + equipment_color = "#4148c8" + chat_color = "#828cff" /datum/squad/upp/kdo name = "UPPKdo" - color = 6 + equipment_color = "#c47a50" + chat_color = "#c47a50" squad_type = "Team" locked = TRUE //############################### @@ -197,11 +231,13 @@ /datum/squad/pmc/one name = "Team Upsilon" - color = 3 + equipment_color = "#c864c8" + chat_color = "#ff96ff" /datum/squad/pmc/two name = "Team Gamma" - color = 6 + equipment_color = "#c47a50" + chat_color = "#c47a50" /datum/squad/pmc/wo name = "Taskforce White" @@ -280,6 +316,7 @@ return TRUE /// Clear references in squad listing upon deletion. Zap also erases the kept records. +/// NOTE: zap will be set true for a forced COMSIG_PARENT_QDELETING /datum/squad/proc/personnel_deleted(mob/M, zap = FALSE) SIGNAL_HANDLER if(M == overwatch_officer) @@ -330,7 +367,7 @@ /// Displays a message to squad members directly on the game map /datum/squad/proc/send_maptext(text = "", title_text = "", only_leader = 0) - var/message_colour = squad_colors_chat[color] + var/message_colour = chat_color if(only_leader) if(squad_leader) var/mob/living/carbon/human/SL = squad_leader @@ -354,14 +391,14 @@ if(!SL.stat && SL.client) if(plus_name) SL << sound('sound/effects/tech_notification.ogg') - to_chat(SL, "[SPAN_BLUE("SL Overwatch: [nametext][text]")]") + to_chat(SL, "[SPAN_BLUE("SL Overwatch: [nametext][text]")]", type = MESSAGE_TYPE_RADIO) return else for(var/mob/living/carbon/human/M in marines_list) if(!M.stat && M.client) //Only living and connected people in our squad if(plus_name) M << sound('sound/effects/tech_notification.ogg') - to_chat(M, "[SPAN_BLUE("Overwatch: [nametext][text]")]") + to_chat(M, "[SPAN_BLUE("Overwatch: [nametext][text]")]", type = MESSAGE_TYPE_RADIO) @@ -404,9 +441,9 @@ if(JOB_SQUAD_SPECIALIST) assignment = JOB_SQUAD_SPECIALIST num_specialists++ - if(JOB_SQUAD_RTO) - assignment = JOB_SQUAD_RTO - num_rto++ + if(JOB_SQUAD_TEAM_LEADER) + assignment = JOB_SQUAD_TEAM_LEADER + num_tl++ M.important_radio_channels += radio_freq if(JOB_SQUAD_SMARTGUN) assignment = JOB_SQUAD_SMARTGUN @@ -533,8 +570,8 @@ num_specialists-- if(JOB_SQUAD_SMARTGUN) num_smartgun-- - if(JOB_SQUAD_RTO) - num_rto-- + if(JOB_SQUAD_TEAM_LEADER) + num_tl-- if(JOB_SQUAD_LEADER) num_leaders-- @@ -553,8 +590,8 @@ old_lead.comm_title = "ComTech" if(JOB_SQUAD_MEDIC) old_lead.comm_title = "HM" - if(JOB_SQUAD_RTO) - old_lead.comm_title = "RTO" + if(JOB_SQUAD_TEAM_LEADER) + old_lead.comm_title = "TL" if(JOB_SQUAD_SMARTGUN) old_lead.comm_title = "SG" if(JOB_SQUAD_LEADER) diff --git a/code/game/jobs/role_authority.dm b/code/game/jobs/role_authority.dm index 6b6e335c084a..5de36963ad39 100644 --- a/code/game/jobs/role_authority.dm +++ b/code/game/jobs/role_authority.dm @@ -23,7 +23,7 @@ var/global/datum/authority/branch/role/RoleAuthority #define MED_PRIORITY 2 #define LOW_PRIORITY 3 -#define SHIPSIDE_ROLE_WEIGHT 0.5 +#define SHIPSIDE_ROLE_WEIGHT 0.25 var/global/players_preassigned = 0 @@ -470,9 +470,9 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou else to_chat(user, "There are no [J.title] slots occupied in [sq.name] Squad.") return - if(JOB_SQUAD_RTO) - if(sq.num_rto > 0) - sq.num_rto-- + if(JOB_SQUAD_TEAM_LEADER) + if(sq.num_tl > 0) + sq.num_tl-- else to_chat(user, "There are no [J.title] slots occupied in [sq.name] Squad.") return @@ -553,6 +553,8 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou var/turf/late_join_turf if(GLOB.latejoin_by_squad[assigned_squad]) late_join_turf = get_turf(pick(GLOB.latejoin_by_squad[assigned_squad])) + else if(GLOB.latejoin_by_job[J.title]) + late_join_turf = get_turf(pick(GLOB.latejoin_by_job[J.title])) else late_join_turf = get_turf(pick(GLOB.latejoin)) H.forceMove(late_join_turf) @@ -720,17 +722,17 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou else if(S.num_specialists < lowest.num_specialists) lowest = S - if(JOB_SQUAD_RTO) + if(JOB_SQUAD_TEAM_LEADER) for(var/datum/squad/S in mixed_squads) if(S.usable && S.roundstart) - if(!skip_limit && S.num_rto >= S.max_rto) continue + if(!skip_limit && S.num_tl >= S.max_tl) continue if(pref_squad_name && S.name == pref_squad_name) S.put_marine_in_squad(H) //fav squad has a spot for us. return if(!lowest) lowest = S - else if(S.num_rto < lowest.num_rto) + else if(S.num_tl < lowest.num_tl) lowest = S if(JOB_SQUAD_SMARTGUN) @@ -768,6 +770,8 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou M = /mob/living/carbon/xenomorph/larva/predalien if(XENO_CASTE_FACEHUGGER) M = /mob/living/carbon/xenomorph/facehugger + if(XENO_CASTE_LESSER_DRONE) + M = /mob/living/carbon/xenomorph/lesser_drone if(XENO_CASTE_RUNNER) M = /mob/living/carbon/xenomorph/runner if(XENO_CASTE_DRONE) @@ -862,7 +866,7 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou if(JOB_SQUAD_SMARTGUN) if(new_squad.num_smartgun >= new_squad.max_smartgun) return TRUE - if(JOB_SQUAD_RTO) - if(new_squad.num_rto >= new_squad.max_rto) + if(JOB_SQUAD_TEAM_LEADER) + if(new_squad.num_tl >= new_squad.max_tl) return TRUE return FALSE diff --git a/code/game/jobs/slot_scaling.dm b/code/game/jobs/slot_scaling.dm index 7e6b0140531b..7230f57eb745 100644 --- a/code/game/jobs/slot_scaling.dm +++ b/code/game/jobs/slot_scaling.dm @@ -47,3 +47,6 @@ /proc/synth_slot_formula(playercount) return job_slot_formula(playercount,120,1,1,2) + +/proc/working_joe_slot_formula(playercount) + return job_slot_formula(playercount,30,1,3,6) diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm index b221f873b571..05f530348029 100644 --- a/code/game/jobs/whitelist.dm +++ b/code/game/jobs/whitelist.dm @@ -40,4 +40,13 @@ GLOBAL_LIST_FILE_LOAD(alien_whitelist, "config/alienwhitelist.txt") return 1 return 0 +/// returns a list of strings containing the whitelists held by a specific ckey +/proc/get_whitelisted_roles(ckey) + if(RoleAuthority.roles_whitelist[ckey] & WHITELIST_PREDATOR) + LAZYADD(., "predator") + if(RoleAuthority.roles_whitelist[ckey] & WHITELIST_COMMANDER) + LAZYADD(., "commander") + if(RoleAuthority.roles_whitelist[ckey] & WHITELIST_SYNTHETIC) + LAZYADD(., "synthetic") + #undef WHITELISTFILE diff --git a/code/game/machinery/ARES/ARES.dm b/code/game/machinery/ARES/ARES.dm new file mode 100644 index 000000000000..de4140ef1b81 --- /dev/null +++ b/code/game/machinery/ARES/ARES.dm @@ -0,0 +1,236 @@ +/obj/structure/machinery/ares + name = "ARES Machinery" + density = TRUE + anchored = TRUE + use_power = USE_POWER_IDLE + idle_power_usage = 600 + icon = 'icons/obj/structures/machinery/ares.dmi' + unslashable = TRUE + unacidable = TRUE + + var/link_id = MAIN_SHIP_DEFAULT_NAME + var/datum/ares_link/link + +/obj/structure/machinery/ares/ex_act(severity) + return + +/obj/structure/machinery/ares/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/structure/machinery/ares/Destroy() + delink() + return ..() + +/obj/structure/machinery/ares/update_icon() + ..() + icon_state = initial(icon_state) + // Broken + if(stat & BROKEN) + icon_state += "_broken" + + // Powered + else if(stat & NOPOWER) + icon_state = initial(icon_state) + icon_state += "_off" + +/// Handles linking and de-linking the ARES systems. +/obj/structure/machinery/ares/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(!new_link) + log_debug("Error: link_systems called without a link datum") + if(link && !override) + return FALSE + if(new_link.link_id == link_id) + link = new_link + log_debug("[name] linked to Ares Link [link_id]") + new_link.linked_systems += src + return TRUE + +/obj/structure/machinery/ares/proc/delink() + log_debug("[name] delinked from Ares Link [link.link_id]") + link.linked_systems -= src + link = null + +/obj/structure/machinery/ares/processor + name = "ARES Processor" + desc = "An external processor for ARES, used to process vast amounts of information." + icon_state = "processor" + +/obj/structure/machinery/ares/processor/apollo + name = "ARES Processor (APOLLO)" + desc = "The external component of ARES' APOLLO processor. Primarily responsible for coordinating Working Joes and Maintenance Drones. It definitely wasn't stolen from Seegson." + icon_state = "apollo_processor" + +/obj/structure/machinery/ares/processor/apollo/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + ..() + new_link.p_apollo = src + +/obj/structure/machinery/ares/processor/apollo/delink() + if(link && link.p_apollo == src) + link.p_apollo = null + ..() + +/obj/structure/machinery/ares/processor/interface + name = "ARES Processor (Interface)" + desc = "An external processor for ARES; this one handles core processes for interfacing with the crew, including radio transmissions and broadcasts." + icon_state = "int_processor" + +/obj/structure/machinery/ares/processor/interface/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + ..() + new_link.p_interface = src + +/obj/structure/machinery/ares/processor/interface/delink() + if(link && link.p_interface == src) + link.p_interface = null + ..() + +/obj/structure/machinery/ares/processor/bioscan + name = "ARES Processor (Bioscan)" + desc = "The external component of ARES' Bioscan systems. Without this, the USS Almayer would be incapable of running bioscans!" + icon_state = "bio_processor" + +/obj/structure/machinery/ares/processor/bioscan/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + ..() + new_link.p_bioscan = src + +/obj/structure/machinery/ares/processor/bioscan/delink() + if(link && link.p_bioscan == src) + link.p_bioscan = null + ..() + +/// Central Core +/obj/structure/machinery/ares/cpu + name = "ARES CPU" + desc = "This is ARES' central processor. Made of a casing designed to withstand nuclear blasts, the CPU also contains ARES' blackbox recorder." + icon_state = "CPU" + +/// Memory Substrate, +/obj/structure/machinery/ares/substrate + name = "ARES Substrate" + desc = "The memory substrate of ARES, containing complex protocols and information. Limited capabilities can operate on substrate alone, without the main ARES Unit operational." + icon_state = "substrate" + +// #################### ARES Interface Console ##################### +/obj/structure/machinery/computer/ares_console + name = "ARES Interface" + desc = "A console built to interface with ARES, allowing for 1:1 communication." + icon = 'icons/obj/structures/machinery/ares.dmi' + icon_state = "console" + exproof = TRUE + + var/current_menu = "login" + var/last_menu = "" + + var/authentication = ARES_ACCESS_BASIC + + /// The last person to login. + var/last_login + /// The person pretending to be last_login + var/sudo_holder + /// A record of who logged in and when. + var/list/access_list = list() + + /// The ID used to link all devices. + var/link_id = MAIN_SHIP_DEFAULT_NAME + var/datum/ares_link/link + + /// The current deleted chat log of 1:1 conversations being read. + var/list/deleted_1to1 = list() + + /// Holds all (/datum/ares_record/announcement)s + var/list/records_announcement = list() + /// Holds all (/datum/ares_record/bioscan)s + var/list/records_bioscan = list() + /// Holds all (/datum/ares_record/bombardment)s + var/list/records_bombardment = list() + /// Holds all (/datum/ares_record/deletion)s + var/list/records_deletion = list() + /// Holds all (/datum/ares_record/talk_log)s + var/list/records_talking = list() + /// Holds all (/datum/ares_record/requisition_log)s + var/list/records_asrs = list() + /// Holds all (/datum/ares_record/security)s and (/datum/ares_record/antiair)s + var/list/records_security = list() + /// Is nuke request usable or not? + var/nuke_available = TRUE + + + COOLDOWN_DECLARE(ares_distress_cooldown) + COOLDOWN_DECLARE(ares_nuclear_cooldown) + +/obj/structure/machinery/computer/ares_console/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link.link_id == link_id) + new_link.interface = src + link = new_link + log_debug("[name] linked to Ares Link [link_id]") + new_link.linked_systems += src + return TRUE + +/obj/structure/machinery/computer/ares_console/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/structure/machinery/computer/ares_console/proc/delink() + if(link && link.interface == src) + link.interface = null + link.linked_systems -= src + link = null + +/obj/structure/machinery/computer/ares_console/Destroy() + delink() + return ..() + +// #################### Working Joe Ticket Console ##################### +/obj/structure/machinery/computer/working_joe + name = "APOLLO Maintenance Controller" + desc = "A console built to facilitate Working Joes and their operation, allowing for simple allocation of resources." + icon = 'icons/obj/structures/machinery/ares.dmi' + icon_state = "console" + exproof = TRUE + + /// The ID used to link all devices. + var/link_id = MAIN_SHIP_DEFAULT_NAME + var/datum/ares_link/link + var/obj/structure/machinery/ares/processor/interface/processor + + var/current_menu = "login" + var/last_menu = "" + + var/authentication = ARES_ACCESS_BASIC + /// The last person to login. + var/last_login + /// A record of who logged in and when. + var/list/login_list = list() + + + /// If this is used to create AI Core access tickets + var/ticket_console = FALSE + var/obj/item/card/id/authenticator_id + var/ticket_authenticated = FALSE + var/obj/item/card/id/target_id + +/obj/structure/machinery/computer/working_joe/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link.link_id == link_id) + new_link.ticket_computers += src + link = new_link + log_debug("[name] linked to Ares Link [link_id]") + new_link.linked_systems += src + return TRUE + +/obj/structure/machinery/computer/working_joe/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/structure/machinery/computer/working_joe/proc/delink() + if(link) + link.ticket_computers -= src + link.linked_systems -= src + link = null + +/obj/structure/machinery/computer/working_joe/Destroy() + delink() + return ..() diff --git a/code/game/machinery/ARES/ARES_procs.dm b/code/game/machinery/ARES/ARES_procs.dm new file mode 100644 index 000000000000..a335a36994e5 --- /dev/null +++ b/code/game/machinery/ARES/ARES_procs.dm @@ -0,0 +1,990 @@ +GLOBAL_DATUM_INIT(ares_link, /datum/ares_link, new) +GLOBAL_LIST_INIT(maintenance_categories, list( + "Broken Light", + "Shattered Glass", + "Minor Structural Damage", + "Major Structural Damage", + "Janitorial", + "Chemical Spill", + "Fire", + "Communications Failure", + "Power Generation Failure", + "Electrical Fault", + "Support", + "Other" + )) + +/datum/ares_link + var/link_id = MAIN_SHIP_DEFAULT_NAME + /// All motion triggers for the link + var/list/linked_alerts = list() + /// All machinery for the link + var/list/linked_systems = list() + var/obj/structure/machinery/ares/processor/interface/p_interface + var/obj/structure/machinery/ares/processor/apollo/p_apollo + var/obj/structure/machinery/ares/processor/bioscan/p_bioscan + var/obj/structure/machinery/computer/ares_console/interface + var/list/obj/structure/machinery/computer/working_joe/ticket_computers = list() + + /// The chat log of the apollo link. Timestamped. + var/list/apollo_log = list() + + /// Working Joe stuff + var/list/tickets_maintenance = list() + var/list/tickets_access = list() + +/datum/ares_link/Destroy() + for(var/obj/structure/machinery/ares/link in linked_systems) + link.delink() + for(var/obj/structure/machinery/computer/ares_console/interface in linked_systems) + interface.delink() + for(var/obj/effect/step_trigger/ares_alert/alert in linked_alerts) + alert.delink() + ..() + + +// ------ ARES Logging Procs ------ // +/proc/log_ares_apollo(speaker, message) + if(!speaker) + speaker = "Unknown" + var/datum/ares_link/link = GLOB.ares_link + if(!link.p_apollo || link.p_apollo.inoperable()) + return FALSE + if(!link.p_interface || link.p_interface.inoperable()) + return FALSE + link.apollo_log.Add("[worldtime2text()]: [speaker], '[message]'") + +/datum/ares_link/proc/log_ares_bioscan(title, input) + interface.records_bioscan.Add(new /datum/ares_record/bioscan(title, input)) + +/datum/ares_link/proc/log_ares_bombardment(mob/living/user, ob_name, coordinates) + interface.records_bombardment.Add(new /datum/ares_record/bombardment(ob_name, "Bombardment fired at [coordinates].", user)) + +/datum/ares_link/proc/log_ares_announcement(title, message) + interface.records_announcement.Add(new /datum/ares_record/announcement(title, message)) + +/datum/ares_link/proc/log_ares_antiair(mob/living/user, details) + interface.records_security.Add(new /datum/ares_record/antiair(details, user)) + +/datum/ares_link/proc/log_ares_requisition(source, details, mob/living/user) + interface.records_asrs.Add(new /datum/ares_record/requisition_log(source, details, user)) + +/datum/ares_link/proc/log_ares_security(title, details) + interface.records_security.Add(new /datum/ares_record/security(title, details)) +// ------ End ARES Logging Procs ------ // + +/proc/ares_apollo_talk(broadcast_message) + var/datum/language/apollo/apollo = GLOB.all_languages[LANGUAGE_APOLLO] + for(var/mob/living/silicon/decoy/ship_ai/ai in ai_mob_list) + if(ai.stat == DEAD) + return FALSE + apollo.broadcast(ai, broadcast_message) + for(var/mob/listener in (GLOB.human_mob_list + GLOB.dead_mob_list)) + if(listener.hear_apollo())//Only plays sound to mobs and not observers, to reduce spam. + playsound_client(listener.client, sound('sound/misc/interference.ogg'), listener, vol = 45) + +/proc/ares_can_interface() + var/obj/structure/machinery/ares/processor/interface/processor = GLOB.ares_link.p_interface + if(!istype(GLOB.ares_link)) + return FALSE + if(processor && !processor.inoperable()) + return TRUE + return FALSE //interface processor not found or is broken + +/proc/ares_can_log() + var/obj/structure/machinery/computer/ares_console/interface = GLOB.ares_link.interface + if(!istype(GLOB.ares_link)) + return FALSE + if(interface && !interface.inoperable()) + return TRUE + return FALSE //ares interface not found or is broken + +// ------ ARES Interface Procs ------ // +/obj/structure/machinery/computer/proc/get_ares_access(obj/item/card/id/card) + if(ACCESS_ARES_DEBUG in card.access) + return ARES_ACCESS_DEBUG + switch(card.assignment) + if(JOB_WORKING_JOE) + return ARES_ACCESS_JOE + if(JOB_CHIEF_ENGINEER) + return ARES_ACCESS_CE + if(JOB_SYNTH) + return ARES_ACCESS_SYNTH + if(card.paygrade in GLOB.wy_paygrades) + return ARES_ACCESS_WY_COMMAND + if(card.paygrade in GLOB.highcom_paygrades) + return ARES_ACCESS_HIGH + if(card.paygrade in GLOB.co_paygrades) + return ARES_ACCESS_CO + if(ACCESS_MARINE_SENIOR in card.access) + return ARES_ACCESS_SENIOR + if(ACCESS_WY_GENERAL in card.access) + return ARES_ACCESS_CORPORATE + if(ACCESS_MARINE_COMMAND in card.access) + return ARES_ACCESS_COMMAND + else + return ARES_ACCESS_BASIC + +/obj/structure/machinery/computer/proc/ares_auth_to_text(access_level) + switch(access_level) + if(ARES_ACCESS_BASIC)//0 + return "Authorized" + if(ARES_ACCESS_COMMAND)//1 + return "[MAIN_SHIP_NAME] Command" + if(ARES_ACCESS_JOE)//2 + return "Working Joe" + if(ARES_ACCESS_CORPORATE)//3 + return "Weyland-Yutani" + if(ARES_ACCESS_SENIOR)//4 + return "[MAIN_SHIP_NAME] Senior Command" + if(ARES_ACCESS_CE)//5 + return "Chief Engineer" + if(ARES_ACCESS_SYNTH)//6 + return "USCM Synthetic" + if(ARES_ACCESS_CO)//7 + return "[MAIN_SHIP_NAME] Commanding Officer" + if(ARES_ACCESS_HIGH)//8 + return "USCM High Command" + if(ARES_ACCESS_WY_COMMAND)//9 + return "Weyland-Yutani Directorate" + if(ARES_ACCESS_DEBUG)//10 + return "AI Service Technician" + + +/obj/structure/machinery/computer/ares_console/proc/message_ares(text, mob/Sender, ref) + var/msg = SPAN_STAFF_IC("ARES: [key_name(Sender, 1)] [ARES_MARK(Sender)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] [ADMIN_JMP_USER(Sender)] [ARES_REPLY(Sender, ref)]: [text]") + var/datum/ares_record/talk_log/conversation = locate(ref) + conversation.conversation += "[last_login] at [worldtime2text()], '[text]'" + for(var/client/admin in GLOB.admins) + if((R_ADMIN|R_MOD) & admin.admin_holder.rights) + to_chat(admin, msg) + if(admin.prefs.toggles_sound & SOUND_ARES_MESSAGE) + playsound_client(admin, 'sound/machines/chime.ogg', vol = 25) + log_say("[key_name(Sender)] sent '[text]' to ARES 1:1.") + +/obj/structure/machinery/computer/ares_console/proc/response_from_ares(text, ref) + var/datum/ares_record/talk_log/conversation = locate(ref) + conversation.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], '[text]'" +// ------ End ARES Interface Procs ------ // + +// ------ ARES Interface UI ------ // + +/obj/structure/machinery/computer/ares_console/attack_hand(mob/user as mob) + if(..() || !allowed(usr) || inoperable()) + return FALSE + + tgui_interact(user) + return TRUE + +/obj/structure/machinery/computer/ares_console/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AresInterface", name) + ui.open() + +/obj/structure/machinery/computer/ares_console/ui_data(mob/user) + var/list/data = list() + + data["current_menu"] = current_menu + data["last_page"] = last_menu + + data["logged_in"] = last_login + data["sudo"] = sudo_holder ? TRUE : FALSE + + data["access_text"] = "[sudo_holder ? "(SUDO)," : ""] access level [authentication], [ares_auth_to_text(authentication)]." + data["access_level"] = authentication + + data["alert_level"] = security_level + data["evac_status"] = EvacuationAuthority.evac_status + data["worldtime"] = world.time + + data["access_log"] = list() + data["access_log"] += access_list + data["apollo_log"] = list() + data["apollo_log"] += link.apollo_log + + data["deleted_conversation"] = list() + data["deleted_conversation"] += deleted_1to1 + + data["distresstime"] = ares_distress_cooldown + data["distresstimelock"] = DISTRESS_TIME_LOCK + data["mission_failed"] = SSticker.mode.is_in_endgame + data["nuketimelock"] = NUCLEAR_TIME_LOCK + data["nuke_available"] = nuke_available + + var/list/logged_announcements = list() + for(var/datum/ares_record/announcement/broadcast as anything in records_announcement) + var/list/current_broadcast = list() + current_broadcast["time"] = broadcast.time + current_broadcast["title"] = broadcast.title + current_broadcast["details"] = broadcast.details + current_broadcast["ref"] = "\ref[broadcast]" + logged_announcements += list(current_broadcast) + data["records_announcement"] = logged_announcements + + var/list/logged_alerts = list() + for(var/datum/ares_record/security/security_alert as anything in records_security) + if(!istype(security_alert)) + continue + var/list/current_alert = list() + current_alert["time"] = security_alert.time + current_alert["title"] = security_alert.title + current_alert["details"] = security_alert.details + current_alert["ref"] = "\ref[security_alert]" + logged_alerts += list(current_alert) + data["records_security"] = logged_alerts + + var/list/logged_bioscans = list() + for(var/datum/ares_record/bioscan/scan as anything in records_bioscan) + var/list/current_scan = list() + current_scan["time"] = scan.time + current_scan["title"] = scan.title + current_scan["details"] = scan.details + current_scan["ref"] = "\ref[scan]" + logged_bioscans += list(current_scan) + data["records_bioscan"] = logged_bioscans + + var/list/logged_bombs = list() + for(var/datum/ares_record/bombardment/bomb as anything in records_bombardment) + var/list/current_bomb = list() + current_bomb["time"] = bomb.time + current_bomb["title"] = bomb.title + current_bomb["details"] = bomb.details + current_bomb["user"] = bomb.user + current_bomb["ref"] = "\ref[bomb]" + logged_bombs += list(current_bomb) + data["records_bombardment"] = logged_bombs + + var/list/logged_deletes = list() + for(var/datum/ares_record/deletion/deleted as anything in records_deletion) + if(!istype(deleted)) + continue + var/list/current_delete = list() + current_delete["time"] = deleted.time + current_delete["title"] = deleted.title + current_delete["details"] = deleted.details + current_delete["user"] = deleted.user + current_delete["ref"] = "\ref[deleted]" + logged_deletes += list(current_delete) + data["records_deletion"] = logged_deletes + + var/list/logged_discussions = list() + for(var/datum/ares_record/deleted_talk/deleted_convo as anything in records_deletion) + if(!istype(deleted_convo)) + continue + var/list/deleted_disc = list() + deleted_disc["time"] = deleted_convo.time + deleted_disc["title"] = deleted_convo.title + deleted_disc["ref"] = "\ref[deleted_convo]" + logged_discussions += list(deleted_disc) + data["deleted_discussions"] = logged_discussions + + var/list/logged_adjustments = list() + for(var/datum/ares_record/antiair/aa_adjustment as anything in records_security) + if(!istype(aa_adjustment)) + continue + var/list/current_adjustment = list() + current_adjustment["time"] = aa_adjustment.time + current_adjustment["details"] = aa_adjustment.details + current_adjustment["user"] = aa_adjustment.user + current_adjustment["ref"] = "\ref[aa_adjustment]" + logged_adjustments += list(current_adjustment) + data["aa_adjustments"] = logged_adjustments + + var/list/logged_orders = list() + for(var/datum/ares_record/requisition_log/req_order as anything in records_asrs) + if(!istype(req_order)) + continue + var/list/current_order = list() + current_order["time"] = req_order.time + current_order["details"] = req_order.details + current_order["title"] = req_order.title + current_order["user"] = req_order.user + current_order["ref"] = "\ref[req_order]" + logged_orders += list(current_order) + data["records_requisition"] = logged_orders + + var/list/logged_convos = list() + var/list/active_convo = list() + var/active_ref + for(var/datum/ares_record/talk_log/log as anything in records_talking) + if(!istype(log)) + continue + if(log.user == last_login) + active_convo = log.conversation + active_ref = "\ref[log]" + + var/list/current_convo = list() + current_convo["user"] = log.user + current_convo["ref"] = "\ref[log]" + current_convo["conversation"] = log.conversation + logged_convos += list(current_convo) + + data["active_convo"] = active_convo + data["active_ref"] = active_ref + data["conversations"] = logged_convos + + return data + +/obj/structure/machinery/computer/ares_console/ui_static_data(mob/user) + var/list/data = list() + + data["link_id"] = link_id + + return data + +/obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(!allowed(user)) + return UI_UPDATE + if(inoperable()) + return UI_DISABLED + +/obj/structure/machinery/computer/ares_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + playsound(src, "keyboard_alt", 15, 1) + + switch (action) + if("go_back") + if(!last_menu) + return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) + var/temp_holder = current_menu + current_menu = last_menu + last_menu = temp_holder + + if("login") + var/mob/living/carbon/human/operator = usr + var/obj/item/card/id/idcard = operator.get_active_hand() + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else + to_chat(usr, SPAN_WARNING("You require an ID card to access this terminal!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(authentication) + access_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." + current_menu = "main" + + if("sudo") + var/new_user = tgui_input_text(usr, "Enter Sudo Username", "Sudo User", encode = FALSE) + if(new_user) + if(new_user == sudo_holder) + last_login = sudo_holder + sudo_holder = null + return FALSE + if(new_user == last_login) + to_chat(usr, SPAN_WARNING("Already remote logged in as this user.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + sudo_holder = last_login + last_login = new_user + access_list += "[last_login] at [worldtime2text()], Sudo Access." + return TRUE + if("sudo_logout") + access_list += "[last_login] at [worldtime2text()], Sudo Logout." + last_login = sudo_holder + sudo_holder = null + return + // -- Page Changers -- // + if("logout") + last_menu = current_menu + current_menu = "login" + if(sudo_holder) + access_list += "[last_login] at [worldtime2text()], Sudo Logout." + last_login = sudo_holder + sudo_holder = null + access_list += "[last_login] logged out at [worldtime2text()]." + + if("home") + last_menu = current_menu + current_menu = "main" + if("page_1to1") + last_menu = current_menu + current_menu = "talking" + if("page_announcements") + last_menu = current_menu + current_menu = "announcements" + if("page_bioscans") + last_menu = current_menu + current_menu = "bioscans" + if("page_bombardments") + last_menu = current_menu + current_menu = "bombardments" + if("page_apollo") + last_menu = current_menu + current_menu = "apollo" + if("page_access") + last_menu = current_menu + current_menu = "access_log" + if("page_security") + last_menu = current_menu + current_menu = "security" + if("page_requisitions") + last_menu = current_menu + current_menu = "requisitions" + if("page_antiair") + last_menu = current_menu + current_menu = "antiair" + if("page_emergency") + last_menu = current_menu + current_menu = "emergency" + if("page_deleted") + last_menu = current_menu + current_menu = "delete_log" + if("page_deleted_1to1") + last_menu = current_menu + current_menu = "deleted_talks" + + // -- Delete Button -- // + if("delete_record") + var/datum/ares_record/record = locate(params["record"]) + if(record.record_name == ARES_RECORD_DELETED) + return FALSE + var/datum/ares_record/deletion/new_delete = new + var/new_details = "Error" + var/new_title = "Error" + switch(record.record_name) + if(ARES_RECORD_ANNOUNCE) + new_title = "[record.title] at [record.time]" + new_details = record.details + records_announcement -= record + if(ARES_RECORD_SECURITY) + new_title = "[record.title] at [record.time]" + new_details = record.details + records_security -= record + if(ARES_RECORD_BIOSCAN) + new_title = "[record.title] at [record.time]" + new_details = record.details + records_bioscan -= record + if(ARES_RECORD_BOMB) + new_title = "[record.title] at [record.time]" + new_details = "[record.details] Launched by [record.user]." + records_bombardment -= record + + new_delete.details = new_details + new_delete.user = last_login + new_delete.title = new_title + + records_deletion += new_delete + + // -- 1:1 Conversation -- // + if("new_conversation") + var/datum/ares_record/talk_log/convo = new(last_login) + convo.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], 'New 1:1 link initiated. Greetings, [last_login].'" + records_talking += convo + + if("clear_conversation") + var/datum/ares_record/talk_log/conversation = locate(params["active_convo"]) + if(!istype(conversation)) + return FALSE + var/datum/ares_record/deleted_talk/deleted = new + deleted.title = conversation.title + deleted.conversation = conversation.conversation + deleted.user = conversation.user + records_deletion += deleted + records_talking -= conversation + + if("message_ares") + var/message = tgui_input_text(usr, "What do you wish to say to ARES?", "ARES Message", encode = FALSE) + if(message) + message_ares(message, usr, params["active_convo"]) + + if("read_record") + var/datum/ares_record/deleted_talk/conversation = locate(params["record"]) + deleted_1to1 = conversation.conversation + last_menu = current_menu + current_menu = "read_deleted" + + // -- Emergency Buttons -- // + if("general_quarters") + if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA) + to_chat(usr, SPAN_WARNING("Alert level is already red or above, General Quarters cannot be called.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + set_security_level(2, no_sound = TRUE, announce = FALSE) + shipwide_ai_announcement("ATTENTION! GENERAL QUARTERS. ALL HANDS, MAN YOUR BATTLESTATIONS.", MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg') + log_game("[key_name(usr)] has called for general quarters via ARES.") + message_admins("[key_name_admin(usr)] has called for general quarters via ARES.") + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_security("General Quarters", "[last_login] has called for general quarters via ARES.") + . = TRUE + + if("evacuation_start") + if(security_level < SEC_LEVEL_RED) + to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + if(!EvacuationAuthority.initiate_evacuation()) + to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + log_game("[key_name(usr)] has called for an emergency evacuation via ARES.") + message_admins("[key_name_admin(usr)] has called for an emergency evacuation via ARES.") + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_security("Initiate Evacuation", "[last_login] has called for an emergency evacuation via ARES.") + . = TRUE + + if("distress") + if(!SSticker.mode) + return FALSE //Not a game mode? + if(world.time < DISTRESS_TIME_LOCK) + to_chat(usr, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(!COOLDOWN_FINISHED(src, ares_distress_cooldown)) + to_chat(usr, SPAN_WARNING("The distress launcher is cooling down!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(security_level == SEC_LEVEL_DELTA) + to_chat(usr, SPAN_WARNING("The ship is already undergoing self destruct procedures!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + else if(security_level < SEC_LEVEL_RED) + to_chat(usr, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + for(var/client/admin in GLOB.admins) + if((R_ADMIN|R_MOD) & admin.admin_holder.rights) + playsound_client(admin,'sound/effects/sos-morse-code.ogg',10) + message_admins("[key_name(usr)] has requested a Distress Beacon (via ARES)! [CC_MARK(usr)] (SEND) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") + to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command.")) + COOLDOWN_START(src, ares_distress_cooldown, COOLDOWN_COMM_REQUEST) + return TRUE + + if("nuclearbomb") + if(!SSticker.mode) + return FALSE //Not a game mode? + if(world.time < NUCLEAR_TIME_LOCK) + to_chat(usr, SPAN_WARNING("It is too soon to request Nuclear Ordnance!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(!COOLDOWN_FINISHED(src, ares_nuclear_cooldown)) + to_chat(usr, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(security_level == SEC_LEVEL_DELTA || SSticker.mode.is_in_endgame) + to_chat(usr, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + var/reason = tgui_input_text(usr, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance") + if(!reason) + return FALSE + for(var/client/admin in GLOB.admins) + if((R_ADMIN|R_MOD) & admin.admin_holder.rights) + playsound_client(admin,'sound/effects/sos-morse-code.ogg',10) + message_admins("[key_name(usr)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(usr)] (APPROVE) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") + to_chat(usr, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]")) + if(ares_can_log()) + link.log_ares_security("Nuclear Ordnance Request", "[last_login] has sent a request for nuclear ordnance for the following reason: [reason]") + if(ares_can_interface()) + ai_silent_announcement("[last_login] has sent a request for nuclear ordnance to USCM High Command.", ".V") + ai_silent_announcement("Reason given: [reason].", ".V") + COOLDOWN_START(src, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT) + return TRUE +// ------ End ARES Interface UI ------ // + + +/obj/structure/machinery/computer/working_joe/get_ares_access(obj/item/card/id/card) + if(ACCESS_ARES_DEBUG in card.access) + return APOLLO_ACCESS_DEBUG + switch(card.assignment) + if(JOB_WORKING_JOE) + return APOLLO_ACCESS_JOE + if(JOB_CHIEF_ENGINEER, JOB_SYNTH, JOB_CO) + return APOLLO_ACCESS_AUTHED + if(ACCESS_MARINE_AI in card.access) + return APOLLO_ACCESS_AUTHED + if(ACCESS_MARINE_AI_TEMP in card.access) + return APOLLO_ACCESS_TEMP + if((ACCESS_MARINE_SENIOR in card.access ) || (ACCESS_MARINE_ENGINEERING in card.access) || (ACCESS_WY_GENERAL in card.access)) + return APOLLO_ACCESS_REPORTER + else + return APOLLO_ACCESS_REQUEST + +/obj/structure/machinery/computer/working_joe/ares_auth_to_text(access_level) + switch(access_level) + if(APOLLO_ACCESS_REQUEST)//0 + return "Unauthorized Personnel" + if(APOLLO_ACCESS_REPORTER)//1 + return "Validated Incident Reporter" + if(APOLLO_ACCESS_TEMP)//2 + return "Authorized Visitor" + if(APOLLO_ACCESS_AUTHED)//3 + return "Certified Personnel" + if(APOLLO_ACCESS_JOE)//4 + return "Working Joe" + if(APOLLO_ACCESS_DEBUG)//5 + return "AI Service Technician" + +// ------ Maintenance Controller UI ------ // +/obj/structure/machinery/computer/working_joe/verb/eject_id() + set category = "Object" + set name = "Eject ID Card" + set src in oview(1) + + if(!usr || usr.stat || usr.lying) + return FALSE + + if(authenticator_id) + authenticator_id.loc = get_turf(src) + if(!usr.get_active_hand() && istype(usr,/mob/living/carbon/human)) + usr.put_in_hands(authenticator_id) + if(operable()) // Powered. Console can response. + visible_message("[SPAN_BOLD("[src]")] states, \"AUTH LOGOUT: Session end confirmed.\"") + else + to_chat(usr, "You remove [authenticator_id] from [src].") + ticket_authenticated = FALSE // No card - no access + authenticator_id = null + + else if(target_id) + target_id.loc = get_turf(src) + if(!usr.get_active_hand() && istype(usr,/mob/living/carbon/human)) + usr.put_in_hands(target_id) + else + to_chat(usr, "You remove [target_id] from [src].") + target_id = null + + else + to_chat(usr, "There is nothing to remove from the console.") + return + +/obj/structure/machinery/computer/working_joe/attackby(obj/object, mob/user) + if(istype(object, /obj/item/card/id)) + if(!ticket_console) + to_chat(user, SPAN_WARNING("This console doesn't have an ID port!")) + return FALSE + if(!operable()) + to_chat(user, SPAN_NOTICE("You try to insert [object] but [src] remains silent.")) + return FALSE + var/obj/item/card/id/idcard = object + if((idcard.assignment == JOB_WORKING_JOE) || (ACCESS_ARES_DEBUG in idcard.access)) + if(!authenticator_id) + if(user.drop_held_item()) + object.forceMove(src) + authenticator_id = object + authenticate(authenticator_id) + else if(!target_id) + if(user.drop_held_item()) + object.forceMove(src) + target_id = object + else + to_chat(user, "Both slots are full already. Remove a card first.") + return FALSE + else + if(!target_id) + if(user.drop_held_item()) + object.forceMove(src) + target_id = object + else + to_chat(user, "Both slots are full already. Remove a card first.") + return FALSE + else + ..() + +/obj/structure/machinery/computer/working_joe/proc/authenticate(obj/item/card/id/id_card) + if(!id_card) + visible_message("[SPAN_BOLD("[src]")] states, \"AUTH ERROR: Authenticator card is missing!\"") + return FALSE + + if((ACCESS_MARINE_AI in id_card.access) || (ACCESS_ARES_DEBUG in id_card.access)) + ticket_authenticated = TRUE + visible_message("[SPAN_BOLD("[src]")] states, \"AUTH LOGIN: Welcome, [id_card.registered_name]. Access granted.\"") + return TRUE + + visible_message("[SPAN_BOLD("[src]")] states, \"AUTH ERROR: Access denied.\"") + return FALSE + + + + +/obj/structure/machinery/computer/working_joe/attack_hand(mob/user as mob) + if(..() || !allowed(usr) || inoperable()) + return FALSE + + tgui_interact(user) + return TRUE + +/obj/structure/machinery/computer/working_joe/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "WorkingJoe", name) + ui.open() + +/obj/structure/machinery/computer/working_joe/ui_data(mob/user) + var/list/data = list() + + data["ticket_console"] = ticket_console + data["current_menu"] = current_menu + data["last_page"] = last_menu + + data["logged_in"] = last_login + + data["access_text"] = "access level [authentication], [ares_auth_to_text(authentication)]." + data["access_level"] = authentication + + data["alert_level"] = security_level + data["worldtime"] = world.time + + data["access_log"] = list() + data["access_log"] += login_list + + data["apollo_log"] = list() + data["apollo_log"] += link.apollo_log + + data["authenticated"] = ticket_authenticated + + + var/list/logged_maintenance = list() + for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance) + if(!istype(maint_ticket)) + continue + var/lock_status = TICKET_OPEN + switch(maint_ticket.ticket_status) + if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED) + lock_status = TICKET_CLOSED + + var/list/current_maint = list() + current_maint["id"] = maint_ticket.ticket_id + current_maint["time"] = maint_ticket.ticket_time + current_maint["priority_status"] = maint_ticket.ticket_priority + current_maint["category"] = maint_ticket.ticket_name + current_maint["details"] = maint_ticket.ticket_details + current_maint["status"] = maint_ticket.ticket_status + current_maint["submitter"] = maint_ticket.ticket_submitter + current_maint["assignee"] = maint_ticket.ticket_assignee + current_maint["lock_status"] = lock_status + current_maint["ref"] = "\ref[maint_ticket]" + logged_maintenance += list(current_maint) + data["maintenance_tickets"] = logged_maintenance + + var/list/logged_access = list() + for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access) + var/lock_status = TICKET_OPEN + switch(access_ticket.ticket_status) + if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED) + lock_status = TICKET_CLOSED + + var/list/current_ticket = list() + current_ticket["id"] = access_ticket.ticket_id + current_ticket["time"] = access_ticket.ticket_time + current_ticket["priority_status"] = access_ticket.ticket_priority + current_ticket["title"] = access_ticket.ticket_name + current_ticket["details"] = access_ticket.ticket_details + current_ticket["status"] = access_ticket.ticket_status + current_ticket["submitter"] = access_ticket.ticket_submitter + current_ticket["assignee"] = access_ticket.ticket_assignee + current_ticket["lock_status"] = lock_status + current_ticket["ref"] = "\ref[access_ticket]" + logged_access += list(current_ticket) + data["access_tickets"] = logged_access + + + return data + +/obj/structure/machinery/computer/working_joe/ui_static_data(mob/user) + var/list/data = list() + + data["link_id"] = link_id + + return data + +/obj/structure/machinery/computer/working_joe/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(!allowed(user)) + return UI_UPDATE + if(inoperable()) + return UI_DISABLED + +/obj/structure/machinery/computer/working_joe/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/playsound = TRUE + var/mob/living/carbon/human/operator = usr + + switch (action) + if("go_back") + if(!last_menu) + return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) + var/temp_holder = current_menu + current_menu = last_menu + last_menu = temp_holder + + if("login") + + var/obj/item/card/id/idcard = operator.get_active_hand() + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else + to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(authentication) + login_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." + current_menu = "main" + + if("logout") + last_menu = current_menu + current_menu = "login" + login_list += "[last_login] logged out at [worldtime2text()]." + + if("home") + last_menu = current_menu + current_menu = "main" + if("page_logins") + last_menu = current_menu + current_menu = "login_records" + if("page_apollo") + last_menu = current_menu + current_menu = "apollo" + if("page_request") + last_menu = current_menu + current_menu = "access_requests" + if("page_returns") + last_menu = current_menu + current_menu = "access_returns" + if("page_report") + last_menu = current_menu + current_menu = "maint_reports" + if("page_tickets") + last_menu = current_menu + current_menu = "access_tickets" + if("page_maintenance") + last_menu = current_menu + current_menu = "maint_claim" + + if("new_report") + var/priority_report = FALSE + var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS) + switch(maint_type) + if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure") + priority_report = TRUE + + if(!maint_type) + return FALSE + var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE) + if(!details) + return FALSE + + if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report) + var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No")) + if(is_priority == "Yes") + priority_report = TRUE + + var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"] \n Category: '[maint_type]' \n Details: '[details]' \n\n Is this correct?", "Confirmation", "Yes", "No") + if(confirm == "Yes") + if(link) + var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report) + link.tickets_maintenance += maint_ticket + if(priority_report) + ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.") + log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.") + return TRUE + return FALSE + + if("claim_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + var/claim = TRUE + var/assigned = ticket.ticket_assignee + if(assigned) + if(assigned == last_login) + var/prompt = tgui_alert(usr, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No")) + if(prompt != "Yes") + return FALSE + /// set ticket back to pending + ticket.ticket_assignee = null + ticket.ticket_status = TICKET_PENDING + return claim + var/choice = tgui_alert(usr, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No")) + if(choice != "Yes") + claim = FALSE + if(claim) + ticket.ticket_assignee = last_login + ticket.ticket_status = TICKET_ASSIGNED + return claim + + if("cancel_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + if(ticket.ticket_submitter != last_login) + to_chat(usr, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!")) + return FALSE + to_chat(usr, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled.")) + ticket.ticket_status = TICKET_CANCELLED + if(ticket.ticket_priority) + ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.") + return TRUE + + if("mark_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.) + to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + return FALSE + var/choice = tgui_alert(usr, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS) + switch(choice) + if(TICKET_COMPLETED) + ticket.ticket_status = TICKET_COMPLETED + if(TICKET_REJECTED) + ticket.ticket_status = TICKET_REJECTED + else + return FALSE + if(ticket.ticket_priority) + ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].") + to_chat(usr, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) + return TRUE + + if("new_access") + var/priority_report = FALSE + var/ticket_holder = tgui_input_text(operator, "Who is the ticket for?", "Ticket Holder", encode = FALSE) + if(!ticket_holder) + return FALSE + var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE) + if(!details) + return FALSE + + if(authentication >= APOLLO_ACCESS_AUTHED) + var/is_priority = tgui_alert(operator, "Is this a priority request?", "Priority designation", list("Yes", "No")) + if(is_priority == "Yes") + priority_report = TRUE + + var/confirm = alert(operator, "Please confirm the submission of your access ticket request. \n\n Priority: [priority_report ? "Yes" : "No"] \n Holder: '[ticket_holder]' \n Details: '[details]' \n\n Is this correct?", "Confirmation", "Yes", "No") + if(confirm != "Yes" || !link) + return FALSE + var/datum/ares_ticket/access/access_ticket = new(last_login, ticket_holder, details, priority_report) + link.tickets_access += access_ticket + if(priority_report) + ares_apollo_talk("Priority Access Request: [ticket_holder] - ID [access_ticket.ticket_id]. Seek and resolve.") + log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Holder '[ticket_holder]' and Details of '[details]'.") + return TRUE + + if(playsound) + playsound(src, "keyboard_alt", 15, 1) diff --git a/code/game/machinery/ARES/ARES_records.dm b/code/game/machinery/ARES/ARES_records.dm new file mode 100644 index 000000000000..4e2b479e71a2 --- /dev/null +++ b/code/game/machinery/ARES/ARES_records.dm @@ -0,0 +1,109 @@ +/datum/ares_record + var/record_name = "ARES Data Core" + /// World time in text format. + var/time + /// The title of the record, usually announcement title. + var/title + /// The content of the record, announcement text/bioscan info etc. + var/details + /// The name of the initiator of certain records. Who fired an OB, or who deleted something etc. + var/user + +/datum/ares_record/New(title, details) + time = worldtime2text() + src.title = title + src.details = details + +/datum/ares_record/announcement + record_name = ARES_RECORD_ANNOUNCE + +/datum/ares_record/bioscan + record_name = ARES_RECORD_BIOSCAN + +/datum/ares_record/requisition_log + record_name = ARES_RECORD_ASRS + +/datum/ares_record/requisition_log/New(title, details, user) + time = worldtime2text() + src.title = title + src.details = details + src.user = user + +/datum/ares_record/security + record_name = ARES_RECORD_SECURITY + +/datum/ares_record/antiair + record_name = ARES_RECORD_ANTIAIR + +/datum/ares_record/antiair/New(details, user) + time = worldtime2text() + src.title = "AntiAir Adjustment" + src.details = details + src.user = user + +/datum/ares_record/bombardment + record_name = ARES_RECORD_BOMB + +/datum/ares_record/bombardment/New(title, details, user) + time = worldtime2text() + src.title = title + src.details = details + src.user = user + +/datum/ares_record/deletion + record_name = ARES_RECORD_DELETED + +/datum/ares_record/deletion/New() + time = worldtime2text() + +/datum/ares_record/talk_log + record_name = "1:1 Data Log" + var/conversation = list() + +/datum/ares_record/talk_log/New(user) + src.user = user + src.title = "1:1 Log ([user])" + +/datum/ares_record/deleted_talk + record_name = ARES_RECORD_DELETED + var/conversation = list() + +/datum/ares_record/deleted_talk/New() + time = worldtime2text() + + +/datum/ares_ticket + var/ticket_type = "Root Ticket" + var/ticket_status = TICKET_PENDING + /// Name of who is handling the ticket. Derived from last login. + var/ticket_assignee + /// Numerical designation of the ticket. + var/ticket_id = "1111" + /// World time in text format. + var/ticket_time + /// Who submitted the ticket. Derived from last login. + var/ticket_submitter + /// The name of the ticket. + var/ticket_name + /// The content of the ticket, usually an explanation of what it is for. + var/ticket_details + /// Whether or not the tickey is a priority. + var/ticket_priority = FALSE + +/datum/ares_ticket/New(user, name, details, priority) + var/ref_holder = "\ref[src]" + var/pos = length(ref_holder) + var/new_id = "#[copytext("\ref[src]", pos - 4, pos)]" + + ticket_time = worldtime2text() + ticket_submitter = user + ticket_details = details + ticket_name = name + ticket_priority = priority + ticket_id = new_id + +/datum/ares_ticket/maintenance + ticket_type = ARES_RECORD_MAINTENANCE + +/datum/ares_ticket/access + ticket_type = ARES_RECORD_ACCESS diff --git a/code/game/machinery/ARES/ARES_step_triggers.dm b/code/game/machinery/ARES/ARES_step_triggers.dm new file mode 100644 index 000000000000..a50aa40abd90 --- /dev/null +++ b/code/game/machinery/ARES/ARES_step_triggers.dm @@ -0,0 +1,187 @@ +/obj/effect/step_trigger/ares_alert + name = "ARES Apollo Sensor" + layer = 5 + /// Link alerts to ARES Link + var/datum/ares_link/link + var/link_id = MAIN_SHIP_DEFAULT_NAME + /// Alert message to report unless area based. + var/alert_message = "ALERT: Unauthorized movement detected in ARES Core!" + /// Connect alerts to use same cooldowns + var/alert_id + /// Set to true if it should report area name and not specific alert. + var/area_based = FALSE + /// Cooldown duration and next time. + var/cooldown_duration = COOLDOWN_ARES_SENSOR + COOLDOWN_DECLARE(sensor_cooldown) + /// The job on a mob to enter + var/list/pass_jobs = list(JOB_WORKING_JOE, JOB_CHIEF_ENGINEER, JOB_CO) + /// The accesses on an ID card to enter + var/pass_accesses = list(ACCESS_MARINE_AI, ACCESS_ARES_DEBUG) + +/obj/effect/step_trigger/ares_alert/Crossed(mob/living/passer) + if(!COOLDOWN_FINISHED(src, sensor_cooldown))//Don't want alerts spammed. + return FALSE + if(!passer) + return FALSE + if(!(ishuman(passer) || isxeno(passer))) + return FALSE + if(passer.alpha <= 100)//Can't be seen/detected to trigger alert. + return FALSE + if(pass_jobs) + if(passer.job in pass_jobs) + return FALSE + if(isxeno(passer) && (JOB_XENOMORPH in pass_jobs)) + return FALSE + if(ishuman(passer)) + var/mob/living/carbon/human/trespasser = passer + if(pass_accesses && (trespasser.wear_id)) + for(var/tag in pass_accesses) + if(tag in trespasser.wear_id.access) + return FALSE + Trigger(passer) + return TRUE + + +/obj/effect/step_trigger/ares_alert/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/effect/step_trigger/ares_alert/Destroy() + delink() + return ..() + +/obj/effect/step_trigger/ares_alert/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link.link_id == link_id) + link = new_link + new_link.linked_alerts += src + return TRUE +/obj/effect/step_trigger/ares_alert/proc/delink() + if(link) + link.linked_alerts -= src + link = null + + +/obj/effect/step_trigger/ares_alert/Trigger(mob/living/passer) + var/broadcast_message = alert_message + if(area_based) + var/area_name = get_area_name(src, TRUE) + broadcast_message = "ALERT: Unauthorized movement detected in [area_name]!" + + var/datum/ares_link/link = GLOB.ares_link + if(link.p_apollo.inoperable()) + return FALSE + + to_chat(passer, SPAN_BOLDWARNING("You hear a soft beeping sound as you cross the threshold.")) + ares_apollo_talk(broadcast_message) + COOLDOWN_START(src, sensor_cooldown, cooldown_duration) + if(alert_id && link) + for(var/obj/effect/step_trigger/ares_alert/sensor in link.linked_alerts) + if(sensor.alert_id == src.alert_id) + COOLDOWN_START(sensor, sensor_cooldown, cooldown_duration) + return TRUE + +/obj/effect/step_trigger/ares_alert/public + pass_accesses = list(ACCESS_MARINE_AI_TEMP, ACCESS_MARINE_AI, ACCESS_ARES_DEBUG) +/obj/effect/step_trigger/ares_alert/core + alert_id = "AresCore" + pass_accesses = list(ACCESS_MARINE_AI_TEMP, ACCESS_MARINE_AI, ACCESS_ARES_DEBUG) + +/obj/effect/step_trigger/ares_alert/mainframe + alert_id = "AresMainframe" + alert_message = "ALERT: Unauthorized movement detected in ARES Mainframe!" + +/obj/effect/step_trigger/ares_alert/terminals + alert_id = "AresTerminals" + alert_message = "ALERT: Unauthorized movement detected in ARES' Operations Center!" + +/obj/effect/step_trigger/ares_alert/comms + area_based = TRUE + alert_id = "TComms" + pass_accesses = list(ACCESS_MARINE_CE) + + +/// Trigger will remove ACCESS_MARINE_AI_TEMP unless ACCESS_MARINE_AI is also present. +/obj/effect/step_trigger/ares_alert/access_control + name = "ARES Access Control Sensor" + alert_message = "HARDCODED" + alert_id = "ARES Access" + cooldown_duration = COOLDOWN_ARES_ACCESS_CONTROL + + +/obj/effect/step_trigger/ares_alert/access_control/Crossed(atom/passer as mob|obj) + if(isobserver(passer) || isxeno(passer)) + return FALSE + if(!COOLDOWN_FINISHED(src, sensor_cooldown))//Don't want alerts spammed. + return FALSE + if(!passer) + return FALSE + if(passer.alpha <= 100)//Can't be seen/detected to trigger alert. + return FALSE + var/area/pass_area = get_area(get_step(passer, passer.dir)) + if(istype(pass_area, /area/almayer/command/airoom))//Don't want it to freak out over someone /entering/ the area. Only leaving. + return FALSE + var/obj/item/card/id/idcard + var/check_contents = TRUE + if(ishuman(passer)) + var/mob/living/carbon/human/human_passer = passer + idcard = human_passer.wear_id + if(istype(idcard)) + check_contents = FALSE + else + idcard = null + + if(istype(passer, /obj/item/card/id)) + idcard = passer + check_contents = FALSE + + if(check_contents) + idcard = locate(/obj/item/card/id) in passer + if(!idcard) + for(var/obj/item/holder in passer.contents) + idcard = locate(/obj/item/card/id) in holder.contents + if(idcard) + break + if(!istype(idcard) && ismob(passer)) + Trigger(passer, failure = TRUE) + return FALSE + if(!(ACCESS_MARINE_AI_TEMP in idcard.access))//No temp access, don't care + return FALSE + if((ACCESS_MARINE_AI in idcard.access) || (ACCESS_ARES_DEBUG in idcard.access))//Permanent access prevents loss of temporary + return FALSE + Trigger(passer, idcard) + return TRUE + +/obj/effect/step_trigger/ares_alert/access_control/Trigger(atom/passer, obj/item/card/id/idcard, failure = FALSE) + var/broadcast_message = get_broadcast(passer, idcard, failure) + + var/datum/ares_link/link = GLOB.ares_link + if(link.p_apollo.inoperable()) + return FALSE + + to_chat(passer, SPAN_BOLDWARNING("You hear a harsh buzzing sound as you cross the threshold!")) + ares_apollo_talk(broadcast_message) + if(idcard) + idcard.access -= ACCESS_MARINE_AI_TEMP + COOLDOWN_START(src, sensor_cooldown, COOLDOWN_ARES_ACCESS_CONTROL) + if(alert_id && link) + for(var/obj/effect/step_trigger/ares_alert/sensor in link.linked_alerts) + if(sensor.alert_id == src.alert_id) + COOLDOWN_START(sensor, sensor_cooldown, COOLDOWN_ARES_ACCESS_CONTROL) + return TRUE + +/obj/effect/step_trigger/ares_alert/access_control/proc/get_broadcast(atom/passer, obj/item/card/id/idcard, failure = FALSE) + if(isxeno(passer)) + return "Unidentified lifeform detected departing AI Chamber." + if(ishuman(passer)) + var/mob/living/carbon/human/human_passer = passer + if(failure) + return "CAUTION: [human_passer.name] left the AI Chamber without a locatable ID card." + return "ALERT: [human_passer.name] left the AI Chamber with a temporary access ticket. Removing access." + + if(idcard) + return "ALERT: ID Card assigned to [idcard.registered_name] left the AI Chamber with a temporary access ticket. Removing access." + + log_debug("ARES ERROR 337: Passer: '[passer]', ID: '[idcard]', F Status: '[failure]'") + return "Warning: Error 337 - Access Control Anomaly." diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm index b259644bba65..28e045163f06 100644 --- a/code/game/machinery/air_alarm.dm +++ b/code/game/machinery/air_alarm.dm @@ -158,9 +158,11 @@ elect_master() /obj/structure/machinery/alarm/Destroy() + if(alarm_area.master_air_alarm == src) + alarm_area.master_air_alarm = null alarm_area = null SSradio.remove_object(src, frequency) - QDEL_NULL(radio_connection) + radio_connection = null return ..() /obj/structure/machinery/alarm/proc/handle_heating_cooling() diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 437cb10fac5e..6ccb0b5b18f7 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -204,7 +204,7 @@ //Exploit detection, not sure if necessary after rewrite. if(!making || multiplier < 0 || multiplier > 100) var/turf/exploit_loc = get_turf(usr) - message_admins("[key_name_admin(usr)] tried to exploit an autolathe to duplicate an item! ([exploit_loc ? "JMP" : "null"])") + message_admins("[key_name_admin(usr)] tried to exploit an autolathe to duplicate an item! ([exploit_loc ? "[ADMIN_JMP(exploit_loc)]" : "null"])") return if(making.is_stack) @@ -284,7 +284,7 @@ return //Dismantle the frame. - if(istype(O, /obj/item/tool/crowbar)) + if(HAS_TRAIT(O, TRAIT_TOOL_CROWBAR)) dismantle() return @@ -554,12 +554,6 @@ printables += list(print_data) -/obj/structure/machinery/autolathe/yautja - name = "yautja autolathe" - desc = "It produces items using metal and glass." - icon = 'icons/obj/structures/machinery/predautolathe.dmi' - stored_material = list("metal" = 40000, "glass" = 20000) - /obj/structure/machinery/autolathe/full stored_material = list("metal" = 40000, "glass" = 20000) diff --git a/code/game/machinery/autolathe_datums.dm b/code/game/machinery/autolathe_datums.dm index ba6c0a85b446..02de2b200821 100644 --- a/code/game/machinery/autolathe_datums.dm +++ b/code/game/machinery/autolathe_datums.dm @@ -478,6 +478,11 @@ path = /obj/item/storage/syringe_case category = AUTOLATHE_CATEGORY_MEDICAL_CONTAINERS +/datum/autolathe/recipe/medilathe/surgical_case + name = "surgical case" + path = /obj/item/storage/surgical_case + category = AUTOLATHE_CATEGORY_MEDICAL_CONTAINERS + /datum/autolathe/recipe/medilathe/vial_box name = "vial box" path = /obj/item/storage/fancy/vials/empty diff --git a/code/game/machinery/bio-dome_floodlights.dm b/code/game/machinery/bio-dome_floodlights.dm index 83d40aef21e3..488cf1ed79cc 100644 --- a/code/game/machinery/bio-dome_floodlights.dm +++ b/code/game/machinery/bio-dome_floodlights.dm @@ -1,6 +1,6 @@ /obj/structure/machinery/hydro_floodlight_switch name = "Biodome Floodlight Switch" - icon = 'icons/turf/ground_map.dmi' + icon = 'icons/obj/structures/machinery/power.dmi' icon_state = "panelnopower" desc = "This switch controls the floodlights surrounding the archaeology complex. It only functions when there is power." density = FALSE diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm index b3494b1846c7..f28a15ea1893 100644 --- a/code/game/machinery/bots/medbot.dm +++ b/code/game/machinery/bots/medbot.dm @@ -50,22 +50,24 @@ -/obj/structure/machinery/bot/medbot/New() - ..() +/obj/structure/machinery/bot/medbot/Initialize(mapload, ...) + . = ..() src.icon_state = "medibot[src.on]" - spawn(4) - if(src.skin) - src.overlays += image('icons/obj/structures/machinery/aibots.dmi', "medskin_[src.skin]") - - src.botcard = new /obj/item/card/id(src) - if(isnull(src.botcard_access) || (src.botcard_access.len < 1)) - var/datum/job/J = RoleAuthority ? RoleAuthority.roles_by_path[/datum/job/civilian/doctor] : new /datum/job/civilian/doctor - botcard.access = J.get_access() - else - src.botcard.access = src.botcard_access + addtimer(CALLBACK(src, PROC_REF(setup_bot)), 0.4 SECONDS) start_processing() +/obj/structure/machinery/bot/medbot/proc/setup_bot() + if(src.skin) + src.overlays += image('icons/obj/structures/machinery/aibots.dmi', "medskin_[src.skin]") + + src.botcard = new /obj/item/card/id(src) + if(isnull(src.botcard_access) || (src.botcard_access.len < 1)) + var/datum/job/J = RoleAuthority ? RoleAuthority.roles_by_path[/datum/job/civilian/doctor] : new /datum/job/civilian/doctor + botcard.access = J.get_access() + else + src.botcard.access = src.botcard_access + /obj/structure/machinery/bot/medbot/Destroy() botcard_access = null patient = null diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index 1a15d40eba9c..a8735cbc06a8 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -110,6 +110,10 @@ /obj/structure/machinery/camera/autoname/almayer/containment/hidden network = list(CAMERA_NET_CONTAINMENT_HIDDEN) +/obj/structure/machinery/camera/autoname/almayer/containment/ares + name = "ares core camera" + network = list(CAMERA_NET_ALMAYER, CAMERA_NET_ARES) + //used by the landing camera dropship equipment. Do not place them right under where the dropship lands. //Should place them near each corner of your LZs. /obj/structure/machinery/camera/autoname/lz_camera diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 6c5ee5d4b70d..bb6972a58ac3 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -3,7 +3,7 @@ anchored = FALSE name = "AI core" icon = 'icons/obj/structures/machinery/AI.dmi' - icon_state = "0" + icon_state = "hydra-off" var/state = 0 var/obj/item/circuitboard/aicore/circuit = null var/obj/item/device/mmi/brain = null @@ -51,7 +51,7 @@ to_chat(user, SPAN_NOTICE(" You screw the circuit board into place.")) state = 2 icon_state = "2" - if(istype(P, /obj/item/tool/crowbar) && circuit) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && circuit) playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the circuit board.")) state = 1 @@ -121,7 +121,7 @@ to_chat(usr, "Added [mmi].") icon_state = "3b" - if(istype(P, /obj/item/tool/crowbar) && brain) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && brain) playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the brain.")) brain.forceMove(loc) @@ -129,7 +129,7 @@ icon_state = "3" if(4) - if(istype(P, /obj/item/tool/crowbar)) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR)) playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the glass panel.")) state = 3 @@ -151,7 +151,7 @@ /obj/structure/AIcore/deactivated name = "Inactive AI" icon = 'icons/obj/structures/machinery/AI.dmi' - icon_state = "ai-empty" + icon_state = "hydra-off" anchored = TRUE state = 20//So it doesn't interact based on the above. Not really necessary. diff --git a/code/game/machinery/computer/almayer_control.dm b/code/game/machinery/computer/almayer_control.dm index 07cb441011ae..7d63a2e8c3af 100644 --- a/code/game/machinery/computer/almayer_control.dm +++ b/code/game/machinery/computer/almayer_control.dm @@ -1,16 +1,3 @@ -#define STATE_DEFAULT 1 -#define STATE_EVACUATION 2 -#define STATE_EVACUATION_CANCEL 3 -#define STATE_DISTRESS 4 -#define STATE_DESTROY 5 -#define STATE_DEFCONLIST 6 - -#define STATE_MESSAGELIST 7 -#define STATE_VIEWMESSAGE 8 -#define STATE_DELMESSAGE 9 - - - #define COMMAND_SHIP_ANNOUNCE "Command Ship Announcement" /obj/structure/machinery/computer/almayer_control @@ -21,271 +8,149 @@ unslashable = TRUE unacidable = TRUE - var/state = STATE_DEFAULT - - var/is_announcement_active = TRUE - - var/cooldown_request = 0 - var/cooldown_destruct = 0 - var/cooldown_central = 0 + /// requesting a distress beacon + COOLDOWN_DECLARE(cooldown_request) + /// requesting evac + COOLDOWN_DECLARE(cooldown_destruct) + /// messaging HC (admins) + COOLDOWN_DECLARE(cooldown_central) + /// making a ship announcement + COOLDOWN_DECLARE(cooldown_message) var/list/messagetitle = list() var/list/messagetext = list() - var/currmsg = 0 - var/aicurrmsg = 0 /obj/structure/machinery/computer/almayer_control/attack_remote(mob/user as mob) return attack_hand(user) /obj/structure/machinery/computer/almayer_control/attack_hand(mob/user as mob) - if(..() || !allowed(user) || inoperable()) + if(..() || inoperable()) return + if(!allowed(user)) + to_chat(usr, SPAN_WARNING("Access denied.")) + return FALSE + if(!istype(loc.loc, /area/almayer/command/cic)) //Has to be in the CIC. Can also be a generic CIC area to communicate, if wanted. to_chat(usr, SPAN_WARNING("Unable to establish a connection.")) return FALSE - ui_interact(user) - -/obj/structure/machinery/computer/almayer_control/ui_interact(mob/user as mob) - user.set_interaction(src) - - var/dat = "Almayer Control Console" + tgui_interact(user) - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING) - dat += "Evacuation in Progress\n
\nETA: [EvacuationAuthority.get_status_panel_eta()]
" - - switch(state) - if(STATE_DEFAULT) - dat += "Alert Level: [get_security_level()]
" - dat += "
[is_announcement_active ? "Make a ship announcement" : "*Unavailable*"]" - dat += GLOB.admins.len > 0 ? "
Send a message to USCM" : "
USCM communication offline" - dat += "
Award a medal" - dat += "

" - dat += "

" - - - dat += "
Message list" - dat += "
Send Distress Beacon" - dat += "
Activate Self-Destruct" - switch(EvacuationAuthority.evac_status) - if(EVACUATION_STATUS_STANDING_BY) - dat += "
Initiate emergency evacuation" - if(EVACUATION_STATUS_INITIATING) - dat += "
Cancel emergency evacuation" - - if(STATE_EVACUATION) - dat += "Are you sure you want to evacuate the [MAIN_SHIP_NAME]? Confirm" - - if(STATE_EVACUATION_CANCEL) - dat += "Are you sure you want to cancel the evacuation of the [MAIN_SHIP_NAME]? Confirm" - - if(STATE_DISTRESS) - dat += "Are you sure you want to trigger a distress signal? The signal can be picked up by anyone listening, friendly or not. Confirm" - - if(STATE_DESTROY) - dat += "Are you sure you want to trigger the self-destruct? This would mean abandoning ship. Confirm" - - if(STATE_MESSAGELIST) - dat += "Messages:" - for(var/i = 1; i<=messagetitle.len; i++) - dat += "
[messagetitle[i]]" - - if(STATE_VIEWMESSAGE) - if (currmsg) - dat += "[messagetitle[currmsg]]

[messagetext[currmsg]]" - dat += "

Delete" - else - state = STATE_MESSAGELIST - attack_hand(user) - return FALSE +// tgui boilerplate \\ - if(STATE_DELMESSAGE) - if (currmsg) - dat += "Are you sure you want to delete this message? OK|Cancel" - else - state = STATE_MESSAGELIST - attack_hand(user) - return FALSE +/obj/structure/machinery/computer/almayer_control/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AlmayerControl", "[name]") + ui.open() - dat += "
[(state != STATE_DEFAULT) ? "Main Menu|" : ""]Close" +/obj/structure/machinery/computer/almayer_control/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(!allowed(user)) + return UI_CLOSE + if(!operable()) + return UI_CLOSE - show_browser(user, dat, name, "almayer_control") - onclose(user, "almayer_control") +/obj/structure/machinery/computer/almayer_control/ui_state(mob/user) + return GLOB.not_incapacitated_and_adjacent_strict_state -/obj/structure/machinery/computer/almayer_control/Topic(href, href_list) - if(..()) - return FALSE +// tgui data \\ - usr.set_interaction(src) +/obj/structure/machinery/computer/almayer_control/ui_static_data(mob/user) + var/list/data = list() - switch(href_list["operation"]) - if("main") - state = STATE_DEFAULT + data["cooldown_request"] = COOLDOWN_COMM_REQUEST + data["cooldown_destruct"] = COOLDOWN_COMM_DESTRUCT + data["cooldown_central"] = COOLDOWN_COMM_CENTRAL + data["cooldown_message"] = COOLDOWN_COMM_MESSAGE + data["distresstimelock"] = DISTRESS_TIME_LOCK - if("ship_announce") - if(!is_announcement_active) - to_chat(usr, SPAN_WARNING("Please allow at least [COOLDOWN_COMM_MESSAGE*0.1] second\s to pass between announcements.")) - return FALSE - var/input = stripped_multiline_input(usr, "Please write a message to announce to the station crew.", "Priority Announcement", "") - if(!input || !is_announcement_active || !(usr in view(1,src))) - return FALSE + return data - is_announcement_active = FALSE +/obj/structure/machinery/computer/almayer_control/ui_data(mob/user) + var/list/data = list() + var/list/messages = list() - var/signed = null - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - var/obj/item/card/id/id = H.wear_id - if(istype(id)) - var/paygrade = get_paygrades(id.paygrade, FALSE, H.gender) - signed = "[paygrade] [id.registered_name]" + data["alert_level"] = security_level - shipwide_ai_announcement(input, COMMAND_SHIP_ANNOUNCE, signature = signed) - addtimer(CALLBACK(src, PROC_REF(reactivate_announcement), usr), COOLDOWN_COMM_MESSAGE) - message_admins("[key_name(usr)] has made a shipwide annoucement.") - log_announcement("[key_name(usr)] has announced the following to the ship: [input]") + data["time_request"] = cooldown_request + data["time_destruct"] = cooldown_destruct + data["time_central"] = cooldown_central + data["time_message"] = cooldown_message + data["worldtime"] = world.time - if("evacuation_start") - if(state == STATE_EVACUATION) - if(security_level < SEC_LEVEL_RED) - to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) - return FALSE - - if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) - to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) - return FALSE - - if(!EvacuationAuthority.initiate_evacuation()) - to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) - return FALSE - - log_game("[key_name(usr)] has called for an emergency evacuation.") - message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") - return TRUE - - state = STATE_EVACUATION + data["evac_status"] = EvacuationAuthority.evac_status + if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING) + data["evac_eta"] = EvacuationAuthority.get_status_panel_eta() - if("evacuation_cancel") - if(state == STATE_EVACUATION_CANCEL) - if(!EvacuationAuthority.cancel_evacuation()) - to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!")) - return FALSE + if(!messagetitle.len) + data["messages"] = null + else + for(var/i in 1 to length(messagetitle)) + var/list/messagedata = list(list( + "title" = messagetitle[i], + "text" = messagetext[i], + "number" = i + )) + messages += messagedata - spawn(35)//some time between AI announcements for evac cancel and SD cancel. - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait - //if the self_destruct is active we try to cancel it (which includes lowering alert level to red) - if(!EvacuationAuthority.cancel_self_destruct(1)) - //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually. - set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level. + data["messages"] = messages - log_game("[key_name(usr)] has canceled the emergency evacuation.") - message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") - return TRUE + return data - state = STATE_EVACUATION_CANCEL +// end tgui data \\ - if("distress") - if(state == STATE_DISTRESS) - if(world.time < DISTRESS_TIME_LOCK) - to_chat(usr, SPAN_WARNING("The distress beacon cannot be launched this early in the operation. Please wait another [time_left_until(DISTRESS_TIME_LOCK, world.time, 1 MINUTES)] minutes before trying again.")) - return FALSE +// tgui interact \\ - if(!SSticker.mode) - return FALSE //Not a game mode? +/obj/structure/machinery/computer/almayer_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return - if(SSticker.mode.force_end_at == 0) - to_chat(usr, SPAN_WARNING("ARES has denied your request for operational security reasons.")) - return FALSE + switch(action) + if("award") + print_medal(usr, src) + . = TRUE - if(world.time < cooldown_request + COOLDOWN_COMM_REQUEST) - to_chat(usr, SPAN_WARNING("The distress beacon has recently broadcast a message. Please wait.")) - return FALSE + // evac stuff start \\ - if(security_level == SEC_LEVEL_DELTA) - to_chat(usr, SPAN_WARNING("The ship is already undergoing self-destruct procedures!")) - return FALSE + if("evacuation_start") + if(security_level < SEC_LEVEL_RED) + to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) + return FALSE - for(var/client/C in GLOB.admins) - if((R_ADMIN|R_MOD) & C.admin_holder.rights) - C << 'sound/effects/sos-morse-code.ogg' - message_admins("[key_name(usr)] has requested a Distress Beacon! (Mark) (SEND) (DENY) (JMP) (RPLY)") - to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM Central Command.")) + if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) + return FALSE - cooldown_request = world.time - return TRUE + if(!EvacuationAuthority.initiate_evacuation()) + to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) + return FALSE - state = STATE_DISTRESS + log_game("[key_name(usr)] has called for an emergency evacuation.") + message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") + . = TRUE - if("destroy") - if(state == STATE_DESTROY) - //Comment to test - if(world.time < DISTRESS_TIME_LOCK) - to_chat(usr, SPAN_WARNING("The self-destruct cannot be activated this early in the operation. Please wait another [time_left_until(DISTRESS_TIME_LOCK, world.time, 1 MINUTES)] minutes before trying again.")) - return FALSE - - if(!SSticker.mode) - return FALSE //Not a game mode? - - if(SSticker.mode.force_end_at == 0) - to_chat(usr, SPAN_WARNING("ARES has denied your request for operational security reasons.")) - return FALSE - - if(world.time < cooldown_destruct + COOLDOWN_COMM_DESTRUCT) - to_chat(usr, SPAN_WARNING("A self-destruct request has already been sent to high command. Please wait.")) - return FALSE - - if(get_security_level() == "delta") - to_chat(usr, SPAN_WARNING("The [MAIN_SHIP_NAME]'s self-destruct is already activated.")) - return FALSE - - for(var/client/C in GLOB.admins) - if((R_ADMIN|R_MOD) & C.admin_holder.rights) - C << 'sound/effects/sos-morse-code.ogg' - message_admins("[key_name(usr)] has requested Self-Destruct! (Mark) (GRANT) (DENY) (JMP) (RPLY)") - to_chat(usr, SPAN_NOTICE("A self-destruct request has been sent to USCM Central Command.")) - cooldown_destruct = world.time - return TRUE - - state = STATE_DESTROY - - if("messagelist") - currmsg = 0 - state = STATE_MESSAGELIST - - if("viewmessage") - state = STATE_VIEWMESSAGE - if (!currmsg) - if(href_list["message-num"]) currmsg = text2num(href_list["message-num"]) - else state = STATE_MESSAGELIST + if("evacuation_cancel") + if(!EvacuationAuthority.cancel_evacuation()) + to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!")) + return FALSE - if("delmessage") - state = (currmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST - - if("delmessage2") - if(currmsg) - var/title = messagetitle[currmsg] - var/text = messagetext[currmsg] - messagetitle.Remove(title) - messagetext.Remove(text) - if(currmsg == aicurrmsg) aicurrmsg = 0 - currmsg = 0 - state = STATE_MESSAGELIST + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/machinery/computer/almayer_control, cancel_evac)), 4 SECONDS) - if("messageUSCM") - if(world.time < cooldown_central + COOLDOWN_COMM_CENTRAL) - to_chat(usr, SPAN_WARNING("Arrays recycling. Please stand by.")) - return FALSE - var/input = stripped_input(usr, "Please choose a message to transmit to USCM. Please be aware that this process is very expensive, and abuse will lead to termination. Transmission does not guarantee a response. There is a small delay before you may send another message. Be clear and concise.", "To abort, send an empty message.", "") - if(!input || !(usr in view(1,src)) || world.time < cooldown_central + COOLDOWN_COMM_CENTRAL) return FALSE + log_game("[key_name(usr)] has canceled the emergency evacuation.") + message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") + . = TRUE - high_command_announce(input, usr) - to_chat(usr, SPAN_NOTICE("Message transmitted.")) - log_announcement("[key_name(usr)] has made an USCM announcement: [input]") - cooldown_central = world.time + // evac stuff end \\ - if("changeseclevel") + if("change_sec_level") var/list/alert_list = list(num2seclevel(SEC_LEVEL_GREEN), num2seclevel(SEC_LEVEL_BLUE)) switch(security_level) if(SEC_LEVEL_GREEN) @@ -300,27 +165,125 @@ return set_security_level(seclevel2num(level_selected)) - log_game("[key_name(usr)] has changed the security level to [get_security_level()].") message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_security("Security Level Update", "[usr] has changed the security level to [get_security_level()].") + . = TRUE - if("award") - print_medal(usr, src) + if("messageUSCM") + if(!COOLDOWN_FINISHED(src, cooldown_central)) + to_chat(usr, SPAN_WARNING("Arrays are re-cycling. Please stand by.")) + return FALSE + var/input = stripped_input(usr, "Please choose a message to transmit to USCM. Please be aware that this process is very expensive, and abuse will lead to termination. Transmission does not guarantee a response. There is a small delay before you may send another message. Be clear and concise.", "To abort, send an empty message.", "") + if(!input || !(usr in view(1,src)) || !COOLDOWN_FINISHED(src, cooldown_central)) + return FALSE + + high_command_announce(input, usr) + to_chat(usr, SPAN_NOTICE("Message transmitted.")) + log_announcement("[key_name(usr)] has made an USCM announcement: [input]") + COOLDOWN_START(src, cooldown_central, COOLDOWN_COMM_CENTRAL) + . = TRUE + + if("ship_announce") + if(!COOLDOWN_FINISHED(src, cooldown_message)) + to_chat(usr, SPAN_WARNING("Please allow at least [COOLDOWN_TIMELEFT(src, cooldown_message)/10] second\s to pass between announcements.")) + return FALSE + var/input = stripped_multiline_input(usr, "Please write a message to announce to the station crew.", "Priority Announcement", "") + if(!input || !COOLDOWN_FINISHED(src, cooldown_message) || !(usr in view(1,src))) + return FALSE + + var/signed = null + if(ishuman(usr)) + var/mob/living/carbon/human/human_user = usr + var/obj/item/card/id/id = human_user.wear_id + if(istype(id)) + var/paygrade = get_paygrades(id.paygrade, FALSE, human_user.gender) + signed = "[paygrade] [id.registered_name]" + + COOLDOWN_START(src, cooldown_message, COOLDOWN_COMM_MESSAGE) + shipwide_ai_announcement(input, COMMAND_SHIP_ANNOUNCE, signature = signed) + message_admins("[key_name(usr)] has made a shipwide annoucement.") + log_announcement("[key_name(usr)] has announced the following to the ship: [input]") + . = TRUE + + if("distress") + if(world.time < DISTRESS_TIME_LOCK) + to_chat(usr, SPAN_WARNING("The distress beacon cannot be launched this early in the operation. Please wait another [time_left_until(DISTRESS_TIME_LOCK, world.time, 1 MINUTES)] minutes before trying again.")) + return FALSE + + if(!SSticker.mode) + return FALSE //Not a game mode? + + if(SSticker.mode.force_end_at == 0) + to_chat(usr, SPAN_WARNING("ARES has denied your request for operational security reasons.")) + return FALSE + + if(!COOLDOWN_FINISHED(src, cooldown_request)) + to_chat(usr, SPAN_WARNING("The distress beacon has recently broadcast a message. Please wait.")) + return FALSE - updateUsrDialog() + if(security_level == SEC_LEVEL_DELTA) + to_chat(usr, SPAN_WARNING("The ship is already undergoing self-destruct procedures!")) + return FALSE + + for(var/client/admin_client as anything in GLOB.admins) + if((R_ADMIN|R_MOD) & admin_client.admin_holder.rights) + admin_client << 'sound/effects/sos-morse-code.ogg' + message_admins("[key_name(usr)] has requested a Distress Beacon! [CC_MARK(usr)] (SEND) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") + to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM Central Command.")) + + COOLDOWN_START(src, cooldown_request, COOLDOWN_COMM_REQUEST) + . = TRUE + + // sd \\ + + if("destroy") + if(world.time < DISTRESS_TIME_LOCK) + to_chat(usr, SPAN_WARNING("The self-destruct cannot be activated this early in the operation. Please wait another [time_left_until(DISTRESS_TIME_LOCK, world.time, 1 MINUTES)] minutes before trying again.")) + return FALSE + + if(!SSticker.mode) + return FALSE //Not a game mode? + + if(SSticker.mode.force_end_at == 0) + to_chat(usr, SPAN_WARNING("ARES has denied your request for operational security reasons.")) + return FALSE + + if(!COOLDOWN_FINISHED(src, cooldown_destruct)) + to_chat(usr, SPAN_WARNING("A self-destruct request has already been sent to high command. Please wait.")) + return FALSE + + if(get_security_level() == "delta") + to_chat(usr, SPAN_WARNING("The [MAIN_SHIP_NAME]'s self-destruct is already activated.")) + return FALSE + + for(var/client/admin_client as anything in GLOB.admins) + if((R_ADMIN|R_MOD) & admin_client.admin_holder.rights) + admin_client << 'sound/effects/sos-morse-code.ogg' + message_admins("[key_name(usr)] has requested Self-Destruct! [CC_MARK(usr)] (GRANT) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") + to_chat(usr, SPAN_NOTICE("A self-destruct request has been sent to USCM Central Command.")) + COOLDOWN_START(src, cooldown_destruct, COOLDOWN_COMM_DESTRUCT) + . = TRUE + + if("delmessage") + var/number_of_message = params["number"] + if(!number_of_message) + return FALSE + var/title = messagetitle[number_of_message] + var/text = messagetext[number_of_message] + messagetitle.Remove(title) + messagetext.Remove(text) + . = TRUE -/obj/structure/machinery/computer/almayer_control/proc/reactivate_announcement(mob/user) - is_announcement_active = TRUE - updateUsrDialog() +// end tgui interact \\ -#undef STATE_DEFAULT -#undef STATE_EVACUATION -#undef STATE_EVACUATION_CANCEL -#undef STATE_DISTRESS -#undef STATE_DESTROY -#undef STATE_DEFCONLIST +// end tgui \\ -#undef STATE_MESSAGELIST -#undef STATE_VIEWMESSAGE -#undef STATE_DELMESSAGE +/obj/structure/machinery/computer/almayer_control/proc/cancel_evac() + if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait + //if the self_destruct is active we try to cancel it (which includes lowering alert level to red) + if(!EvacuationAuthority.cancel_self_destruct(1)) + //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually. + set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level. diff --git a/code/game/machinery/computer/area_air_control.dm b/code/game/machinery/computer/area_air_control.dm index ee217ccbac7f..e3f16a988c86 100644 --- a/code/game/machinery/computer/area_air_control.dm +++ b/code/game/machinery/computer/area_air_control.dm @@ -1,7 +1,7 @@ /obj/structure/machinery/computer/area_atmos name = "Area Air Control" desc = "A computer used to control the stationary scrubbers and pumps in the area." - icon_state = "area_atmos" + icon_state = "atmos" circuit = /obj/item/circuitboard/computer/area_atmos var/list/connectedscrubbers = new() diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index e32e43a9a4f2..9a17449b9e47 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -21,7 +21,7 @@ SSradio.remove_object(src, receive_frequency) QDEL_NULL_LIST(priority_alarms) QDEL_NULL_LIST(minor_alarms) - QDEL_NULL(radio_connection) + radio_connection = null . = ..() /obj/structure/machinery/computer/atmos_alert/receive_signal(datum/signal/signal) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index bd42b31ea573..07c960807205 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -52,7 +52,7 @@ to_chat(user, SPAN_NOTICE(" You screw the circuit board into place.")) src.state = 2 src.icon_state = "2" - if(istype(P, /obj/item/tool/crowbar) && circuit) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && circuit) playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the circuit board.")) src.state = 1 @@ -99,7 +99,7 @@ src.state = 4 src.icon_state = "4" if(4) - if(istype(P, /obj/item/tool/crowbar)) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR)) playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the glass panel.")) src.state = 3 diff --git a/code/game/machinery/computer/camera_console.dm b/code/game/machinery/computer/camera_console.dm index f4b2ed22f718..d4feca457f4a 100644 --- a/code/game/machinery/computer/camera_console.dm +++ b/code/game/machinery/computer/camera_console.dm @@ -286,20 +286,23 @@ /obj/structure/machinery/computer/cameras/mining name = "Outpost Cameras" + icon = 'icons/obj/structures/machinery/computer.dmi' desc = "Used to access the various cameras on the outpost." - icon_state = "miningcameras" + icon_state = "cameras" network = list("MINE") circuit = /obj/item/circuitboard/computer/cameras/mining /obj/structure/machinery/computer/cameras/engineering name = "Engineering Cameras" + icon = 'icons/obj/structures/machinery/computer.dmi' desc = "Used to monitor fires and breaches." - icon_state = "engineeringcameras" + icon_state = "cameras" network = list("Engineering","Power Alarms","Atmosphere Alarms","Fire Alarms") circuit = /obj/item/circuitboard/computer/cameras/engineering /obj/structure/machinery/computer/cameras/nuclear name = "Mission Monitor" + icon = 'icons/obj/structures/machinery/computer.dmi' desc = "Used to access the built-in cameras in helmets." icon_state = "syndicam" network = list("NUKE") @@ -315,6 +318,10 @@ name = "Containment Cameras" network = list(CAMERA_NET_CONTAINMENT) +/obj/structure/machinery/computer/cameras/almayer/ares + name = "ARES Core Cameras" + network = list(CAMERA_NET_ARES) + /obj/structure/machinery/computer/cameras/almayer/vehicle name = "Ship Security Cameras" network = list(CAMERA_NET_ALMAYER, CAMERA_NET_VEHICLE) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 796d0479e75e..edc39faf3ddc 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -65,6 +65,7 @@ if(..()) return FALSE usr.set_interaction(src) + var/datum/ares_link/link = GLOB.ares_link switch(href_list["operation"]) if("mapview") tacmap.tgui_interact(usr) @@ -148,6 +149,7 @@ log_game("[key_name(usr)] has called for an emergency evacuation.") message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") + link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") return TRUE state = STATE_EVACUATION @@ -167,6 +169,7 @@ log_game("[key_name(usr)] has canceled the emergency evacuation.") message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") + link.log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") return TRUE state = STATE_EVACUATION_CANCEL @@ -197,7 +200,7 @@ for(var/client/C in GLOB.admins) if((R_ADMIN|R_MOD) & C.admin_holder.rights) C << 'sound/effects/sos-morse-code.ogg' - message_admins("[key_name(usr)] has requested a Distress Beacon! (Mark) (SEND) (DENY) (JMP) (RPLY)") + message_admins("[key_name(usr)] has requested a Distress Beacon! [CC_MARK(usr)] (SEND) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM Central Command.")) cooldown_request = world.time @@ -231,7 +234,7 @@ for(var/client/C in GLOB.admins) if((R_ADMIN|R_MOD) & C.admin_holder.rights) C << 'sound/effects/sos-morse-code.ogg' - message_admins("[key_name(usr)] has requested Self-Destruct! (Mark) (GRANT) (DENY) (JMP) (RPLY)") + message_admins("[key_name(usr)] has requested Self-Destruct! [CC_MARK(usr)] (GRANT) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") to_chat(usr, SPAN_NOTICE("A self-destruct request has been sent to USCM Central Command.")) cooldown_destruct = world.time return TRUE diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index fecedda22a14..8fa0b9b86a0c 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -11,6 +11,7 @@ unslashable = TRUE var/circuit = null //The path to the circuit board type. If circuit==null, the computer can't be disassembled. var/processing = FALSE //Set to true if computer needs to do /process() + var/deconstructible = TRUE var/exproof = 0 /obj/structure/machinery/computer/Initialize() @@ -96,6 +97,9 @@ /obj/structure/machinery/computer/attackby(obj/item/I, mob/user) if(HAS_TRAIT(I, TRAIT_TOOL_SCREWDRIVER) && circuit) + if(!deconstructible) + to_chat(user, SPAN_WARNING("You can't figure out how to deconstruct [src]...")) + return if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) to_chat(user, SPAN_WARNING("You don't know how to deconstruct [src]...")) return diff --git a/code/game/machinery/computer/demo_sim.dm b/code/game/machinery/computer/demo_sim.dm index c4cdd14468ee..15261cfc8f4b 100644 --- a/code/game/machinery/computer/demo_sim.dm +++ b/code/game/machinery/computer/demo_sim.dm @@ -1,66 +1,12 @@ -#define HUMAN_MODE "Unarmoured Humans" -#define UPP_MODE "UPP Conscripts" -#define CLF_MODE "CLF Guerillas" -#define RUNNER_MODE "Xenomorph Runners" -#define SPITTER_MODE "Xenomorph Spitters" -#define DEFENDER_MODE "Xenomorph Defenders" -#define RAVAGER_MODE "Xenomorph Ravagers" -#define CRUSHER_MODE "Xenomorph Crushers" - /obj/structure/machinery/computer/demo_sim name = "demolitions simulator" desc = "A powerful simulator that can simulate explosions. Its processors need a cooldown of approximately 1 minute after each simulation." icon_state = "demo_sim" exproof = TRUE unacidable = TRUE + var/datum/simulator/simulation + var/turf/sim_location var/obj/item/configuration - var/obj/structure/machinery/camera/simulation/simulation - // is the ui user actually looking at the simulation? - var/looking_at_simulation = FALSE - - COOLDOWN_DECLARE(detonation_cooldown) - var/detonation_cooldown_time = 1 MINUTES - - var/dummy_mode = HUMAN_MODE - - var/list/target_types = list( - HUMAN_MODE = /mob/living/carbon/human, - UPP_MODE = /mob/living/carbon/human, - CLF_MODE = /mob/living/carbon/human, - RUNNER_MODE = /mob/living/carbon/xenomorph/runner, - SPITTER_MODE = /mob/living/carbon/xenomorph/spitter, - DEFENDER_MODE = /mob/living/carbon/xenomorph/defender, - RAVAGER_MODE = /mob/living/carbon/xenomorph/ravager, - CRUSHER_MODE = /mob/living/carbon/xenomorph/crusher, - ) - -/obj/effect/landmark/sim_target - name = "simulator_target" - -/obj/effect/landmark/sim_target/Initialize(mapload, ...) - . = ..() - GLOB.simulator_targets += src - -/obj/effect/landmark/sim_target/Destroy() - GLOB.simulator_targets -= src - return ..() - -/obj/effect/landmark/sim_camera - name = "simulator_camera" - color = "#FFFF00"; - -/obj/effect/landmark/sim_camera/Initialize(mapload, ...) - . = ..() - GLOB.simulator_cameras += src - -/obj/effect/landmark/sim_camera/Destroy() - GLOB.simulator_cameras -= src - return ..() - -/obj/structure/machinery/computer/demo_sim/get_examine_text(mob/user) - . = ..() - if(!COOLDOWN_FINISHED(src, detonation_cooldown)) - . += SPAN_WARNING("The processors are currently cooling, [COOLDOWN_TIMELEFT(src, detonation_cooldown)/10] seconds remaining") /obj/structure/machinery/computer/demo_sim/attackby(obj/item/B, mob/living/user) if(inoperable()) @@ -82,9 +28,14 @@ /obj/structure/machinery/computer/demo_sim/attack_hand(mob/user as mob) if(..()) return + tgui_interact(user) -// TGUI SHIT \\ +/obj/structure/machinery/computer/demo_sim/Initialize() + . = ..() + simulation = new() + +// DEMOLITIONS TGUI SHIT \\ /obj/structure/machinery/computer/demo_sim/tgui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -104,12 +55,12 @@ var/list/data = list() data["configuration"] = configuration - data["looking"] = looking_at_simulation - data["dummy_mode"] = dummy_mode + data["looking"] = simulation.looking_at_simulation + data["dummy_mode"] = simulation.dummy_mode data["worldtime"] = world.time - data["nextdetonationtime"] = detonation_cooldown - data["detonation_cooldown"] = detonation_cooldown_time + data["nextdetonationtime"] = simulation.detonation_cooldown + data["detonation_cooldown"] = simulation.detonation_cooldown_time return data @@ -118,13 +69,15 @@ if(.) return + var/user = ui.user + switch(action) if("start_watching") - start_watching(usr) + simulation.start_watching(user) . = TRUE if("stop_watching") - stop_watching(usr) + simulation.stop_watching(user) . = TRUE if("eject") @@ -132,70 +85,33 @@ configuration.forceMove(loc) configuration = null else - to_chat(usr, SPAN_NOTICE("Nothing to eject.")) + to_chat(user, SPAN_NOTICE("Nothing to eject.")) . = TRUE if("detonate") if(!configuration) - to_chat(usr, SPAN_NOTICE("No configuration set.")) + to_chat(user, SPAN_NOTICE("No configuration set.")) return - simulate_detonation(usr) + simulate_detonation(user) . = TRUE if("switchmode") - dummy_mode = tgui_input_list(usr, "Select target type to simulate", "Target type", target_types, 30 SECONDS) - if(!dummy_mode) - dummy_mode = HUMAN_MODE + simulation.dummy_mode = tgui_input_list(user, "Select target type to simulate", "Target type", simulation.target_types, 30 SECONDS) + if(!simulation.dummy_mode) + simulation.dummy_mode = /mob/living/carbon/human . = TRUE /obj/structure/machinery/computer/demo_sim/ui_close(mob/user) + . = ..() - if(looking_at_simulation) - stop_watching(user) + if(simulation.looking_at_simulation) + simulation.stop_watching(user) -// TGUI SHIT END \\ +// DEMOLITIONS TGUI SHIT END \\ -/obj/structure/machinery/computer/demo_sim/proc/start_watching(mob/living/user) - if(!simulation) - simulation = SAFEPICK(GLOB.simulator_cameras) - if(!simulation) - to_chat(user, SPAN_WARNING("GPU damaged! Unable to start simulation.")) - return - if(user.client.view != world_view_size) - to_chat(user, SPAN_WARNING("You're too busy looking at something else.")) - return - user.reset_view(simulation) - looking_at_simulation = TRUE - -/obj/structure/machinery/computer/demo_sim/proc/stop_watching(mob/living/user) - user.unset_interaction() - user.reset_view(null) - user.cameraFollow = null - looking_at_simulation = FALSE /obj/structure/machinery/computer/demo_sim/proc/simulate_detonation(mob/living/user) - COOLDOWN_START(src, detonation_cooldown, detonation_cooldown_time) - - var/spawn_path = target_types[dummy_mode] - var/spawning_humans = FALSE - if(dummy_mode == HUMAN_MODE || dummy_mode == CLF_MODE || dummy_mode == UPP_MODE) - spawning_humans = TRUE - - for(var/spawn_loc in GLOB.simulator_targets) - if(spawning_humans) - var/mob/living/carbon/human/dummy = new /mob/living/carbon/human(get_turf(spawn_loc)) - switch(dummy_mode) - if(CLF_MODE) - user.client.cmd_admin_dress_human(dummy, "CLF Soldier", no_logs = TRUE) - if(UPP_MODE) - user.client.cmd_admin_dress_human(dummy, "UPP Conscript", no_logs = TRUE) - dummy.name = "simulated human" - QDEL_IN(dummy, detonation_cooldown_time - 10 SECONDS) - else - var/mob/living/carbon/xenomorph/xeno_dummy = new spawn_path(get_turf(spawn_loc)) - xeno_dummy.hardcore = TRUE - QDEL_IN(xeno_dummy, detonation_cooldown_time - 10 SECONDS) - + simulation.spawn_mobs(user) //Simply an explosive if(istype(configuration,/obj/item/explosive)) make_and_prime_explosive(configuration) @@ -206,8 +122,8 @@ if(O.warhead) make_and_prime_explosive(O.warhead) else - var/obj/item/mortar_shell/O = new configuration.type(simulation.loc) - O.detonate(simulation.loc) + var/obj/item/mortar_shell/O = new configuration.type(get_turf(simulation.sim_camera)) + O.detonate(get_turf(simulation.sim_camera)) //Rockets (custom only because projectiles are spaghetti) else if(istype(configuration,/obj/item/ammo_magazine/rocket/custom)) var/obj/item/ammo_magazine/rocket/custom/O = configuration @@ -215,9 +131,9 @@ make_and_prime_explosive(O.warhead) /obj/structure/machinery/computer/demo_sim/proc/make_and_prime_explosive(obj/item/explosive/O) - var/obj/item/explosive/E = new O.type(simulation.loc) + var/obj/item/explosive/E = new O.type(get_turf(simulation.sim_camera)) E.make_copy_of(O) E.prime(TRUE) - var/turf/sourceturf = get_turf(simulation) - sourceturf.chemexploded = FALSE //Make sure that this actually resets + sim_location = get_turf(simulation.sim_camera) + sim_location.chemexploded = FALSE //Make sure that this actually resets QDEL_IN(E,1 MINUTES) diff --git a/code/game/machinery/computer/dropship_weapons.dm b/code/game/machinery/computer/dropship_weapons.dm index 788d07523b6f..60bf17388db8 100644 --- a/code/game/machinery/computer/dropship_weapons.dm +++ b/code/game/machinery/computer/dropship_weapons.dm @@ -1,7 +1,6 @@ - /obj/structure/machinery/computer/dropship_weapons name = "abstract dropship weapons controls" - desc = "A computer to manage equipment and weapons installed on the dropship." + desc = "A computer to manage equipment, weapons and simulations installed on the dropship." density = TRUE icon = 'icons/obj/structures/machinery/shuttle-parts.dmi' icon_state = "consoleright" @@ -23,7 +22,12 @@ var/matrixcol //color of matrix, only used when we upgrade to nv var/power //level of the property var/datum/cas_signal/selected_cas_signal + var/datum/simulator/simulation + var/datum/cas_fire_mission/configuration +/obj/structure/machinery/computer/dropship_weapons/Initialize() + . = ..() + simulation = new() /obj/structure/machinery/computer/dropship_weapons/New() ..() @@ -34,7 +38,15 @@ if(..()) return if(!allowed(user)) - to_chat(user, SPAN_WARNING("Access denied.")) + + // everyone can access the simulator, requested feature. + to_chat(user, SPAN_WARNING("Weapons modification access denied, attempting to launch simulation.")) + + if(!selected_firemission) + to_chat(usr, SPAN_WARNING("Firemission must be selected before attempting to run the simulation")) + return + + tgui_interact(user) return 1 user.set_interaction(src) @@ -415,6 +427,16 @@ return in_firemission_mode = TRUE + if(href_list["switch_to_simulation"]) + if(!selected_firemission) + to_chat(usr, SPAN_WARNING("Select a firemission before attempting to run the simulation")) + return + + configuration = selected_firemission + + // simulation mode + tgui_interact(usr) + if(href_list["leave_firemission_execution"]) var/mob/M = usr if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons. @@ -690,7 +712,7 @@ /obj/structure/machinery/computer/dropship_weapons/dropship1 name = "\improper 'Alamo' weapons controls" - req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_WY_FLIGHT) firemission_envelope = new /datum/cas_fire_envelope/uscm_dropship() /obj/structure/machinery/computer/dropship_weapons/dropship1/New() @@ -699,9 +721,105 @@ /obj/structure/machinery/computer/dropship_weapons/dropship2 name = "\improper 'Normandy' weapons controls" - req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_WY_FLIGHT) firemission_envelope = new /datum/cas_fire_envelope/uscm_dropship() /obj/structure/machinery/computer/dropship_weapons/dropship2/New() ..() shuttle_tag = DROPSHIP_NORMANDY + +/obj/structure/machinery/computer/dropship_weapons/Destroy() + . = ..() + + QDEL_NULL(firemission_envelope) + +// CAS TGUI SHIT \\ + +/obj/structure/machinery/computer/dropship_weapons/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CasSim", "[src.name]") + ui.open() + +/obj/structure/machinery/computer/dropship_weapons/ui_state(mob/user) // we gotta do custom shit here so that it always closes instead of suspending + return GLOB.not_incapacitated_and_adjacent_strict_state + +/obj/structure/machinery/computer/dropship_weapons/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(inoperable()) + return UI_CLOSE + +/obj/structure/machinery/computer/dropship_weapons/ui_data(mob/user) + var/list/data = list() + + data["configuration"] = configuration + data["looking"] = simulation.looking_at_simulation + data["dummy_mode"] = simulation.dummy_mode + + data["worldtime"] = world.time + data["nextdetonationtime"] = simulation.detonation_cooldown + data["detonation_cooldown"] = simulation.detonation_cooldown_time + + return data + +/obj/structure/machinery/computer/dropship_weapons/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/user = ui.user + + switch(action) + if("start_watching") + simulation.start_watching(user) + . = TRUE + + if("stop_watching") + simulation.stop_watching(user) + . = TRUE + + if("execute_simulated_firemission") + if(!configuration) + to_chat(user, SPAN_WARNING("No configured firemission")) + return + simulate_firemission(user) + . = TRUE + + if("switch_firemission") + configuration = tgui_input_list(user, "Select firemission to simulate", "Select firemission", firemission_envelope.missions, 30 SECONDS) + if(!selected_firemission) + to_chat(user, SPAN_WARNING("No configured firemission")) + return + if(!configuration) + configuration = selected_firemission + . = TRUE + + if("switchmode") + simulation.dummy_mode = tgui_input_list(user, "Select target type to simulate", "Target type", simulation.target_types, 30 SECONDS) + if(!simulation.dummy_mode) + simulation.dummy_mode = CLF_MODE + . = TRUE + +/obj/structure/machinery/computer/dropship_weapons/ui_close(mob/user) + . = ..() + if(simulation.looking_at_simulation) + simulation.stop_watching(user) + +// CAS TGUI SHIT END \\ + +/obj/structure/machinery/computer/dropship_weapons/proc/simulate_firemission(mob/living/user) + + if(!configuration) + to_chat(user, SPAN_WARNING("Configure a firemission before attempting to run the simulation")) + return + if(configuration.check(src) != FIRE_MISSION_ALL_GOOD) + to_chat(user, SPAN_WARNING("Configured firemission has errors, fix the errors before attempting to run the simulation")) + return + + simulation.spawn_mobs(user) + + if(!simulation.sim_camera) + to_chat(user, SPAN_WARNING("The simulator has malfunctioned!")) + + //acutal firemission + configuration.simulate_execute_firemission(src, get_turf(simulation.sim_camera), user) diff --git a/code/game/machinery/computer/groundside_operations.dm b/code/game/machinery/computer/groundside_operations.dm index 234852539226..9856ae8f970e 100644 --- a/code/game/machinery/computer/groundside_operations.dm +++ b/code/game/machinery/computer/groundside_operations.dm @@ -273,16 +273,20 @@ to_chat(usr, "[icon2html(src, usr)] [SPAN_WARNING("Searching for helmet cam. No helmet cam found for this marine! Tell your squad to put their helmets on!")]") else if(cam && cam == new_cam)//click the camera you're watching a second time to stop watching. visible_message("[icon2html(src, viewers(src))] [SPAN_BOLDNOTICE("Stopping helmet cam view of [cam_target].")]") + usr.UnregisterSignal(cam, COMSIG_PARENT_QDELETING) cam = null usr.reset_view(null) else if(usr.client.view != world_view_size) to_chat(usr, SPAN_WARNING("You're too busy peering through binoculars.")) else + if(cam) + usr.UnregisterSignal(cam, COMSIG_PARENT_QDELETING) cam = new_cam usr.reset_view(cam) + usr.RegisterSignal(cam, COMSIG_PARENT_QDELETING, TYPE_PROC_REF(/mob, reset_observer_view_on_deletion)) if("activate_echo") - var/reason = input(usr, "What is the purpose of Echo Squad?", "Activation Reason") + var/reason = strip_html(input(usr, "What is the purpose of Echo Squad?", "Activation Reason")) if(!reason) return if(alert(usr, "Confirm activation of Echo Squad for [reason]", "Confirm Activation", "Yes", "No") != "Yes") return @@ -306,6 +310,8 @@ ..() if(!isRemoteControlling(user)) + if(cam) + user.UnregisterSignal(cam, COMSIG_PARENT_QDELETING) cam = null user.reset_view(null) diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 7d82c5bd9a75..b68ca41d6f09 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -5,7 +5,7 @@ desc = "This can be used to check medical records." icon_state = "medcomp" density = TRUE - req_one_access = list(ACCESS_MARINE_MEDBAY, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_MARINE_MEDBAY, ACCESS_WY_MEDICAL) circuit = /obj/item/circuitboard/computer/med_data var/obj/item/card/id/scan = null var/last_user_name = "" @@ -469,9 +469,10 @@ if(!record) return playsound(src.loc, 'sound/machines/fax.ogg', 15, 1) sleep(40) + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) var/obj/item/paper/P = new /obj/item/paper( src.loc ) P.name = text("Scan: [], []",record.fields["name"],worldtime2text()) - P.info += text("

Official Weyland-Yutani Document
Scan Record

[]

\n
",record.fields["name"]) + P.info += text("

Official Weyland-Yutani Document
Scan Record

[]

\n
",record.fields["name"]) for(var/datum/data/record/R as anything in GLOB.data_core.medical) if (R.fields["name"] == record.fields["name"]) if(R.fields["last_scan_time"] && R.fields["last_scan_result"]) diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm index b7f79d50caef..3858230a089c 100644 --- a/code/game/machinery/computer/pod.dm +++ b/code/game/machinery/computer/pod.dm @@ -136,15 +136,13 @@ /obj/structure/machinery/computer/pod/old - icon_state = "old" name = "DoorMex Control Computer" title = "Door Controls" - - /obj/structure/machinery/computer/pod/old/syndicate name = "ProComp Executive IIc" desc = "The Syndicate operate on a tight budget. Operates external airlocks." + icon_state = "syndicomp" title = "External Airlock Controls" req_access = list(ACCESS_ILLEGAL_PIRATE) @@ -157,4 +155,5 @@ /obj/structure/machinery/computer/pod/old/swf name = "Magix System IV" + icon_state = "wizard" desc = "An arcane artifact that holds much magic. Running E-Knock 2.2: Sorceror's Edition" diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 0288b7eb2426..357ef48fff37 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -114,7 +114,7 @@ A.amount = 5 if(CONSTRUCTION_STATE_FINISHED) - if(istype(P, /obj/item/tool/crowbar)) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR)) if(!skillcheck(user, SKILL_ENGINEER, required_dismantle_skill)) to_chat(user, SPAN_WARNING("You are not trained to dismantle machines...")) return diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index 296493cabcac..afcc9686cff5 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -2,6 +2,7 @@ /obj/structure/machinery/cryo_cell name = "cryo cell" + desc = "A donation from the old A.W. project, using cryogenic technology. It slowly heals whoever is inside the tube." icon = 'icons/obj/structures/machinery/cryogenics2.dmi' icon_state = "cell" density = FALSE @@ -160,7 +161,7 @@ for(var/datum/reagent/R in beaker.reagents.reagent_list) reagentnames += ";[R.name]" - msg_admin_niche("[key_name(user)] put \a [beaker] into \the [src], containing [reagentnames] at ([src.loc.x],[src.loc.y],[src.loc.z]) (JMP).", 1) + msg_admin_niche("[key_name(user)] put \a [beaker] into \the [src], containing [reagentnames] at ([src.loc.x],[src.loc.y],[src.loc.z]) [ADMIN_JMP(src.loc)].", 1) if(user.drop_inv_item_to_loc(W, src)) user.visible_message("[user] adds \a [W] to \the [src]!", "You add \a [W] to \the [src]!") diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 5ba958ad95fe..ed7335ea8778 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -185,6 +185,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li flags_atom |= USES_HEARING /obj/structure/machinery/cryopod/Destroy() + SetLuminosity(0) QDEL_NULL(occupant) QDEL_NULL(announce) . = ..() @@ -192,7 +193,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li //Lifted from Unity stasis.dm and refactored. ~Zuhayr /obj/structure/machinery/cryopod/process() - if(occupant) + if(occupant && !(WEAKREF(occupant) in GLOB.freed_mob_list)) //ignore freed mobs //if occupant ghosted, time till despawn is severely shorter if(!occupant.key && time_till_despawn == 10 MINUTES) time_till_despawn -= 8 MINUTES @@ -367,6 +368,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li qdel(G) icon_state = "body_scanner_open" + SetLuminosity(0) if(occupant.key) occupant.ghostize(0) @@ -501,22 +503,25 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li add_fingerprint(usr) -/obj/structure/machinery/cryopod/proc/go_in_cryopod(mob/M, silent = FALSE) +/obj/structure/machinery/cryopod/proc/go_in_cryopod(mob/mob, silent = FALSE) if(occupant) return - M.forceMove(src) - occupant = M + mob.forceMove(src) + occupant = mob icon_state = "body_scanner_closed" + SetLuminosity(2) time_entered = world.time start_processing() if(!silent) - if(M.client) - to_chat(M, SPAN_NOTICE("You feel cool air surround you. You go numb as your senses turn inward.")) - to_chat(M, SPAN_BOLDNOTICE("If you log out or close your client now, your character will permanently removed from the round in 10 minutes. If you ghost, timer will be decreased to 2 minutes.")) + if(mob.client) + to_chat(mob, SPAN_NOTICE("You feel cool air surround you. You go numb as your senses turn inward.")) + to_chat(mob, SPAN_BOLDNOTICE("If you log out or close your client now, your character will permanently removed from the round in 10 minutes. If you ghost, timer will be decreased to 2 minutes.")) + if(!is_admin_level(src.z)) // Set their queue time now because the client has to actually leave to despawn and at that point the client is lost + mob.client.player_details.larva_queue_time = max(mob.client.player_details.larva_queue_time, world.time) var/area/location = get_area(src) - if(M.job != GET_MAPPED_ROLE(JOB_SQUAD_MARINE)) - message_admins("[key_name_admin(M)], [M.job], has entered \a [src] at [location] after playing for [duration2text(world.time - M.life_time_start)].") + if(mob.job != GET_MAPPED_ROLE(JOB_SQUAD_MARINE)) + message_admins("[key_name_admin(mob)], [mob.job], has entered \a [src] at [location] after playing for [duration2text(world.time - mob.life_time_start)].") playsound(src, 'sound/machines/hydraulics_3.ogg', 30) silent_exit = silent @@ -527,6 +532,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li occupant = null stop_processing() icon_state = "body_scanner_open" + SetLuminosity(0) playsound(src, 'sound/machines/pod_open.ogg', 30) #ifdef OBJECTS_PROXY_SPEECH diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index 0f1058d59016..8be8609d6008 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -52,6 +52,11 @@ /obj/structure/machinery/door_control/attackby(obj/item/W, mob/user as mob) return src.attack_hand(user) +/obj/structure/machinery/door_control/ex_act(severity) + if(indestructible) + return FALSE + ..() + /obj/structure/machinery/door_control/proc/handle_dropship(ship_id) var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(ship_id) if (!istype(shuttle)) @@ -270,5 +275,3 @@ desiredstate = !desiredstate -/obj/structure/machinery/door_control/power_change() - return diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index e310ce2966b1..e3e5fd3bee87 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -22,7 +22,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( /obj/structure/machinery/door/airlock name = "airlock" - icon = 'icons/obj/structures/doors/Doorint.dmi' + icon = 'icons/obj/structures/doors/Door1.dmi' icon_state = "door_closed" power_channel = POWER_CHANNEL_ENVIRON @@ -551,6 +551,9 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( update_icon() /obj/structure/machinery/door/airlock/attackby(obj/item/C, mob/user) + if(SEND_SIGNAL(C, COMSIG_ITEM_ATTACK_AIRLOCK, src, user) & COMPONENT_CANCEL_AIRLOCK_ATTACK) + return + if(istype(C, /obj/item/clothing/mask/cigarette)) if(isElectrified()) var/obj/item/clothing/mask/cigarette/L = C @@ -606,32 +609,6 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( update_icon() return - if(istype(C, /obj/item/maintenance_jack) && locked) - var/obj/item/maintenance_jack/current_jack = C - - if(current_jack.crowbar_mode) - return - - if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_MASTER)) //Engi 3 is much faster - user.visible_message(SPAN_DANGER("[user] begins to search for [src]'s bolts!"),\ - SPAN_NOTICE("You search for [src]'s bolts.")) - if(!do_after(user, 15 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE, src, INTERRUPT_ALL)) //Otherwise it takes an extra 15 seconds - to_chat(user, SPAN_WARNING("You fail to find the bolts on [src].")) - return - - user.visible_message(SPAN_DANGER("[user] begins to disable [src]'s bolts!"),\ - SPAN_NOTICE("You start to disable [src]'s bolts.")) - playsound(src, "pry", 25, TRUE) - - if(!do_after(user, 5 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE, src, INTERRUPT_ALL)) - to_chat(user, SPAN_WARNING("You decide not to disable the bolts on [src].")) - return - - user.visible_message(SPAN_DANGER("[user] disables the bolts on [src]."),\ - SPAN_NOTICE("You unbolt [src].")) - unlock(TRUE) - return - else if(HAS_TRAIT(C, TRAIT_TOOL_SCREWDRIVER)) if(no_panel) to_chat(user, SPAN_WARNING("\The [src] has no panel to open!")) @@ -763,7 +740,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( closeOther.close() return ..(forced) -/obj/structure/machinery/door/airlock/close(forced=0) +/obj/structure/machinery/door/airlock/close(forced = FALSE) if(operating || welded || locked || !loc) return if(!forced) @@ -809,12 +786,12 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( ..() return -/obj/structure/machinery/door/airlock/proc/lock(forced=0) +/obj/structure/machinery/door/airlock/proc/lock(forced = FALSE) if((operating && !forced) || locked) return playsound(loc, 'sound/machines/hydraulics_1.ogg', 25) - locked = 1 + locked = TRUE visible_message(SPAN_NOTICE("\The [src] airlock emits a loud thunk, then a click.")) update_icon() @@ -822,7 +799,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( if(operating || !locked) return if(forced || (arePowerSystemsOn())) //only can raise bolts if power's on - locked = 0 + locked = FALSE playsound(loc, 'sound/machines/hydraulics_2.ogg', 25) visible_message(SPAN_NOTICE("\The [src] airlock emits a click, then hums slightly.")) diff --git a/code/game/machinery/doors/airlock_control.dm b/code/game/machinery/doors/airlock_control.dm index 068f9e3906b4..57e27cc60d91 100644 --- a/code/game/machinery/doors/airlock_control.dm +++ b/code/game/machinery/doors/airlock_control.dm @@ -218,7 +218,7 @@ /obj/structure/machinery/airlock_sensor/Destroy() stop_processing() SSradio.remove_object(src, frequency) - QDEL_NULL(radio_connection) + radio_connection = null return ..() /obj/structure/machinery/airlock_sensor/airlock_interior @@ -284,7 +284,7 @@ /obj/structure/machinery/access_button/Destroy() SSradio.remove_object(src, frequency) - QDEL_NULL(radio_connection) + radio_connection = null return ..() /obj/structure/machinery/access_button/airlock_interior diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index 09193fde7ff3..f4d09796194c 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -10,32 +10,32 @@ name = "\improper Command Airlock" icon = 'icons/obj/structures/doors/comdoor.dmi' assembly_type = /obj/structure/airlock_assembly/airlock_assembly_com - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/security/colony name = "\improper Security Airlock" icon = 'icons/obj/structures/doors/secdoor.dmi' assembly_type = /obj/structure/airlock_assembly/airlock_assembly_sec - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_SECURITY) /obj/structure/machinery/door/airlock/engineering/colony name = "\improper Engineering Airlock" icon = 'icons/obj/structures/doors/engidoor.dmi' assembly_type = /obj/structure/airlock_assembly/airlock_assembly_eng - req_one_access = list(ACCESS_CIVILIAN_COMMAND, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS) + req_one_access = list(ACCESS_CIVILIAN_COMMAND, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/medical/colony name = "\improper Medical Airlock" icon = 'icons/obj/structures/doors/medidoor.dmi' assembly_type = /obj/structure/airlock_assembly/airlock_assembly_med - req_one_access = list(ACCESS_CIVILIAN_MEDBAY, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND) + req_one_access = list(ACCESS_CIVILIAN_MEDBAY, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/maintenance/colony name = "\improper Maintenance Hatch" icon = 'icons/obj/structures/doors/maintdoor.dmi' assembly_type = /obj/structure/airlock_assembly/airlock_assembly_mai - req_one_access = list(ACCESS_CIVILIAN_PUBLIC) + req_one_access = list(ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_ENGINEERING, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/external/colony name = "\improper External Airlock" @@ -61,7 +61,7 @@ icon = 'icons/obj/structures/doors/vault.dmi' opacity = TRUE assembly_type = /obj/structure/airlock_assembly/airlock_assembly_highsecurity //Until somebody makes better sprites. - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_LEADERSHIP) /obj/structure/machinery/door/airlock/freezer/colony name = "\improper Freezer Airlock" @@ -83,7 +83,7 @@ opacity = FALSE assembly_type = /obj/structure/airlock_assembly/airlock_assembly_com glass = 1 - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/glass_engineering/colony name = "\improper Engineering Airlock" @@ -130,7 +130,7 @@ name = "\improper Research Airlock" icon = 'icons/obj/structures/doors/medidoor.dmi' assembly_type = /obj/structure/airlock_assembly/airlock_assembly_research - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/glass_research/colony name = "\improper Research Airlock" @@ -139,7 +139,7 @@ assembly_type = /obj/structure/airlock_assembly/airlock_assembly_research glass = 1 heat_proof = 1 - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/glass_mining/colony name = "\improper Mining Airlock" @@ -214,7 +214,7 @@ name = "\improper Research Airlock" icon = 'icons/obj/structures/doors/medidoor.dmi' assembly_type = /obj/structure/airlock_assembly/airlock_assembly_science - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_RESEARCH) /obj/structure/machinery/door/airlock/glass_science/colony name = "\improper Research Airlock" @@ -222,13 +222,13 @@ opacity = 0 assembly_type = /obj/structure/airlock_assembly/airlock_assembly_science glass = 1 - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_RESEARCH) /obj/structure/machinery/door/airlock/highsecurity/colony name = "\improper High Tech Security Airlock" icon = 'icons/obj/structures/doors/hightechsecurity.dmi' assembly_type = /obj/structure/airlock_assembly/airlock_assembly_highsecurity - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_SECURITY, ACCESS_WY_LEADERSHIP) //STRATA AIRLOCKS // Add me later y'know? @@ -267,6 +267,36 @@ /obj/structure/machinery/door/airlock/strata/mining/autoname autoname = TRUE +//YAUTJA SHIP - CURRENTLY USES STRATA DOORS +/obj/structure/machinery/door/airlock/yautja + name = "\improper Airlock" + icon = 'icons/obj/structures/doors/strata/strata_doors.dmi' + openspeed = 5 + req_access = null + req_one_access = null + tiles_with = list( + /obj/structure/window/framed/strata, + /obj/structure/machinery/door/airlock, + ) + masterkey_resist = TRUE + no_panel = TRUE + not_weldable = TRUE + unacidable = TRUE + +/obj/structure/machinery/door/airlock/yautja/autoname + autoname = TRUE + +/obj/structure/machinery/door/airlock/yautja/secure + heavy = TRUE + req_one_access = list(ACCESS_YAUTJA_SECURE, ACCESS_YAUTJA_ELDER, ACCESS_YAUTJA_ANCIENT) + +/obj/structure/machinery/door/airlock/yautja/secure/elder + req_one_access = list(ACCESS_YAUTJA_ELDER, ACCESS_YAUTJA_ANCIENT) + +/obj/structure/machinery/door/airlock/yautja/secure/ancient + req_one_access = list(ACCESS_YAUTJA_ANCIENT) + unslashable = TRUE + //FIORINA PENITENTIARY (PRISON_FOP) MAINTENANCE HATCHES /obj/structure/machinery/door/airlock/prison_hatch @@ -362,7 +392,7 @@ /obj/structure/machinery/door/airlock/almayer/command/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/almayer/command/autoname autoname = TRUE @@ -373,7 +403,7 @@ /obj/structure/machinery/door/airlock/almayer/command/reinforced/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/almayer/secure name = "\improper Secure Airlock" @@ -491,11 +521,11 @@ /obj/structure/machinery/door/airlock/almayer/research name = "\improper Research Airlock" icon = 'icons/obj/structures/doors/medidoor.dmi' - req_access = list(ACCESS_MARINE_RESEARCH) + req_one_access = list(ACCESS_MARINE_RESEARCH, ACCESS_WY_RESEARCH, ACCESS_WY_EXEC) /obj/structure/machinery/door/airlock/almayer/research/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL, ACCESS_WY_RESEARCH) /obj/structure/machinery/door/airlock/almayer/research/autoname autoname = TRUE @@ -506,7 +536,7 @@ /obj/structure/machinery/door/airlock/almayer/research/reinforced/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL, ACCESS_WY_RESEARCH) /obj/structure/machinery/door/airlock/almayer/research/glass name = "\improper Research Airlock" @@ -517,7 +547,7 @@ /obj/structure/machinery/door/airlock/almayer/research/glass/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/almayer/research/glass/autoname autoname = TRUE @@ -528,7 +558,7 @@ /obj/structure/machinery/door/airlock/almayer/research/glass/reinforced/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/almayer/generic name = "\improper Airlock" @@ -546,7 +576,11 @@ /obj/structure/machinery/door/airlock/almayer/generic/corporate name = "Corporate Liaison's Quarters" icon = 'icons/obj/structures/doors/personaldoor.dmi' - req_access = list(ACCESS_WY_CORPORATE) + req_access = list(ACCESS_WY_GENERAL) + +/obj/structure/machinery/door/airlock/almayer/generic/press + name = "Press Office" + req_access = list(ACCESS_PRESS) /obj/structure/machinery/door/airlock/almayer/marine name = "\improper Airlock" @@ -761,30 +795,30 @@ opacity = FALSE glass = 1 -//RTO doors, yes this is stupid +//TL doors, yes this is stupid -/obj/structure/machinery/door/airlock/almayer/marine/alpha/rto - name = "\improper Alpha Squad Radio Telephone Operator Preparations" +/obj/structure/machinery/door/airlock/almayer/marine/alpha/tl + name = "\improper Alpha Squad Fireteam Leader Preparations" req_access = list() - req_one_access = list(ACCESS_MARINE_RTO_PREP) + req_one_access = list(ACCESS_MARINE_TL_PREP) dir = SOUTH -/obj/structure/machinery/door/airlock/almayer/marine/bravo/rto - name = "\improper Bravo Squad Radio Telephone Operator Preparations" +/obj/structure/machinery/door/airlock/almayer/marine/bravo/tl + name = "\improper Bravo Squad Fireteam Leader Preparations" req_access = list() - req_one_access = list(ACCESS_MARINE_RTO_PREP) + req_one_access = list(ACCESS_MARINE_TL_PREP) dir = SOUTH -/obj/structure/machinery/door/airlock/almayer/marine/charlie/rto - name = "\improper Charlie Squad Radio Telephone Operator Preparations" +/obj/structure/machinery/door/airlock/almayer/marine/charlie/tl + name = "\improper Charlie Squad Fireteam Leader Preparations" req_access = list() - req_one_access = list(ACCESS_MARINE_RTO_PREP) + req_one_access = list(ACCESS_MARINE_TL_PREP) dir = SOUTH -/obj/structure/machinery/door/airlock/almayer/marine/delta/rto - name = "\improper Delta Squad Radio Telephone Operator Preparations" +/obj/structure/machinery/door/airlock/almayer/marine/delta/tl + name = "\improper Delta Squad Fireteam Leader Preparations" req_access = list() - req_one_access = list(ACCESS_MARINE_RTO_PREP) + req_one_access = list(ACCESS_MARINE_TL_PREP) dir = SOUTH //SQUAD PREP SHARED DOORS diff --git a/code/game/machinery/doors/brig_system.dm b/code/game/machinery/doors/brig_system.dm index baae8171e874..58c3282abed4 100644 --- a/code/game/machinery/doors/brig_system.dm +++ b/code/game/machinery/doors/brig_system.dm @@ -177,7 +177,7 @@ viewed_report.incident.status |= BRIG_SENTENCE_PARDONED viewed_report.name += " (PARDONED)" - message_admins("[key_name(user, 1)](JMP) has pardoned [viewed_report.incident.criminal_name].") + message_admins("[key_name(user, 1)][ADMIN_JMP_USER(user)] has pardoned [viewed_report.incident.criminal_name].") log_admin("[key_name(user)] pardoned [viewed_report.incident.criminal_name] for [viewed_report.incident.charges_to_string()].") ai_silent_announcement("BRIG REPORT: [viewed_report.incident.criminal_name] has been pardoned for [viewed_report.incident.charges_to_string()].") @@ -227,7 +227,7 @@ incident.status &= ~BRIG_SENTENCE_ACTIVE incident.time_served = (incident.brig_sentence * 600) - (incident.time_to_release - REALTIMEOFDAY) - message_admins("[key_name(user, 1)](JMP) has paused the jail timer of [incident.criminal_name].") + message_admins("[key_name(user, 1)][ADMIN_JMP_USER(user)] has paused the jail timer of [incident.criminal_name].") log_admin("[key_name(user)] paused the jail timer of [incident.criminal_name], [incident.charges_to_string()].") active_report = null @@ -246,7 +246,7 @@ incident.status |= BRIG_SENTENCE_SERVED if (user) - message_admins("[key_name(user, 1)](JMP) has prematurely ended the jail timer of [incident.criminal_name].") + message_admins("[key_name(user, 1)][ADMIN_JMP_USER(user)] has prematurely ended the jail timer of [incident.criminal_name].") log_admin("[key_name(user)] prematurely ended the jail timer of [incident.criminal_name], [incident.charges_to_string()].") active_report = null @@ -266,7 +266,7 @@ incident.status &= ~BRIG_SENTENCE_PARDONED incident.status &= ~BRIG_SENTENCE_SERVED - message_admins("[key_name(user, 1)](JMP) has reset the jail timer of [incident.criminal_name].") + message_admins("[key_name(user, 1)][ADMIN_JMP_USER(user)] has reset the jail timer of [incident.criminal_name].") log_admin("[key_name(user)] reset the jail timer of [incident.criminal_name], [incident.charges_to_string()].") ai_silent_announcement("BRIG REPORT: [incident.criminal_name] had their jail time reset by [user].", ":p") diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 4a206f389027..b54658b24245 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -2,7 +2,7 @@ /obj/structure/machinery/door name = "\improper Door" desc = "It opens and closes." - icon = 'icons/obj/structures/doors/Doorint.dmi' + icon = 'icons/obj/structures/doors/Door1.dmi' icon_state = "door1" anchored = TRUE opacity = TRUE @@ -247,7 +247,6 @@ return FALSE operating = TRUE - CHECK_TICK src.density = TRUE src.layer = closed_layer do_animate("closing") diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm index ee30af72558e..2a49b8696a9f 100644 --- a/code/game/machinery/doors/multi_tile.dm +++ b/code/game/machinery/doors/multi_tile.dm @@ -39,7 +39,7 @@ /obj/structure/machinery/door/airlock/multi_tile/command/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/multi_tile/medical name = "Medical Airlock" @@ -69,7 +69,7 @@ /obj/structure/machinery/door/airlock/multi_tile/research/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/multi_tile/research/reinforced name = "Reinforced Research Airlock" @@ -77,7 +77,7 @@ /obj/structure/machinery/door/airlock/multi_tile/research/reinforced/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/multi_tile/secure name = "Secure Airlock" @@ -183,7 +183,7 @@ /obj/structure/machinery/door/airlock/multi_tile/almayer/medidoor/research/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/multi_tile/almayer/comdoor name = "\improper Command Airlock" @@ -194,7 +194,7 @@ /obj/structure/machinery/door/airlock/multi_tile/almayer/comdoor/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/multi_tile/almayer/comdoor/reinforced name = "\improper Reinforced Command Airlock" @@ -202,7 +202,7 @@ /obj/structure/machinery/door/airlock/multi_tile/almayer/comdoor/reinforced/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/multi_tile/almayer/comdoor/solid icon = 'icons/obj/structures/doors/2x1comdoor_solid.dmi' @@ -211,7 +211,7 @@ /obj/structure/machinery/door/airlock/multi_tile/almayer/comdoor/solid/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/multi_tile/almayer/comdoor/solid/reinforced name = "\improper Reinforced Command Airlock" @@ -219,7 +219,7 @@ /obj/structure/machinery/door/airlock/multi_tile/almayer/comdoor/solid/reinforced/colony req_access = null - req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/multi_tile/almayer/handle_multidoor() if(!(width > 1)) return //Bubblewrap diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index 301957f4801a..da6137e5e8cb 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -3,7 +3,8 @@ name = "\improper Podlock" desc = "That looks like it doesn't open easily." icon = 'icons/obj/structures/doors/rapid_pdoor.dmi' - icon_state = "pdoor" + icon_state = "pdoor1" + var/base_icon_state = "pdoor" id = 1 dir = NORTH unslashable = TRUE @@ -22,9 +23,9 @@ /obj/structure/machinery/door/poddoor/update_icon() if(density) - icon_state = initial(icon_state) + "1" + icon_state = "[base_icon_state]1" else - icon_state = initial(icon_state) + "0" + icon_state = "[base_icon_state]0" /obj/structure/machinery/door/poddoor/Collided(atom/movable/AM) if(!density) @@ -39,8 +40,8 @@ if(density && (stat & NOPOWER) && !operating && !unacidable) spawn(0) operating = 1 - flick(initial(icon_state) + "c0", src) - icon_state = initial(icon_state) + "0" + flick("[base_icon_state]c0", src) + icon_state = "[base_icon_state]0" SetOpacity(0) sleep(15) density = FALSE @@ -72,54 +73,56 @@ return /obj/structure/machinery/door/poddoor/open() - if(operating == 1) //doors can still open when emag-disabled + if(operating) //doors can still open when emag-disabled return - if(!operating) //in case of emag - operating = 1 + + if(!opacity) + return TRUE + + operating = TRUE playsound(loc, 'sound/machines/blastdoor.ogg', 20, 0) - flick(initial(icon_state) + "c0", src) - icon_state = initial(icon_state) + "0" + flick("[base_icon_state]c0", src) + icon_state = "[base_icon_state]0" SetOpacity(0) - sleep(10) - layer = open_layer - density = FALSE - if(operating == 1) //emag again - operating = 0 - if(autoclose) - addtimer(CALLBACK(src, PROC_REF(autoclose)), 150) - return 1 + addtimer(CALLBACK(src, PROC_REF(finish_open)), openspeed) + return TRUE /obj/structure/machinery/door/poddoor/close() if(operating) return - operating = 1 + if(opacity == initial(opacity)) + return + + operating = TRUE playsound(loc, 'sound/machines/blastdoor.ogg', 20, 0) layer = closed_layer - flick(initial(icon_state) + "c1", src) - icon_state = initial(icon_state) + "1" + flick("[base_icon_state]c1", src) + icon_state = "[base_icon_state]1" density = TRUE SetOpacity(initial(opacity)) - sleep(10) - operating = 0 + addtimer(CALLBACK(src, PROC_REF(finish_close)), openspeed) return +/obj/structure/machinery/door/poddoor/finish_close() + operating = FALSE + /obj/structure/machinery/door/poddoor/two_tile/open() - if(operating == 1) //doors can still open when emag-disabled + if(operating) //doors can still open when emag-disabled return - if(!operating) //in case of emag - operating = 1 + + operating = TRUE start_opening() - sleep(10) - open_fully() - return 1 + + addtimer(CALLBACK(src, PROC_REF(open_fully)), openspeed) + return TRUE /obj/structure/machinery/door/poddoor/two_tile/proc/start_opening() - flick("pdoorc0", src) - icon_state = "pdoor0" + flick("[base_icon_state]c0", src) + icon_state = "[base_icon_state]0" SetOpacity(0) f1.SetOpacity(0) f2.SetOpacity(0) @@ -148,14 +151,13 @@ if(operating) return start_closing() - sleep(10) - close_fully() + addtimer(CALLBACK(src, PROC_REF(close_fully)), openspeed) return /obj/structure/machinery/door/poddoor/two_tile/proc/start_closing() operating = 1 - flick("pdoorc1", src) - icon_state = "pdoor1" + flick("[base_icon_state]c1", src) + icon_state = "[base_icon_state]1" density = TRUE f1.density = TRUE @@ -283,10 +285,15 @@ /obj/structure/machinery/door/poddoor/almayer/open density = FALSE /obj/structure/machinery/door/poddoor/almayer/blended - icon_state = "almayer_pdoor" - + icon_state = "almayer_pdoor1" + base_icon_state = "almayer_pdoor" +/obj/structure/machinery/door/poddoor/almayer/blended/open + density = FALSE /obj/structure/machinery/door/poddoor/almayer/blended/white - icon_state = "w_almayer_pdoor" + icon_state = "w_almayer_pdoor1" + base_icon_state = "w_almayer_pdoor" +/obj/structure/machinery/door/poddoor/almayer/blended/white/open + density = FALSE /obj/structure/machinery/door/poddoor/almayer/Initialize() . = ..() diff --git a/code/game/machinery/doors/railing.dm b/code/game/machinery/doors/railing.dm index 0147946761d3..8449d5d52256 100644 --- a/code/game/machinery/doors/railing.dm +++ b/code/game/machinery/doors/railing.dm @@ -19,7 +19,8 @@ . = ..() if(dir == SOUTH) closed_layer = ABOVE_MOB_LAYER - layer = closed_layer + if(density)//Allows preset-open to work + layer = closed_layer SetOpacity(initial(opacity)) @@ -35,29 +36,34 @@ PF.flags_can_pass_all = (PASS_OVER^PASS_OVER_FIRE)|PASS_CRUSHER_CHARGE /obj/structure/machinery/door/poddoor/railing/open() - if (operating == 1) //doors can still open when emag-disabled - return 0 - if(!operating) //in case of emag - operating = 1 + if(operating) //doors can still open when emag-disabled + return FALSE + + operating = TRUE flick("railingc0", src) icon_state = "railing0" layer = open_layer - sleep(12) + addtimer(CALLBACK(src, PROC_REF(finish_open)), 1.2 SECONDS) + return TRUE +/obj/structure/machinery/door/poddoor/railing/finish_open() density = FALSE - if(operating == 1) //emag again - operating = 0 - return 1 + if(operating) //emag again + operating = FALSE /obj/structure/machinery/door/poddoor/railing/close() - if (operating) - return 0 + if(operating) + return FALSE + density = TRUE - operating = 1 + operating = TRUE layer = closed_layer flick("railingc1", src) icon_state = "railing1" addtimer(VARSET_CALLBACK(src, operating, FALSE), 1.2 SECONDS) - return 1 + return TRUE + +/obj/structure/machinery/door/poddoor/railing/open + density = FALSE diff --git a/code/game/machinery/doors/runed_sandstone.dm b/code/game/machinery/doors/runed_sandstone.dm index 8939ba8ca368..d67398baa305 100644 --- a/code/game/machinery/doors/runed_sandstone.dm +++ b/code/game/machinery/doors/runed_sandstone.dm @@ -89,33 +89,34 @@ return FALSE -/obj/structure/machinery/door/airlock/sandstone/runed/open(forced=1) +/obj/structure/machinery/door/airlock/sandstone/runed/open(forced = TRUE) if(operating || welded || locked || !loc || !density) return FALSE if(!forced && !arePowerSystemsOn()) return FALSE + playsound(loc, 'sound/effects/runedsanddoor.ogg', 25, 0) visible_message(SPAN_NOTICE("\The [src] makes a loud grating sound as hidden workings pull it open.")) - - if(!operating) - operating = TRUE - CHECK_TICK + operating = TRUE do_animate("opening") icon_state = "door0" - src.SetOpacity(FALSE) - sleep(openspeed) - src.layer = open_layer - src.density = FALSE + SetOpacity(FALSE) + + addtimer(CALLBACK(src, PROC_REF(finish_open)), openspeed) + return + +/obj/structure/machinery/door/airlock/sandstone/runed/finish_open() + layer = open_layer + density = FALSE update_icon() SetOpacity(0) - if (filler) + if(filler) filler.SetOpacity(opacity) if(operating) operating = FALSE - return -/obj/structure/machinery/door/airlock/sandstone/runed/close(forced=1) +/obj/structure/machinery/door/airlock/sandstone/runed/close(forced = TRUE) if(operating || welded || locked || !loc || density) return if(safe) @@ -128,12 +129,15 @@ visible_message(SPAN_NOTICE("\The [src] makes a loud grating sound as hidden workings force it shut.")) operating = TRUE - CHECK_TICK - src.density = TRUE - src.SetOpacity(TRUE) - src.layer = closed_layer + density = TRUE + SetOpacity(TRUE) + layer = closed_layer do_animate("closing") - sleep(openspeed) + + addtimer(CALLBACK(src, PROC_REF(finish_close)), openspeed) + return + +/obj/structure/machinery/door/airlock/sandstone/runed/finish_close() update_icon() operating = FALSE @@ -150,7 +154,6 @@ var/obj/structure/window/killthis = (locate(/obj/structure/window) in turf) if(killthis) killthis.ex_act(EXPLOSION_THRESHOLD_LOW) - return /obj/structure/machinery/door/airlock/sandstone/runed/lock(forced=0) if(operating || locked) return diff --git a/code/game/machinery/doors/shutters.dm b/code/game/machinery/doors/shutters.dm index d9ecb56939cf..39ecbd806e64 100644 --- a/code/game/machinery/doors/shutters.dm +++ b/code/game/machinery/doors/shutters.dm @@ -1,7 +1,8 @@ /obj/structure/machinery/door/poddoor/shutters name = "\improper Shutters" icon = 'icons/obj/structures/doors/rapid_pdoor.dmi' - icon_state = "shutter" + icon_state = "shutter1" + base_icon_state = "shutter" power_channel = POWER_CHANNEL_ENVIRON /obj/structure/machinery/door/poddoor/shutters/opened @@ -9,9 +10,9 @@ /obj/structure/machinery/door/poddoor/shutters/update_icon() if(density) - icon_state = "shutter1" + icon_state = "[base_icon_state]1" else - icon_state = "shutter0" + icon_state = "[base_icon_state]0" return /obj/structure/machinery/door/poddoor/shutters/attackby(obj/item/C as obj, mob/user as mob) @@ -21,8 +22,8 @@ if(density && (stat & NOPOWER) && !operating && !unacidable) operating = 1 spawn(-1) - flick("shutterc0", src) - icon_state = "shutter0" + flick("[base_icon_state]c0", src) + icon_state = "[base_icon_state]0" sleep(15) density = FALSE SetOpacity(0) @@ -31,40 +32,46 @@ return /obj/structure/machinery/door/poddoor/shutters/open() - if(operating == 1) //doors can still open when emag-disabled + if(operating) //doors can still open when emag-disabled return - if(!operating) //in case of emag - operating = 1 - flick("shutterc0", src) - icon_state = "shutter0" + + operating = TRUE + flick("[base_icon_state]c0", src) + icon_state = "[base_icon_state]0" playsound(loc, 'sound/machines/blastdoor.ogg', 25) - sleep(10) + + addtimer(CALLBACK(src, PROC_REF(finish_open)), openspeed) + return TRUE + +/obj/structure/machinery/door/poddoor/shutters/finish_open() density = FALSE layer = open_layer SetOpacity(0) - if(operating == 1) //emag again - operating = 0 + if(operating) //emag again + operating = FALSE if(autoclose) addtimer(CALLBACK(src, PROC_REF(autoclose)), 150) - return 1 /obj/structure/machinery/door/poddoor/shutters/close() if(operating) return - operating = 1 - flick("shutterc1", src) - icon_state = "shutter1" + + operating = TRUE + flick("[base_icon_state]c1", src) + icon_state = "[base_icon_state]1" layer = closed_layer density = TRUE if(visible) SetOpacity(1) playsound(loc, 'sound/machines/blastdoor.ogg', 25) - sleep(10) - operating = 0 + addtimer(CALLBACK(src, PROC_REF(finish_close)), openspeed) return +/obj/structure/machinery/door/poddoor/shutters/finish_close() + operating = FALSE + /obj/structure/machinery/door/poddoor/shutters/almayer icon = 'icons/obj/structures/doors/blastdoors_shutters.dmi' openspeed = 4 //shorter open animation. @@ -80,6 +87,17 @@ . = ..() relativewall_neighbours() +/obj/structure/machinery/door/poddoor/shutters/almayer/yautja + name = "Armory Shutter" + id = "Yautja Armory" + needs_power = FALSE + unacidable = TRUE + indestructible = TRUE + +/obj/structure/machinery/door/poddoor/shutters/almayer/yautja/Initialize() + . = ..() + RegisterSignal(SSdcs, COMSIG_GLOB_YAUTJA_ARMORY_OPENED, PROC_REF(open)) + /obj/structure/machinery/door/poddoor/shutters/almayer/containment unacidable = TRUE diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 19bdedd35765..e9006a9f2fb4 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -62,35 +62,38 @@ return /obj/structure/machinery/door/window/open() - if (src.operating == 1) //doors can still open when emag-disabled - return 0 - if(!src.operating) //in case of emag - src.operating = 1 - flick(text("[]opening", src.base_state), src) - playsound(src.loc, 'sound/machines/windowdoor.ogg', 25, 1) - src.icon_state = text("[]open", src.base_state) - sleep(10) - - src.density = FALSE - - if(operating == 1) //emag again - src.operating = 0 - return 1 + if(operating) //doors can still open when emag-disabled + return FALSE + + operating = TRUE + flick(text("[]opening", base_state), src) + playsound(loc, 'sound/machines/windowdoor.ogg', 25, 1) + icon_state = text("[]open", base_state) + + addtimer(CALLBACK(src, PROC_REF(finish_open)), openspeed) + return TRUE + +/obj/structure/machinery/door/window/finish_open() + density = FALSE + + if(operating) //emag again + operating = FALSE /obj/structure/machinery/door/window/close() - if (src.operating) - return 0 - src.operating = 1 - flick(text("[]closing", src.base_state), src) - playsound(src.loc, 'sound/machines/windowdoor.ogg', 25, 1) - src.icon_state = src.base_state + if (operating) + return FALSE - src.density = TRUE + operating = TRUE + flick(text("[]closing", src.base_state), src) + playsound(loc, 'sound/machines/windowdoor.ogg', 25, 1) + icon_state = base_state + density = TRUE - sleep(10) + addtimer(CALLBACK(src, PROC_REF(finish_close)), openspeed) + return TRUE - src.operating = 0 - return 1 +/obj/structure/machinery/door/window/finish_close() + operating = FALSE /obj/structure/machinery/door/window/proc/take_damage(damage) src.health = max(0, src.health - damage) @@ -164,7 +167,7 @@ return //If it's emagged, crowbar can pry electronics out. - if (src.operating == -1 && istype(I, /obj/item/tool/crowbar)) + if (src.operating == -1 && HAS_TRAIT(I, TRAIT_TOOL_CROWBAR)) playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) user.visible_message("[user] removes the electronics from the windoor.", "You start to remove electronics from the windoor.") if (do_after(user, 40, INTERRUPT_ALL, BUSY_ICON_BUILD)) diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm index f09d98479bfc..bed5b5b9c5b3 100644 --- a/code/game/machinery/embedded_controller/embedded_controller_base.dm +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -56,7 +56,7 @@ /obj/structure/machinery/embedded_controller/radio/Destroy() SSradio.remove_object(src, frequency) - QDEL_NULL(radio_connection) + radio_connection = null return ..() /obj/structure/machinery/embedded_controller/radio/update_icon() diff --git a/code/game/machinery/embedded_controller/embedded_program_base.dm b/code/game/machinery/embedded_controller/embedded_program_base.dm index 98a984f76803..97e6feb6d202 100644 --- a/code/game/machinery/embedded_controller/embedded_program_base.dm +++ b/code/game/machinery/embedded_controller/embedded_program_base.dm @@ -5,6 +5,10 @@ var/id_tag +/datum/computer/file/embedded_program/Destroy(force, ...) + master = null + return ..() + /datum/computer/file/embedded_program/New(obj/structure/machinery/embedded_controller/M) master = M if (istype(M, /obj/structure/machinery/embedded_controller/radio)) diff --git a/code/game/machinery/embedded_controller/simple_docking_controller.dm b/code/game/machinery/embedded_controller/simple_docking_controller.dm index 665c3a6c2314..d32f3a7e9e96 100644 --- a/code/game/machinery/embedded_controller/simple_docking_controller.dm +++ b/code/game/machinery/embedded_controller/simple_docking_controller.dm @@ -9,6 +9,10 @@ docking_program = new/datum/computer/file/embedded_program/docking/simple(src) program = docking_program +/obj/structure/machinery/embedded_controller/radio/simple_docking_controller/Destroy() + QDEL_NULL(docking_program) + return ..() + //A docking controller program for a simple door based docking port /datum/computer/file/embedded_program/docking/simple var/tag_door diff --git a/code/game/machinery/fax_machine.dm b/code/game/machinery/fax_machine.dm index 97f593703b9a..783d24c00f2e 100644 --- a/code/game/machinery/fax_machine.dm +++ b/code/game/machinery/fax_machine.dm @@ -7,9 +7,8 @@ var/list/alldepartments = list() #define DEPARTMENT_PROVOST "USCM Provost Office" #define DEPARTMENT_PRESS "Various Press Organizations" -//This fax machine will become a colonial one after I have mapped it onto the Almayer. -/obj/structure/machinery/faxmachine - name = "General Purpose Fax Machine" +/obj/structure/machinery/faxmachine // why not fax_machine? + name = "\improper General Purpose Fax Machine" icon = 'icons/obj/structures/machinery/library.dmi' icon_state = "fax" anchored = TRUE @@ -19,10 +18,13 @@ var/list/alldepartments = list() active_power_usage = 200 power_channel = POWER_CHANNEL_EQUIP - var/obj/item/card/id/scan = null // identification + var/obj/item/card/id/scan // identification var/authenticated = FALSE - var/obj/item/paper/tofax = null // what we're sending + var/obj/item/paper/original_fax // what we're sending + + // copy of the original fax in paper format, we want the original item (i.e. photo, paper bundle) not be changed as the user will need to eject it. + var/obj/item/paper/fax_paper_copy ///Our department var/department = "General Public" @@ -30,6 +32,9 @@ var/list/alldepartments = list() ///Target department var/target_department = DEPARTMENT_WY + // list for img and their photo reference to be stored into the admin's cache. + var/list/photo_list = list() + ///Fluff network shown by fax machine when logged in var/network = "Weyland-Yutani Public Network" @@ -59,36 +64,51 @@ var/list/alldepartments = list() tgui_interact(user) /obj/structure/machinery/faxmachine/attackby(obj/item/O as obj, mob/user as mob) - if(istype(O, /obj/item/paper)) - if(!tofax) - user.drop_inv_item_to_loc(O, src) - tofax = O - to_chat(user, SPAN_NOTICE("You insert the paper into \the [src].")) - flick("faxsend", src) - updateUsrDialog() - else + + if(istype(O, /obj/item/paper) || istype(O, /obj/item/paper_bundle) || istype(O, /obj/item/photo)) + if(original_fax) to_chat(user, SPAN_NOTICE("There is already something in \the [src].")) + return + + var/jammed = FALSE + if(istype(O, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/bundle = O + if(bundle.amount > 5) + jammed = TRUE + + user.drop_inv_item_to_loc(O, src) + original_fax = O + if(!jammed) + to_chat(user, SPAN_NOTICE("You insert the [O.name] into \the [src].")) + else + to_chat(user, SPAN_NOTICE("\The [src] jammed! It can only accept up to five papers at once.")) + playsound(src, "sound/machines/terminal_insert_disc.ogg", 50, TRUE) + flick("faxsend", src) + updateUsrDialog() + return - else if(istype(O, /obj/item/card/id)) + if(istype(O, /obj/item/card/id)) var/obj/item/card/id/idcard = O - if(!scan) - user.drop_inv_item_to_loc(idcard, src) - scan = idcard - to_chat(usr, SPAN_NOTICE("You put \the [scan] into \the [src].")) - playsound(src, 'sound/machines/pda_button1.ogg', 15, TRUE) + if(scan) + to_chat(user, SPAN_NOTICE("There is already an id in \the [src].")) + return + + user.drop_inv_item_to_loc(idcard, src) + scan = idcard + to_chat(usr, SPAN_NOTICE("You put \the [scan] into \the [src].")) + playsound(src, 'sound/machines/pda_button1.ogg', 15, TRUE) + return - else if(HAS_TRAIT(O, TRAIT_TOOL_WRENCH)) + if(HAS_TRAIT(O, TRAIT_TOOL_WRENCH)) playsound(loc, 'sound/items/Ratchet.ogg', 25, 1) anchored = !anchored to_chat(user, SPAN_NOTICE("You [anchored ? "wrench" : "unwrench"] \the [src].")) - return /obj/structure/machinery/faxmachine/verb/eject_id() set category = "Object" set name = "Eject ID Card" set src in view(1) - if(!usr || usr.stat || usr.lying) return if(ishuman(usr) && scan) @@ -144,9 +164,9 @@ var/list/alldepartments = list() var/list/data = list() data["idcard"] = scan - data["paper"] = tofax - if(tofax) - data["paper_name"] = tofax.name + data["paper"] = original_fax + if(original_fax) + data["paper_name"] = original_fax.name data["authenticated"] = authenticated data["target_department"] = target_department @@ -164,73 +184,77 @@ var/list/alldepartments = list() switch(action) if("send") - if(tofax) - if(target_department == DEPARTMENT_HC) - highcom_fax(src, tofax.info, tofax.name, usr) - fax_cooldown = 600 - - else if(target_department == DEPARTMENT_PROVOST) - provost_fax(src, tofax.info, tofax.name, usr) - fax_cooldown = 600 + if(!original_fax) + to_chat(ui.user, SPAN_NOTICE("No paper loaded.")) + return - else if(target_department == DEPARTMENT_CMB) - cmb_fax(src, tofax.info, tofax.name, usr) - fax_cooldown = 600 + if(istype(original_fax, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/bundle = original_fax + if(bundle.amount > 5) + to_chat(ui.user, SPAN_NOTICE("\The [src] is jammed!")) + return - else if(target_department == DEPARTMENT_WY) - company_fax(src, tofax.info, tofax.name, usr) - fax_cooldown = 600 + copy_fax_paper() - else if(target_department == DEPARTMENT_PRESS) - press_fax(src, tofax.info, tofax.name, usr) - fax_cooldown = 600 + outgoing_fax_message(ui.user) - else - general_fax(src, tofax.info, tofax.name, usr) - fax_cooldown = 600 - - COOLDOWN_START(src, send_cooldown, fax_cooldown) - SendFax(tofax.info, tofax.name, usr, target_department, network, src) - to_chat(usr, "Message transmitted successfully.") - . = TRUE + COOLDOWN_START(src, send_cooldown, fax_cooldown) + to_chat(ui.user, "Message transmitted successfully.") + . = TRUE if("ejectpaper") - if(tofax) - if(!ishuman(usr)) - to_chat(usr, SPAN_WARNING("You can't do it.")) - else - tofax.forceMove(usr.loc) - usr.put_in_hands(tofax) - to_chat(usr, SPAN_NOTICE("You take \the [tofax] out of \the [src].")) - tofax = null - . = TRUE + if(!original_fax) + to_chat(ui.user, SPAN_NOTICE("No paper loaded.")) + if(!ishuman(ui.user)) + to_chat(ui.user, SPAN_NOTICE("You can't do that.")) + return + + original_fax.forceMove(ui.user.loc) + ui.user.put_in_hands(original_fax) + to_chat(ui.user, SPAN_NOTICE("You take \the [original_fax.name] out of \the [src].")) + original_fax = null + fax_paper_copy = null + photo_list = null + . = TRUE if("insertpaper") - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/paper)) - usr.drop_inv_item_to_loc(I, src) - tofax = I - to_chat(usr, SPAN_NOTICE("You put \the [tofax] into \the [src].")) + var/jammed = FALSE + var/obj/item/I = ui.user.get_active_hand() + if(istype(I, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/bundle = I + if(bundle.amount > 5) + jammed = TRUE + // Repeating code? This is not ideal. Why not put this functionality inside of a proc? + if(istype(I, /obj/item/paper) || istype(I, /obj/item/paper_bundle) || istype(I, /obj/item/photo)) + ui.user.drop_inv_item_to_loc(I, src) + original_fax = I + if(!jammed) + to_chat(ui.user, SPAN_NOTICE("You put \the [original_fax.name] into \the [src].")) + else + to_chat(ui.user, SPAN_NOTICE("\The [src] jammed! It can only accept up to five papers at once.")) + playsound(src, "sound/machines/terminal_insert_disc.ogg", 50, TRUE) + flick("faxsend", src) . = TRUE if("ejectid") - if(scan) - if(ishuman(usr)) - scan.forceMove(usr.loc) - if(!usr.get_active_hand()) - usr.put_in_hands(scan) - scan = null - else - scan.forceMove(src.loc) - scan = null - to_chat(usr, SPAN_NOTICE("You take \the [scan] out of \the [src].")) - authenticated = FALSE - playsound(src, 'sound/machines/terminal_eject.ogg', 15, TRUE) - . = TRUE + if(!scan || !ishuman(ui.user)) + to_chat(ui.user, SPAN_WARNING("You can't do that.")) + return + to_chat(ui.user, SPAN_NOTICE("You take \the [scan] out of \the [src].")) + scan.forceMove(ui.user.loc) + if(!ui.user.get_active_hand()) + ui.user.put_in_hands(scan) + scan = null + else + scan.forceMove(src.loc) + scan = null + authenticated = FALSE + playsound(src, 'sound/machines/terminal_eject.ogg', 15, TRUE) + . = TRUE if("select") var/last_target_department = target_department - target_department = tgui_input_list(usr, "Which department?", "Choose a department", alldepartments) + target_department = tgui_input_list(ui.user, "Which department?", "Choose a department", alldepartments) if(!target_department) target_department = last_target_department . = TRUE @@ -245,7 +269,7 @@ var/list/alldepartments = list() authenticated = FALSE . = TRUE - add_fingerprint(usr) + add_fingerprint(ui.user) /obj/structure/machinery/faxmachine/vv_get_dropdown() . = ..() @@ -255,90 +279,80 @@ var/list/alldepartments = list() . += "" . += "" -/proc/highcom_fax(originfax, sent, sentname, mob/Sender) - var/faxcontents = "[sent]" - GLOB.fax_contents += faxcontents - - var/msg_admin = SPAN_NOTICE("USCM FAX: [key_name(Sender, 1)] ") - msg_admin += "(Mark) (PP) " - msg_admin += "(VV) (SM) " - msg_admin += "(JMP) " - msg_admin += "(RPLY): " - msg_admin += "Receiving '[sentname]' via secure connection ... view message" +// converting whatever type the fax is into a single paper with all the information on it. +/obj/structure/machinery/faxmachine/proc/copy_fax_paper(mob/living/user) - var/msg_ghost = SPAN_NOTICE("USCM FAX: ") - msg_ghost += "Receiving '[sentname]' via secure connection ... view message" - - GLOB.USCMFaxes.Add("\[view message at [world.timeofday]\] REPLY") - announce_fax(msg_admin, msg_ghost) + if(fax_paper_copy) + return -/proc/provost_fax(originfax, sent, sentname, mob/Sender) - var/faxcontents = "[sent]" - GLOB.fax_contents += faxcontents + if(istype(original_fax, /obj/item/paper)) + fax_paper_copy = original_fax + return - var/msg_admin = SPAN_NOTICE("PROVOST FAX: [key_name(Sender, 1)] ") - msg_admin += "(Mark) (PP) " - msg_admin += "(VV) (SM) " - msg_admin += "(JMP) " - msg_admin += "(RPLY): " - msg_admin += "Receiving '[sentname]' via secure connection ... view message" + fax_paper_copy = new() + fax_paper_copy.name = original_fax.name - var/msg_ghost = SPAN_NOTICE("USCM FAX: ") - msg_ghost += "Receiving '[sentname]' via secure connection ... view message" + if(istype(original_fax, /obj/item/photo)) + var/obj/item/photo/faxed_photo = original_fax + photo_list += list("tmp_photo.png" = faxed_photo.img ) + fax_paper_copy.info += "" + return - GLOB.ProvostFaxes.Add("\[view message at [world.timeofday]\] REPLY") - announce_fax(msg_admin, msg_ghost) + // type bundle + var/obj/item/paper_bundle/papers = original_fax + for(var/content in 1 to papers.amount) + fax_paper_copy.info += "

Page #[content]

" + fax_paper_copy.info += "
" + if(istype(papers[content], /obj/item/paper)) + var/obj/item/paper/faxed_paper = papers[content] + fax_paper_copy.info += faxed_paper.info + else // type photo + var/obj/item/photo/faxed_photo = papers[content] + if(!isicon(faxed_photo.img)) + return + photo_list += list("tmp_photo[content].png" = (faxed_photo.img)) + fax_paper_copy.info += "" + +/obj/structure/machinery/faxmachine/proc/outgoing_fax_message(mob/user) + + var/datum/fax/faxcontents = new(fax_paper_copy.info, photo_list) -/proc/cmb_fax(originfax, sent, sentname, mob/Sender) - var/faxcontents = "[sent]" GLOB.fax_contents += faxcontents - var/msg_admin = SPAN_NOTICE("COLONIAL MARSHAL BUREAU FAX: [key_name(Sender, 1)] ") - msg_admin += "(Mark) (PP) " - msg_admin += "(VV) (SM) " - msg_admin += "(JMP) " - msg_admin += "(RPLY): " - msg_admin += "Receiving '[sentname]' via encrypted connection ... view message" - - var/msg_ghost = SPAN_NOTICE("COLONIAL MARSHAL BUREAU FAX: ") - msg_ghost += "Receiving '[sentname]' via encrypted connection ... view message" - - GLOB.CMBFaxes.Add("\[view message at [world.timeofday]\] REPLY") - announce_fax(msg_admin, msg_ghost) - -/proc/company_fax(originfax, sent, sentname, mob/Sender) - var/faxcontents = "[sent]" - GLOB.fax_contents += faxcontents - var/msg_admin = SPAN_NOTICE("WEYLAND-YUTANI FAX: [key_name(Sender, 1)] ") - msg_admin += "(Mark) (PP) " - msg_admin += "(VV) (SM) " - msg_admin += "(JMP) " - msg_admin += "(RPLY): " - msg_admin += "Receiving '[sentname]' via secure connection ... view message" - var/msg_ghost = SPAN_NOTICE("WEYLAND-YUTANI FAX: ") - msg_ghost += "Receiving '[sentname]' via secure connection ... view message" - GLOB.WYFaxes.Add("\[view message at [world.timeofday]\] REPLY") - announce_fax(msg_admin, msg_ghost) + var/msg_admin = SPAN_STAFF_IC("[target_department]: [key_name(user, 1)] ") + msg_admin += "[CC_MARK(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_JMP_USER(user)] " + + switch(target_department) + if(DEPARTMENT_HC) + GLOB.USCMFaxes.Add("\[view message at [world.timeofday]\] REPLY") + msg_admin += "(RPLY): " + if(DEPARTMENT_PROVOST) + GLOB.ProvostFaxes.Add("\[view message at [world.timeofday]\] REPLY") + msg_admin += "(RPLY): " + if(DEPARTMENT_CMB) + GLOB.CMBFaxes.Add("\[view message at [world.timeofday]\] REPLY") + msg_admin += "(RPLY): " + if(DEPARTMENT_WY) + GLOB.WYFaxes.Add("\[view message at [world.timeofday]\] REPLY") + msg_admin += "(RPLY): " + if(DEPARTMENT_PRESS) + GLOB.PressFaxes.Add("\[view message at [world.timeofday]\] REPLY") + msg_admin += "(RPLY): " + else + GLOB.GeneralFaxes.Add("\[view message at [world.timeofday]\] REPLY") + msg_admin += "(RPLY): " -/proc/press_fax(originfax, sent, sentname, mob/Sender) - var/faxcontents = "[sent]" - GLOB.fax_contents += faxcontents + msg_admin += SPAN_STAFF_IC("Receiving fax via secure connection ... view message") - var/msg_admin = SPAN_NOTICE("PRESS FAX: [key_name(Sender, 1)] ") - msg_admin += "(Mark) (PP) " - msg_admin += "(VV) (SM) " - msg_admin += "(JMP) " - msg_admin += "(RPLY): " - msg_admin += "Receiving '[sentname]' via secure connection ... view message" + var/msg_ghost = SPAN_NOTICE("[target_department]: ") + msg_ghost += "Receiving fax via secure connection ... view message" - var/msg_ghost = SPAN_NOTICE("USCM FAX: ") - msg_ghost += "Receiving '[sentname]' via secure connection ... view message" + send_fax(faxcontents) - GLOB.PressFaxes.Add("\[view message at [world.timeofday]\] REPLY") announce_fax(msg_admin, msg_ghost) -/proc/announce_fax(msg_admin, msg_ghost) - log_admin(msg_admin) //Always irked me the replies do show up but the faxes themselves don't +/datum/proc/announce_fax(msg_admin, msg_ghost) + log_admin(msg_admin) for(var/client/C in GLOB.admins) if((R_ADMIN|R_MOD) & C.admin_holder.rights) if(msg_admin) @@ -358,33 +372,27 @@ var/list/alldepartments = list() to_chat(C, msg_ghost) C << 'sound/effects/sos-morse-code.ogg' -/proc/general_fax(originfax, sent, sentname, mob/Sender) - var/faxcontents = "[sent]" - GLOB.fax_contents += faxcontents - GLOB.GeneralFaxes.Add("\[view message at [world.timeofday]\] REPLY") -/proc/SendFax(sent, sentname, mob/Sender, target_department, network, obj/structure/machinery/faxmachine/origin) +/obj/structure/machinery/faxmachine/proc/send_fax(datum/fax/faxcontents) for(var/obj/structure/machinery/faxmachine/F in allfaxes) - if(F != origin && F.department == target_department) + if(F != src && F.department == target_department) + if(!faxcontents) + return if(! (F.inoperable() ) ) flick("faxreceive", F) // give the sprite some time to flick spawn(20) - var/obj/item/paper/P = new /obj/item/paper( F.loc ) - P.name = "[sentname]" - P.info = "[sent]" + var/obj/item/paper/P = new(F.loc,faxcontents.photo_list) + P.name = "faxed message" + P.info = "[faxcontents.data]" P.update_icon() switch(network) if("USCM High Command Quantum Relay") var/image/stampoverlay = image('icons/obj/items/paper.dmi') stampoverlay.icon_state = "paper_stamp-uscm" - if(!P.stamped) - P.stamped = new - P.stamped += /obj/item/tool/stamp - P.overlays += stampoverlay P.stamps += "
This paper has been stamped by the USCM High Command Quantum Relay." if("NC4 UA Federal Secure Network - CMB Relay") var/image/stampoverlay = image('icons/obj/items/paper.dmi') @@ -404,16 +412,16 @@ var/list/alldepartments = list() P.stamps += "
This paper has been stamped and encrypted by the Weyland-Yutani Quantum Relay (tm)." playsound(F.loc, "sound/items/polaroid1.ogg", 15, 1) - + qdel(faxcontents) /obj/structure/machinery/faxmachine/cmb - name = "CMB Incident Command Center Fax Machine" + name = "\improper CMB Incident Command Center Fax Machine" department = "Colonial Marshal Bureau, Anchorpoint Station" network = "NC4 UA Federal Secure Network - CMB Relay" department = DEPARTMENT_CMB /obj/structure/machinery/faxmachine/corporate - name = "W-Y Corporate Fax Machine" + name = "\improper W-Y Corporate Fax Machine" department = "W-Y Local Office" network = "Weyland-Yutani Secure Network" @@ -426,7 +434,7 @@ var/list/alldepartments = list() network = "Weyland-Yutani Quantum Relay" /obj/structure/machinery/faxmachine/uscm - name = "USCM Military Fax Machine" + name = "\improper USCM Military Fax Machine" department = "USCM Local Operations" network = "USCM Encrypted Network" target_department = DEPARTMENT_HC @@ -443,7 +451,7 @@ var/list/alldepartments = list() network = "USCM High Command Quantum Relay" /obj/structure/machinery/faxmachine/uscm/brig - name = "USCM Provost Fax Machine" + name = "\improper USCM Provost Fax Machine" department = "Brig" target_department = DEPARTMENT_PROVOST @@ -454,3 +462,12 @@ var/list/alldepartments = list() department = DEPARTMENT_PROVOST target_department = "Brig" network = "USCM High Command Quantum Relay" + +/datum/fax + var/data + var/list/photo_list + +/datum/fax/New(data, photo_list) + . = ..() + src.data = data + src.photo_list = photo_list diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm index 261eea67913b..fe1f80646c4f 100644 --- a/code/game/machinery/fire_alarm.dm +++ b/code/game/machinery/fire_alarm.dm @@ -139,8 +139,10 @@ FIRE ALARM var/area/area = get_area(src) if (area.flags_alarm_state & ALARM_WARNING_FIRE) + user.visible_message("[user] deactivates [src].", "You deactivate [src].") reset() else + user.visible_message("[user] activates [src].", "You activate [src].") alarm() return diff --git a/code/game/machinery/groundmap_geothermal.dm b/code/game/machinery/groundmap_geothermal.dm index ec20f00449bb..4be9c53f0094 100644 --- a/code/game/machinery/groundmap_geothermal.dm +++ b/code/game/machinery/groundmap_geothermal.dm @@ -198,10 +198,13 @@ else return ..() //Deal with everything else, like hitting with stuff +/obj/structure/machinery/power/geothermal/ex_act(severity, direction) + return FALSE //gameplay-wise these should really never go away + //Putting these here since it's power-related /obj/structure/machinery/colony_floodlight_switch name = "Colony Floodlight Switch" - icon = 'icons/turf/ground_map.dmi' + icon = 'icons/obj/structures/machinery/power.dmi' icon_state = "panelnopower" desc = "This switch controls the floodlights surrounding the archaeology complex. It only functions when there is power." density = FALSE @@ -279,7 +282,7 @@ if(!ispowered) to_chat(user, "Nothing happens.") return 0 - playsound(src,'sound/machines/click.ogg', 15, 1) + playsound(src,'sound/items/Deconstruct.ogg', 30, 1) use_power(5) toggle_lights() turned_on = !(src.turned_on) @@ -299,7 +302,7 @@ icon_state = "flood_s_off" density = TRUE anchored = TRUE - layer = WINDOW_LAYER + layer = ABOVE_XENO_LAYER var/damaged = 0 //Can be smashed by xenos var/is_lit = 0 //whether the floodlight is switched to on or off. Does not necessarily mean it emits light. unslashable = TRUE diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index e102285fed4d..1acb47370d96 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -217,4 +217,4 @@ Holographic project of everything else. name = "hologram projector" desc = "It makes a hologram appear...with magnets or something..." icon = 'icons/obj/structures/props/stationobjs.dmi' - icon_state = "hologram0" + icon_state = "holopad0" diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 9407ef61277b..ef6c74a052cd 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -4,13 +4,18 @@ anchored = FALSE density = FALSE drag_delay = 1 + base_pixel_x = 15 + base_pixel_y = -2 - var/mob/living/carbon/human/attached = null + var/mob/living/carbon/attached = null var/mode = 1 // 1 is injecting, 0 is taking blood. var/obj/item/reagent_container/beaker = null + var/datum/beam/current_beam + //make it so that IV doesn't require power to function. + use_power = USE_POWER_NONE /obj/structure/machinery/iv_drip/update_icon() - if(src.attached) + if(attached) icon_state = "hooked" else icon_state = "" @@ -35,50 +40,71 @@ filling.color = mix_color_from_reagents(reagents.reagent_list) overlays += filling +/obj/structure/machinery/iv_drip/proc/update_beam() + if(current_beam && !attached) + QDEL_NULL(current_beam) + else if(!current_beam && attached && !QDELETED(src)) + current_beam = beam(attached, "iv_tube") + +/obj/structure/machinery/iv_drip/Destroy() + attached?.active_transfusions -= src + attached = null + update_beam() + . = ..() + /obj/structure/machinery/iv_drip/MouseDrop(over_object, src_location, over_location) ..() if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - if(H.stat || get_dist(H, src) > 1 || H.blinded || H.lying) + var/mob/living/carbon/human/user = usr + if(user.stat || get_dist(user, src) > 1 || user.blinded || user.lying) + return + + if(!skillcheck(user, SKILL_SURGERY, SKILL_SURGERY_NOVICE)) + to_chat(user, SPAN_WARNING("You don't know how to [attached ? "disconnect" : "connect"] this!")) return if(attached) - H.visible_message("[H] detaches \the [src] from \the [attached].", \ + user.visible_message("[user] detaches \the [src] from \the [attached].", \ "You detach \the [src] from \the [attached].") + attached.active_transfusions -= src attached = null + update_beam() update_icon() stop_processing() return if(in_range(src, usr) && iscarbon(over_object) && get_dist(over_object, src) <= 1) - H.visible_message("[H] attaches \the [src] to \the [over_object].", \ + user.visible_message("[user] attaches \the [src] to \the [over_object].", \ "You attach \the [src] to \the [over_object].") attached = over_object + attached.active_transfusions += src + update_beam() update_icon() start_processing() - -/obj/structure/machinery/iv_drip/attackby(obj/item/W, mob/living/user) - if (istype(W, /obj/item/reagent_container)) +/obj/structure/machinery/iv_drip/attackby(obj/item/container, mob/living/user) + if (istype(container, /obj/item/reagent_container)) if(beaker) to_chat(user, SPAN_WARNING("There is already a reagent container loaded!")) return - if((!istype(W, /obj/item/reagent_container/blood) && !istype(W, /obj/item/reagent_container/glass)) || istype(W, /obj/item/reagent_container/glass/bucket)) + if((!istype(container, /obj/item/reagent_container/blood) && !istype(container, /obj/item/reagent_container/glass)) || istype(container, /obj/item/reagent_container/glass/bucket)) to_chat(user, SPAN_WARNING("That won't fit!")) return - if(user.drop_inv_item_to_loc(W, src)) - beaker = W + if(user.drop_inv_item_to_loc(container, src)) + beaker = container var/reagentnames = "" - for(var/datum/reagent/R in beaker.reagents.reagent_list) - reagentnames += ";[R.name]" + + for(var/datum/reagent/chem in beaker.reagents.reagent_list) + reagentnames += ";[chem.name]" log_admin("[key_name(user)] put a [beaker] into [src], containing [reagentnames] at ([src.loc.x],[src.loc.y],[src.loc.z]).") - to_chat(user, "You attach \the [W] to \the [src].") + to_chat(user, "You attach \the [container] to \the [src].") + update_beam() update_icon() return else @@ -93,7 +119,9 @@ attached.apply_damage(3, BRUTE, pick("r_arm", "l_arm")) if(attached.pain.feels_pain) attached.emote("scream") + attached.active_transfusions -= src attached = null + update_beam() update_icon() stop_processing() return @@ -118,20 +146,20 @@ if(prob(5)) visible_message("\The [src] pings.") return - var/mob/living/carbon/T = attached + var/mob/living/carbon/patient = attached - if(!istype(T)) + if(!istype(patient)) return - if(ishuman(T)) - var/mob/living/carbon/human/H = T - if(H.species && H.species.flags & NO_BLOOD) + if(ishuman(patient)) + var/mob/living/carbon/human/human_patient = patient + if(human_patient.species && human_patient.species.flags & NO_BLOOD) return // If the human is losing too much blood, beep. - if(T.blood_volume < BLOOD_VOLUME_SAFE) if(prob(5)) + if(patient.blood_volume < BLOOD_VOLUME_SAFE) if(prob(5)) visible_message("\The [src] beeps loudly.") - T.take_blood(beaker,amount) + patient.take_blood(beaker,amount) update_icon() /obj/structure/machinery/iv_drip/attack_hand(mob/user as mob) diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm index 514fddd744de..08a3d5c4dfee 100644 --- a/code/game/machinery/kitchen/gibber.dm +++ b/code/game/machinery/kitchen/gibber.dm @@ -116,7 +116,7 @@ if(ishuman(victim) && ishuman_strict(user) && !occupant) var/turf/turf_ref = get_turf(user) var/area/area = get_area(user) - message_admins("ALERT: [user] ([user.key]) is trying to gib [victim] ([victim.key]) in [area.name] (JMP)") + message_admins("ALERT: [user] ([user.key]) is trying to gib [victim] ([victim.key]) in [area.name] [ADMIN_JMP(turf_ref)]") log_attack("[key_name(user)] tried to gib [victim] ([victim.key]) in [area.name]") to_chat(user, SPAN_DANGER("Are you insane?!")) if(do_after(user, 30 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE && grabbed && grabbed.grabbed_thing && !occupant)) diff --git a/code/game/machinery/line_nexter.dm b/code/game/machinery/line_nexter.dm index 98245a8080e0..d736df44664a 100644 --- a/code/game/machinery/line_nexter.dm +++ b/code/game/machinery/line_nexter.dm @@ -11,6 +11,10 @@ var/last_use var/id +/obj/structure/machinery/line_nexter/med + icon = 'icons/obj/structures/barricades.dmi' + icon_state = "turnstile_med" + /obj/structure/machinery/line_nexter/Initialize() . = ..() last_use = world.time diff --git a/code/game/machinery/medical_pod/medical_pod.dm b/code/game/machinery/medical_pod/medical_pod.dm index 2c2d59a7aec8..b284d71ad4a7 100644 --- a/code/game/machinery/medical_pod/medical_pod.dm +++ b/code/game/machinery/medical_pod/medical_pod.dm @@ -1,7 +1,8 @@ /obj/structure/machinery/medical_pod name = "generic medical pod" icon = 'icons/obj/structures/machinery/cryogenics.dmi' - icon_state = "sleeper" + icon_state = "sleeper_open" + var/base_icon_state = "sleeper" unslashable = TRUE density = TRUE @@ -32,9 +33,9 @@ /obj/structure/machinery/medical_pod/update_icon() if(occupant) - icon_state = "[initial(icon_state)]_closed" + icon_state = "[base_icon_state]_closed" else - icon_state = "[initial(icon_state)]_open" + icon_state = "[base_icon_state]_open" /obj/structure/machinery/medical_pod/verb/move_inside(mob/target) set src in oview(1) diff --git a/code/game/machinery/nuclearbomb.dm b/code/game/machinery/nuclearbomb.dm index 573240bfa718..743f53e4f03b 100644 --- a/code/game/machinery/nuclearbomb.dm +++ b/code/game/machinery/nuclearbomb.dm @@ -12,7 +12,7 @@ var/bomb_set = FALSE var/timing = FALSE var/deployable = FALSE var/explosion_time = null - var/timeleft = 4800 + var/timeleft = 8 MINUTES var/safety = TRUE var/being_used = FALSE var/end_round = TRUE @@ -29,7 +29,7 @@ var/bomb_set = FALSE update_minimap_icon() /obj/structure/machinery/nuclearbomb/proc/update_minimap_icon() - if(!z) + if(!is_ground_level(z)) return SSminimaps.remove_marker(src) @@ -55,31 +55,35 @@ var/bomb_set = FALSE /obj/structure/machinery/nuclearbomb/process() . = ..() - if(timing) - bomb_set = TRUE //So long as there is one nuke timing, it means one nuke is armed. - timeleft = explosion_time - world.time - if(world.time >= explosion_time) - explode() - //3 warnings: 1. Halfway through, 2. 1 minute left, 3. 10 seconds left. - //this structure allows varedits to var/timeleft without losing or spamming warnings. - else if(timer_announcements_flags) - if(timer_announcements_flags & NUKE_SHOW_TIMER_HALF) - if(timeleft <= initial(timeleft) / 2 && timeleft >= initial(timeleft) / 2 - 30) - announce_to_players(NUKE_SHOW_TIMER_HALF) - timer_announcements_flags &= ~NUKE_SHOW_TIMER_HALF - return - if(timer_announcements_flags & NUKE_SHOW_TIMER_MINUTE) - if(timeleft <= 600 && timeleft >= 570) - announce_to_players(NUKE_SHOW_TIMER_MINUTE) - timer_announcements_flags = NUKE_SHOW_TIMER_TEN_SEC - return - if(timer_announcements_flags & NUKE_SHOW_TIMER_TEN_SEC) - if(timeleft <= 100 && timeleft >= 70) - announce_to_players(NUKE_SHOW_TIMER_TEN_SEC) - timer_announcements_flags = 0 - return - else - stop_processing() + if(!timing) + update_minimap_icon() + return PROCESS_KILL + + bomb_set = TRUE //So long as there is one nuke timing, it means one nuke is armed. + timeleft = explosion_time - world.time + if(world.time >= explosion_time) + explode() + return + //3 warnings: 1. Halfway through, 2. 1 minute left, 3. 10 seconds left. + //this structure allows varedits to var/timeleft without losing or spamming warnings. + if(!timer_announcements_flags) + return + + if(timer_announcements_flags & NUKE_SHOW_TIMER_HALF) + if(timeleft <= initial(timeleft) / 2 && timeleft >= initial(timeleft) / 2 - 30) + announce_to_players(NUKE_SHOW_TIMER_HALF) + timer_announcements_flags &= ~NUKE_SHOW_TIMER_HALF + return + if(timer_announcements_flags & NUKE_SHOW_TIMER_MINUTE) + if(timeleft <= 600 && timeleft >= 570) + announce_to_players(NUKE_SHOW_TIMER_MINUTE) + timer_announcements_flags = NUKE_SHOW_TIMER_TEN_SEC + return + if(timer_announcements_flags & NUKE_SHOW_TIMER_TEN_SEC) + if(timeleft <= 100 && timeleft >= 70) + announce_to_players(NUKE_SHOW_TIMER_TEN_SEC) + timer_announcements_flags = 0 + return /obj/structure/machinery/nuclearbomb/attack_alien(mob/living/carbon/xenomorph/M) INVOKE_ASYNC(src, TYPE_PROC_REF(/atom, attack_hand), M) @@ -87,10 +91,10 @@ var/bomb_set = FALSE /obj/structure/machinery/nuclearbomb/attackby(obj/item/O as obj, mob/user as mob) if(anchored && timing && bomb_set && HAS_TRAIT(O, TRAIT_TOOL_WIRECUTTERS)) - user.visible_message(SPAN_DANGER("[user] begins to defuse \the [src]."), SPAN_DANGER("You begin to defuse \the [src]. This will take some time...")) + user.visible_message(SPAN_INFO("[user] begins to defuse \the [src]."), SPAN_INFO("You begin to defuse \the [src]. This will take some time...")) if(do_after(user, 150 * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) disable() - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) return ..() @@ -103,12 +107,12 @@ var/bomb_set = FALSE if(deployable) if(!ishuman(user) && !isqueen(user)) - to_chat(usr, SPAN_DANGER("You don't have the dexterity to do this!")) + to_chat(usr, SPAN_INFO("You don't have the dexterity to do this!")) return if(isqueen(user)) if(timing && bomb_set) - user.visible_message(SPAN_DANGER("[user] begins to defuse \the [src]."), SPAN_DANGER("You begin to defuse \the [src]. This will take some time...")) + user.visible_message(SPAN_INFO("[user] begins to defuse \the [src]."), SPAN_INFO("You begin to defuse \the [src]. This will take some time...")) if(do_after(user, 5 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) disable() return @@ -148,6 +152,7 @@ var/bomb_set = FALSE data["command_lockout"] = command_lockout data["allowed"] = allowed data["being_used"] = being_used + data["decryption_complete"] = TRUE //this is overriden by techweb nuke UI_data later, this just makes it default to true return data @@ -162,67 +167,68 @@ var/bomb_set = FALSE if(timing == -1) return - if(!ishuman(usr)) + if(!ishuman(ui.user)) return - if(!allowed(usr)) - to_chat(usr, SPAN_DANGER("Access denied!")) + if(!allowed(ui.user)) + to_chat(ui.user, SPAN_INFO("Access denied!")) return if(!anchored) - to_chat(usr, SPAN_DANGER("Engage anchors first!")) + to_chat(ui.user, SPAN_INFO("Engage anchors first!")) return if(safety) - to_chat(usr, SPAN_DANGER("The safety is still on.")) + to_chat(ui.user, SPAN_INFO("The safety is still on.")) return if(!A.can_build_special) - to_chat(usr, SPAN_DANGER("You cannot deploy [src] here!")) + to_chat(ui.user, SPAN_INFO("You cannot deploy [src] here!")) return - if(usr.action_busy) + if(ui.user.action_busy) return - usr.visible_message(SPAN_WARNING("[usr] begins to [timing ? "disengage" : "engage"] [src]!"), SPAN_WARNING("You begin to [timing ? "disengage" : "engage"] [src].")) + ui.user.visible_message(SPAN_WARNING("[ui.user] begins to [timing ? "disengage" : "engage"] [src]!"), SPAN_WARNING("You begin to [timing ? "disengage" : "engage"] [src].")) being_used = TRUE - ui = SStgui.try_update_ui(usr, src, ui) - if(do_after(usr, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + ui = SStgui.try_update_ui(ui.user, src, ui) + if(do_after(ui.user, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) timing = !timing if(timing) if(!safety) bomb_set = TRUE explosion_time = world.time + timeleft + update_minimap_icon() start_processing() announce_to_players() - message_admins("[src] has been activated by [key_name(usr, 1)](JMP)") + message_admins("\The [src] has been activated by [key_name(ui.user, 1)] [ADMIN_JMP_USER(ui.user)]") else bomb_set = FALSE else disable() - message_admins("[src] has been deactivated by [key_name(usr, 1)](JMP)") - playsound(src.loc, 'sound/effects/thud.ogg', 100, 1) + message_admins("\The [src] has been deactivated by [key_name(ui.user, 1)] [ADMIN_JMP_USER(ui.user)]") + playsound(loc, 'sound/effects/thud.ogg', 100, 1) being_used = FALSE . = TRUE if("toggleSafety") - if(!allowed(usr)) - to_chat(usr, SPAN_DANGER("Access denied!")) + if(!allowed(ui.user)) + to_chat(ui.user, SPAN_INFO("Access denied!")) return if(timing) - to_chat(usr, SPAN_DANGER("Disengage first!")) + to_chat(ui.user, SPAN_INFO("Disengage first!")) return if(!A.can_build_special) - to_chat(usr, SPAN_DANGER("You cannot deploy [src] here!")) + to_chat(ui.user, SPAN_INFO("You cannot deploy [src] here!")) return - if(usr.action_busy) + if(ui.user.action_busy) return - usr.visible_message(SPAN_WARNING("[usr] begins to [safety ? "disable" : "enable"] the safety on [src]!"), SPAN_WARNING("You begin to [safety ? "disable" : "enable"] the safety on [src].")) + ui.user.visible_message(SPAN_WARNING("[ui.user] begins to [safety ? "disable" : "enable"] the safety on [src]!"), SPAN_WARNING("You begin to [safety ? "disable" : "enable"] the safety on [src].")) being_used = TRUE - ui = SStgui.try_update_ui(usr, src, ui) - if(do_after(usr, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + ui = SStgui.try_update_ui(ui.user, src, ui) + if(do_after(ui.user, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) safety = !safety - playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1) + playsound(loc, 'sound/items/poster_being_created.ogg', 100, 1) being_used = FALSE if(safety) timing = FALSE @@ -230,63 +236,55 @@ var/bomb_set = FALSE . = TRUE if("toggleCommandLockout") - if(!ishuman(usr)) + if(!ishuman(ui.user)) return - if(!allowed(usr)) - to_chat(usr, SPAN_DANGER("Access denied!")) + if(!allowed(ui.user)) + to_chat(ui.user, SPAN_INFO("Access denied!")) return if(command_lockout) command_lockout = FALSE req_one_access = list() - to_chat(usr, SPAN_DANGER("Command lockout disengaged.")) + to_chat(ui.user, SPAN_INFO("Command lockout disengaged.")) else //Check if they have command access var/list/acc = list() - var/mob/living/carbon/human/H = usr + var/mob/living/carbon/human/H = ui.user if(H.wear_id) acc += H.wear_id.GetAccess() if(H.get_active_hand()) acc += H.get_active_hand().GetAccess() if(!(ACCESS_MARINE_COMMAND in acc)) - to_chat(usr, SPAN_DANGER("Access denied!")) + to_chat(ui.user, SPAN_INFO("Access denied!")) return command_lockout = TRUE req_one_access = list(ACCESS_MARINE_COMMAND) - to_chat(usr, SPAN_DANGER("Command lockout engaged.")) + to_chat(ui.user, SPAN_INFO("Command lockout engaged.")) . = TRUE if("toggleAnchor") if(timing) - to_chat(usr, SPAN_DANGER("Disengage first!")) + to_chat(ui.user, SPAN_INFO("Disengage first!")) return if(!A.can_build_special) - to_chat(usr, SPAN_DANGER("You cannot deploy [src] here!")) + to_chat(ui.user, SPAN_INFO("You cannot deploy [src] here!")) return - if(usr.action_busy) + if(ui.user.action_busy) return being_used = TRUE - ui = SStgui.try_update_ui(usr, src, ui) - if(do_after(usr, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + ui = SStgui.try_update_ui(ui.user, src, ui) + if(do_after(ui.user, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) if(!anchored) - visible_message(SPAN_DANGER("With a steely snap, bolts slide out of [src] and anchor it to the flooring.")) + visible_message(SPAN_INFO("With a steely snap, bolts slide out of [src] and anchor it to the flooring.")) else - visible_message(SPAN_DANGER("The anchoring bolts slide back into the depths of [src].")) - playsound(src.loc, 'sound/items/Deconstruct.ogg', 100, 1) + visible_message(SPAN_INFO("The anchoring bolts slide back into the depths of [src].")) + playsound(loc, 'sound/items/Deconstruct.ogg', 100, 1) anchored = !anchored being_used = FALSE . = TRUE update_icon() - add_fingerprint(usr) - -/obj/structure/machinery/nuclearbomb/start_processing() - . = ..() - update_minimap_icon() - -/obj/structure/machinery/nuclearbomb/stop_processing() - . = ..() - update_minimap_icon() + add_fingerprint(ui.user) /obj/structure/machinery/nuclearbomb/verb/make_deployable() set category = "Object" @@ -297,12 +295,12 @@ var/bomb_set = FALSE return if(!ishuman(usr)) - to_chat(usr, SPAN_DANGER("You don't have the dexterity to do this!")) + to_chat(usr, SPAN_INFO("You don't have the dexterity to do this!")) return var/area/A = get_area(src) if(!A.can_build_special) - to_chat(usr, SPAN_DANGER("You don't want to deploy this here!")) + to_chat(usr, SPAN_INFO("You don't want to deploy this here!")) return usr.visible_message(SPAN_WARNING("[usr] begins to [deployable ? "close" : "adjust"] several panels to make [src] [deployable ? "undeployable" : "deployable"]."), SPAN_WARNING("You begin to [deployable ? "close" : "adjust"] several panels to make [src] [deployable ? "undeployable" : "deployable"].")) @@ -314,26 +312,25 @@ var/bomb_set = FALSE else deployable = TRUE anchored = TRUE - playsound(src.loc, 'sound/items/Deconstruct.ogg', 100, 1) + playsound(loc, 'sound/items/Deconstruct.ogg', 100, 1) being_used = FALSE update_icon() //unified all announcements to one proc /obj/structure/machinery/nuclearbomb/proc/announce_to_players(timer_warning) + + var/list/humans_other = GLOB.human_mob_list + GLOB.dead_mob_list + var/list/humans_uscm = list() + for(var/mob/current_mob as anything in humans_other) + if(current_mob.stat != CONSCIOUS || isyautja(current_mob)) + humans_other -= current_mob + continue + if(current_mob.faction == FACTION_MARINE || current_mob.faction == FACTION_SURVIVOR) //separating marines from other factions. Survs go here too + humans_uscm += current_mob + humans_other -= current_mob + if(timer_warning) //we check for timer warnings first - //humans part - var/list/humans_other = GLOB.human_mob_list + GLOB.dead_mob_list - var/list/humans_USCM = list() - for(var/mob/M in humans_other) - var/mob/living/carbon/human/H = M - if(istype(H)) //if it's unconsious human or yautja, we remove them - if(H.stat != CONSCIOUS || isyautja(H)) - humans_other.Remove(M) - continue - if(M.faction == FACTION_MARINE || M.faction == FACTION_SURVIVOR) //separating marines from other factions. Survs go here too - humans_USCM += M - humans_other -= M - announcement_helper("WARNING.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_USCM, 'sound/misc/notice1.ogg') + announcement_helper("WARNING.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') announcement_helper("WARNING.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') //preds part var/t_left = duration2text_sec(round(rand(timeleft - timeleft / 10, timeleft + timeleft / 10))) @@ -354,21 +351,9 @@ var/bomb_set = FALSE xeno_announcement(SPAN_XENOANNOUNCE(warning), hive.hivenumber, XENO_GENERAL_ANNOUNCE) return - //deal with start/stop announcements for players - var/list/humans_other = GLOB.human_mob_list + GLOB.dead_mob_list - var/list/humans_USCM = list() - for(var/mob/M in humans_other) - var/mob/living/carbon/human/H = M - if(istype(H)) //if it's unconsious human or yautja, we remove them - if(H.stat != CONSCIOUS || isyautja(H)) - humans_other.Remove(M) - continue - if(M.faction == FACTION_MARINE || M.faction == FACTION_SURVIVOR) //separating marines from other factions. Survs go here too - humans_USCM += M - humans_other -= M var/datum/hive_status/hive if(timing) - announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE ACTIVATED.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_USCM, 'sound/misc/notice1.ogg') + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE ACTIVATED.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE ACTIVATED.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "HQ Nuclear Tracker", humans_other, 'sound/misc/notice1.ogg') var/t_left = duration2text_sec(round(rand(timeleft - timeleft / 10, timeleft + timeleft / 10))) yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!
A human Purification Device has been detected. You have approximately [t_left] to abandon the hunting grounds before it activates.")) @@ -378,7 +363,7 @@ var/bomb_set = FALSE continue xeno_announcement(SPAN_XENOANNOUNCE("The tallhosts have deployed a hive killer at [get_area_name(loc)]! Stop it at all costs!"), hive.hivenumber, XENO_GENERAL_ANNOUNCE) else - announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DEACTIVATED.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_USCM, 'sound/misc/notice1.ogg') + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DEACTIVATED.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DEACTIVATED.", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!
The human Purification Device's signature has disappeared.")) for(var/hivenumber in GLOB.hive_datum) @@ -401,6 +386,7 @@ var/bomb_set = FALSE /obj/structure/machinery/nuclearbomb/proc/explode() if(safety) timing = FALSE + update_minimap_icon() stop_processing() update_icon() return FALSE @@ -417,8 +403,205 @@ var/bomb_set = FALSE /obj/structure/machinery/nuclearbomb/Destroy() if(timing != -1) - message_admins("[src] has been unexpectedly deleted at ([x],[y],[x]). (JMP)") - log_game("[src] has been unexpectedly deleted at ([x],[y],[x]).") + message_admins("\The [src] has been unexpectedly deleted at ([x],[y],[x]). [ADMIN_JMP(src)]") + log_game("\The [src] has been unexpectedly deleted at ([x],[y],[x]).") bomb_set = FALSE SSminimaps.remove_marker(src) return ..() + +/obj/structure/machinery/nuclearbomb/tech + var/decryption_time = 10 MINUTES + var/decryption_end_time = null + var/decrypting = FALSE + + timeleft = 1 MINUTES + timer_announcements_flags = NUKE_DECRYPT_SHOW_TIMER_ALL + + var/list/linked_decryption_towers + +/obj/structure/machinery/nuclearbomb/tech/Initialize(mapload) + . = ..() + + linked_decryption_towers = list() + + return INITIALIZE_HINT_LATELOAD + +/obj/structure/machinery/nuclearbomb/tech/LateInitialize() + . = ..() + + for(var/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/possible_telecomm in GLOB.all_static_telecomms_towers) + if(is_ground_level(possible_telecomm.z)) + linked_decryption_towers += possible_telecomm + + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_TELECOMM_TURNED_OFF, PROC_REF(connected_comm_shutdown)) + +/obj/structure/machinery/nuclearbomb/tech/ui_data(mob/user) + . = ..() + + .["decrypting"] = decrypting + .["decryption_time"] = duration2text_sec(decryption_time) + + .["decryption_complete"] = decryption_time ? FALSE : TRUE + +/obj/structure/machinery/nuclearbomb/tech/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return + + switch(action) + if("toggleEncryption") + if(!ishuman(ui.user)) + return + + if(!allowed(ui.user)) + to_chat(ui.user, SPAN_INFO("Access denied!")) + return + + if(!anchored) + to_chat(ui.user, SPAN_INFO("Engage anchors first!")) + return + + var/area/current_area = get_area(src) + if(!current_area.can_build_special) + to_chat(ui.user, SPAN_INFO("You cannot deploy [src] here!")) + return + + if(is_ground_level(z)) + for(var/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/telecomm_unit in linked_decryption_towers) + if(!telecomm_unit.on) + to_chat(ui.user, SPAN_INFO("The groundside telecommunication relays must be activated!")) + return + + if(ui.user.action_busy) + return + + if(being_used) + return + + ui.user.visible_message(SPAN_WARNING("[ui.user] begins to [decrypting ? "stop the decryption process." : "start decrypting."]!"), SPAN_WARNING("You begin to [decrypting ? "stop the decryption process." : "start decrypting."].")) + being_used = TRUE + ui = SStgui.try_update_ui(ui.user, src, ui) + if(do_after(ui.user, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + decrypting = !decrypting + if(decrypting) + //add signal handlers + decryption_end_time = world.time + decryption_time + start_processing() + announce_to_players() + message_admins("[src]'s encryption process has been started by [key_name(ui.user, 1)] [ADMIN_JMP_USER(ui.user)]") + else + //remove signal handlers + decryption_end_time = null + announce_to_players() + message_admins("[src]'s encryption process has been deactivated by [key_name(ui.user, 1)] [ADMIN_JMP_USER(ui.user)]") + playsound(loc, 'sound/effects/thud.ogg', 100, 1) + being_used = FALSE + return TRUE + +/obj/structure/machinery/nuclearbomb/tech/process() + if(!decrypting) + return ..() + + decryption_time = decryption_end_time - world.time + + if(world.time > decryption_end_time) + decrypting = FALSE + decryption_time = 0 + announce_to_players(NUKE_DECRYPT_SHOW_TIMER_COMPLETE) + timer_announcements_flags &= ~NUKE_DECRYPT_SHOW_TIMER_COMPLETE + return PROCESS_KILL + + if(!timer_announcements_flags) + return + + if(timer_announcements_flags & NUKE_DECRYPT_SHOW_TIMER_HALF) + if(decryption_time <= initial(decryption_time) / 2 && decryption_time >= initial(decryption_time) / 2 - 30) + announce_to_players(NUKE_DECRYPT_SHOW_TIMER_HALF) + timer_announcements_flags &= ~NUKE_DECRYPT_SHOW_TIMER_HALF + return + if(timer_announcements_flags & NUKE_DECRYPT_SHOW_TIMER_MINUTE) + if(decryption_time <= 600 && decryption_time >= 570) + announce_to_players(NUKE_DECRYPT_SHOW_TIMER_MINUTE) + timer_announcements_flags &= ~NUKE_DECRYPT_SHOW_TIMER_MINUTE + return + +/obj/structure/machinery/nuclearbomb/tech/announce_to_players(timer_warning) + if(!decryption_time && (timer_warning != NUKE_DECRYPT_SHOW_TIMER_COMPLETE)) + return ..() + + var/list/humans_other = GLOB.human_mob_list + GLOB.dead_mob_list + var/list/humans_uscm = list() + for(var/mob/current_mob as anything in humans_other) + var/mob/living/carbon/human/current_human = current_mob + if(istype(current_human)) //if it's unconsious human or yautja, we remove them + if(current_human.stat != CONSCIOUS || isyautja(current_human)) + humans_other -= current_mob + continue + if(current_mob.faction == FACTION_MARINE || current_mob.faction == FACTION_SURVIVOR) + humans_uscm += current_mob + humans_other -= current_mob + + if(timer_warning) + if(timer_warning == NUKE_DECRYPT_SHOW_TIMER_COMPLETE) + announcement_helper("DECRYPTION COMPLETE", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') + announcement_helper("DECRYPTION COMPLETE", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') + + yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!\n\nThe human Purification Device is able to be activated.")) + + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + return + xeno_announcement(SPAN_XENOANNOUNCE("The hive killer is ready to be activated! Assault at once!"), hive.hivenumber, XENO_GENERAL_ANNOUNCE) + return + + announcement_helper("DECRYPTION IN [round(decryption_time/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') + announcement_helper("DECRYPTION IN [round(decryption_time/10)] SECONDS.", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') + + //preds part + var/time_left = duration2text_sec(round(rand(decryption_time - decryption_time / 10, decryption_time + decryption_time / 10))) + yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!\n\nYou have approximately [time_left] seconds to abandon the hunting grounds before human Purification Device is able to be activated.")) + + //xenos part + var/warning = "Hive killer is almost prepared to be activated!" + if(timer_warning & NUKE_DECRYPT_SHOW_TIMER_HALF) + warning = "Hive killer is halfway through its initial phase!" + + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!hive.totalXenos.len) + return + xeno_announcement(SPAN_XENOANNOUNCE(warning), hive.hivenumber, XENO_GENERAL_ANNOUNCE) + return + + var/datum/hive_status/hive + if(decrypting) + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DECRYPTION STARTED.\n\nDECRYPTION IN [round(decryption_time/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DECRYPTION STARTED.\n\nDECRYPTION IN [round(decryption_time/10)] SECONDS.", "HQ Nuclear Tracker", humans_other, 'sound/misc/notice1.ogg') + var/time_left = duration2text_sec(round(rand(decryption_time - decryption_time / 10, decryption_time + decryption_time / 10))) + yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!
A human Purification Device has been detected. You have approximately [time_left] before it finishes its initial phase.")) + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + continue + xeno_announcement(SPAN_XENOANNOUNCE("The tallhosts have started the initial phase of a hive killer at [get_area_name(loc)]! Destroy their communications relays!"), hive.hivenumber, XENO_GENERAL_ANNOUNCE) + return + + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE DECRYPTION HALTED.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE DECRYPTION HALTED.", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') + yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!
The human Purification Device's signature has disappeared.")) + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + continue + xeno_announcement(SPAN_XENOANNOUNCE("The hive killer's initial phase has been halted! Rejoice!"), hive.hivenumber, XENO_GENERAL_ANNOUNCE) + +/obj/structure/machinery/nuclearbomb/tech/proc/connected_comm_shutdown(obj/structure/machinery/telecomms/relay/preset/tower/telecomm_unit) + SIGNAL_HANDLER + + if(!decrypting) + return + + decrypting = FALSE + announce_to_players() diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 1ef3a326485d..7855f446c805 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -11,7 +11,7 @@ black_market_value = 35 var/obj/item/charging = null var/percent_charge_complete = 0 - var/list/allowed_devices = list(/obj/item/weapon/baton, /obj/item/cell, /obj/item/weapon/gun/energy, /obj/item/device/defibrillator, /obj/item/tool/portadialysis, /obj/item/clothing/suit/auto_cpr) + var/list/allowed_devices = list(/obj/item/weapon/baton, /obj/item/cell, /obj/item/weapon/gun/energy, /obj/item/device/defibrillator, /obj/item/tool/portadialysis, /obj/item/clothing/suit/auto_cpr, /obj/item/smartgun_battery) var/charge_amount = 1000 @@ -166,6 +166,21 @@ update_icon() return + if(istype(charging, /obj/item/smartgun_battery)) + var/obj/item/smartgun_battery/charging_smartgun_battery = charging + if(charging_smartgun_battery.power_cell) + if(!charging_smartgun_battery.power_cell.fully_charged()) + charging_smartgun_battery.power_cell.give(charge_amount) + percent_charge_complete = charging_smartgun_battery.power_cell.percent() + update_use_power(USE_POWER_ACTIVE) + update_icon() + return + + percent_charge_complete = 100 + update_use_power(USE_POWER_IDLE) + update_icon() + return + /* Disable defib recharging if(istype(charging, /obj/item/device/defibrillator)) var/obj/item/device/defibrillator/D = charging diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 66f3a92cbdf2..644402128852 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -1,8 +1,8 @@ /obj/structure/machinery/recharge_station - name = "robot recharge station" + name = "synthetic maintenance station" icon = 'icons/obj/objects.dmi' icon_state = "borgcharger0" - desc = "A recharge and repair station for robots and synthetics. Simply put the synthetic in need of repair in here and they will be fixed up in no time!" + desc = "A Synthetic Maintenance Station designed to recharge, repair and maintain various sizes of artificial people. Simply place the synthetic or android in need of repair in here and they will be fixed up in no time!" density = TRUE anchored = TRUE use_power = USE_POWER_IDLE @@ -14,8 +14,10 @@ var/charging_cap_active = 25000 // Active Cap - When cyborg is inside var/charging_cap_passive = 2500 // Passive Cap - Recharging internal capacitor when no cyborg is inside var/icon_update_tick = 0 // Used to update icon only once every 10 ticks + var/known_implants = list(/obj/item/implant/chem, /obj/item/implant/death_alarm, /obj/item/implant/loyalty, /obj/item/implant/tracking, /obj/item/implant/neurostim) can_buckle = TRUE + /obj/structure/machinery/recharge_station/Initialize(mapload, ...) . = ..() update_icon() @@ -157,21 +159,42 @@ doing_stuff = TRUE else update_use_power(USE_POWER_IDLE) - if (isrobot(occupant) || issynth(occupant)) + if (issynth(occupant)) + var/mob/living/carbon/human/humanoid_occupant = occupant //for special synth surgeries if(occupant.getBruteLoss() > 0 || occupant.getFireLoss() > 0 || occupant.getBrainLoss() > 0) occupant.heal_overall_damage(10, 10, TRUE) occupant.apply_damage(-10, BRAIN) current_internal_charge = max(current_internal_charge - 500, 0) - to_chat(occupant, "Repairing...") + to_chat(occupant, "Structural damage detected. Repairing...") doing_stuff = TRUE occupant.pain.recalculate_pain() if(!doing_stuff && occupant.blood_volume < initial(occupant.blood_volume)) occupant.blood_volume = min(occupant.blood_volume + 10, initial(occupant.blood_volume)) - to_chat(occupant, "Refreshing liquids...") + to_chat(occupant, "Fluid volume low. Refreshing liquids...") doing_stuff = TRUE + if(!doing_stuff) + for(var/obj/limb/current_limb in humanoid_occupant.limbs) + if(current_limb.implants.len) + doing_stuff = TRUE + to_chat(occupant, "Foreign material detected. Beginning removal process...") + for(var/obj/item/current_implant in current_limb.implants) + if(!is_type_in_list(current_implant,known_implants)) + sleep(REMOVE_OBJECT_MAX_DURATION) + current_limb.implants -= current_implant + humanoid_occupant.embedded_items -= current_implant + qdel(current_implant) + to_chat(occupant, "Foreign object removed.") + for(var/datum/internal_organ/current_organ in humanoid_occupant.internal_organs) + if(current_organ.robotic == ORGAN_ASSISTED||current_organ.robotic == ORGAN_ROBOT) //this time the machine can *only* fix robotic organs + if(current_organ.damage > 0) + to_chat(occupant, "Damaged internal component detected. Beginning repair process.") + doing_stuff = TRUE + sleep(FIX_ORGAN_MAX_DURATION) + current_organ.rejuvenate() + to_chat(occupant, "Internal component repaired.") if(!doing_stuff) - to_chat(occupant, "Maintenance complete! Have a nice day!") + to_chat(occupant, "Maintenance cycle completed. All systems nominal.") go_out() diff --git a/code/game/machinery/storm_siren.dm b/code/game/machinery/storm_siren.dm new file mode 100644 index 000000000000..e78414cb7e5b --- /dev/null +++ b/code/game/machinery/storm_siren.dm @@ -0,0 +1,26 @@ +/obj/structure/machinery/storm_siren + name = "storm siren" + desc = "A siren used to announce storm warnings for the colony." + icon = 'icons/obj/structures/machinery/loudspeaker.dmi' + icon_state = "loudspeaker" + density = FALSE + anchored = TRUE + unacidable = 1 + unslashable = 1 + use_power = USE_POWER_NONE + health = 0 + +/obj/structure/machinery/storm_siren/Initialize() + weather_notify_objects += src + return ..() + +/obj/structure/machinery/storm_siren/Destroy() + weather_notify_objects -= src + . = ..() + +/obj/structure/machinery/storm_siren/power_change() + return + +/obj/structure/machinery/storm_siren/proc/weather_warning() + playsound(loc, 'sound/effects/weather_warning_varadero.ogg', 60, 0) + visible_message(SPAN_DANGER("The storm siren blares: ATTENTION. ATTENTION. INCOMING TROPICAL STORM DETECTED. SEEK SHELTER IMMEDIATELY.")) diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index cded8a1148c7..a370356ad60b 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -62,7 +62,7 @@ stat &= ~BROKEN // the machine's not borked anymore! else to_chat(user, SPAN_WARNING("You need five coils of wire for this.")) - if(istype(P, /obj/item/tool/crowbar)) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR)) to_chat(user, "You begin prying out the circuit board other components...") playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) if(do_after(user, 60 * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm index 7deb24fb43c2..47d4bb20849b 100644 --- a/code/game/machinery/telecomms/presets.dm +++ b/code/game/machinery/telecomms/presets.dm @@ -50,7 +50,7 @@ . = ..() if(z) - SSminimaps.add_marker(src, z, MINIMAP_FLAG_USCM, "supply") + SSminimaps.add_marker(src, z, MINIMAP_FLAG_ALL, "supply") // doesn't need power, instead uses health /obj/structure/machinery/telecomms/relay/preset/tower/inoperable(additional_flags) @@ -60,11 +60,11 @@ return TRUE return FALSE -/obj/structure/machinery/telecomms/relay/preset/tower/tcomms_startup() +/obj/structure/machinery/telecomms/relay/preset/tower/update_state() . = ..() if(on) playsound(src, 'sound/machines/tcomms_on.ogg', vol = 80, vary = FALSE, sound_range = 16, falloff = 0.5) - msg_admin_niche("Portable communication relay started for Z-Level [src.z] (JMP)") + msg_admin_niche("Portable communication relay started for Z-Level [src.z] [ADMIN_JMP(src)]") if(SSobjectives && SSobjectives.comms) // This is the first time colony comms have been established. @@ -74,7 +74,7 @@ /obj/structure/machinery/telecomms/relay/preset/tower/tcomms_shutdown() . = ..() if(!on) - msg_admin_niche("Portable communication relay shut down for Z-Level [src.z] (JMP)") + msg_admin_niche("Portable communication relay shut down for Z-Level [src.z] [ADMIN_JMP(src)]") /obj/structure/machinery/telecomms/relay/preset/tower/bullet_act(obj/item/projectile/P) ..() @@ -212,12 +212,27 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) freq_listening = list(COLONY_FREQ) var/toggle_cooldown = 0 + /// Tower has been taken over by xenos, is not usable + var/corrupted = FALSE + + /// Held image for the current overlay on the tower from xeno corruption + var/image/corruption_image + +/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/Initialize() + . = ..() + + RegisterSignal(src, COMSIG_ATOM_TURF_CHANGE, PROC_REF(register_with_turf)) + register_with_turf() + /obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/attack_hand(mob/user) if(user.action_busy) return if(toggle_cooldown > world.time) //cooldown only to prevent spam toggling to_chat(user, SPAN_WARNING("\The [src]'s processors are still cooling! Wait before trying to flip the switch again.")) return + if(corrupted) + to_chat(user, SPAN_WARNING("[src] is entangled in resin. Impossible to interact with.")) + return var/current_state = on if(!do_after(user, 20, INTERRUPT_NO_NEEDHAND|BEHAVIOR_IMMOBILE, BUSY_ICON_FRIENDLY, src)) return @@ -235,10 +250,10 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) var/area/commarea = get_area(src) if(on) //now, if it went on it now uses power use_power = USE_POWER_IDLE - message_admins("[key_name(user)] turned \the [src] in [commarea] ON. (JMP)") + message_admins("[key_name(user)] turned \the [src] in [commarea] ON. [ADMIN_JMP(commloc.loc)]") else use_power = USE_POWER_NONE - message_admins("[key_name(user)] turned \the [src] in [commarea] OFF. (JMP)") + message_admins("[key_name(user)] turned \the [src] in [commarea] OFF. [ADMIN_JMP(commloc.loc)]") toggle_cooldown = world.time + 40 /obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/attackby(obj/item/I, mob/user) @@ -282,6 +297,84 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) else update_icon() +/// Handles xenos corrupting the tower when weeds touch the turf it is located on +/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/proc/handle_xeno_acquisition(turf/weeded_turf) + SIGNAL_HANDLER + + if(corrupted) + return + + if(!weeded_turf.weeds) + return + + if(weeded_turf.weeds.weed_strength < WEED_LEVEL_HIVE) + return + + if(!weeded_turf.weeds.parent) + return + + if(!istype(weeded_turf.weeds.parent, /obj/effect/alien/weeds/node/pylon/cluster)) + return + + if(SSticker.mode.is_in_endgame) + return + + if(ROUND_TIME < XENO_COMM_ACQUISITION_TIME) + addtimer(CALLBACK(src, PROC_REF(handle_xeno_acquisition), weeded_turf), (XENO_COMM_ACQUISITION_TIME - ROUND_TIME)) + return + + var/obj/effect/alien/weeds/node/pylon/cluster/parent_node = weeded_turf.weeds.parent + + var/obj/effect/alien/resin/special/cluster/cluster_parent = parent_node.resin_parent + + var/list/held_children_weeds = parent_node.children + var/cluster_loc = cluster_parent.loc + var/linked_hive = cluster_parent.linked_hive + + parent_node.children = list() + + qdel(cluster_parent) + + var/obj/effect/alien/resin/special/pylon/endgame/new_pylon = new(cluster_loc, linked_hive) + new_pylon.node.children = held_children_weeds + + for(var/obj/effect/alien/weeds/weed in new_pylon.node.children) + weed.parent = new_pylon.node + + RegisterSignal(new_pylon, COMSIG_PARENT_QDELETING, PROC_REF(uncorrupt)) + + corrupted = TRUE + + corruption_image = image(icon, icon_state = "resin_growing") + + flick_overlay(src, corruption_image, (2 SECONDS)) + addtimer(CALLBACK(src, PROC_REF(switch_to_idle_corruption)), (2 SECONDS)) + + new_pylon.comms_relay_connection() + +/// Handles removing corruption effects from the comms relay +/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/proc/uncorrupt(datum/deleting_datum) + SIGNAL_HANDLER + + corrupted = FALSE + + overlays -= corruption_image + +/// Handles moving the overlay from growing to idle +/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/proc/switch_to_idle_corruption() + if(!corrupted) + return + + corruption_image = image(icon, icon_state = "resin_idle") + + overlays += corruption_image + +/// Handles re-registering signals on new turfs if changed +/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/proc/register_with_turf() + SIGNAL_HANDLER + + RegisterSignal(get_turf(src), COMSIG_WEEDNODE_GROWTH, PROC_REF(handle_xeno_acquisition)) + /obj/structure/machinery/telecomms/relay/preset/telecomms id = "Telecomms Relay" autolinkers = list("relay") diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 324a358d041f..255d70f45870 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -71,6 +71,9 @@ GLOBAL_LIST_EMPTY_TYPED(telecomms_list, /obj/structure/machinery/telecomms) // When effectively shut down /obj/structure/machinery/telecomms/proc/tcomms_shutdown() on = FALSE + + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_GROUNDSIDE_TELECOMM_TURNED_OFF) + if(tcomms_machine) SSradio.remove_tcomm_machine(src) diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index 8cfb6c44f7d2..bf7c4fffee65 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -118,7 +118,11 @@ GLOBAL_LIST_EMPTY(vending_products) if (!item_name || item_name == "" || !typepath) continue - GLOB.vending_products[typepath] = 1 + if(islist(typepath)) + for(var/path in typepath) + GLOB.vending_products[path] = 1 + else + GLOB.vending_products[typepath] = 1 //get which turf the vendor will dispense its products on. /obj/structure/machinery/cm_vending/proc/get_appropriate_vend_turf() @@ -140,7 +144,7 @@ GLOBAL_LIST_EMPTY(vending_products) hacked = !hacked if(hacked) - to_chat(user, SPAN_WARNING("You have succesfully removed access restrictions in [src].")) + to_chat(user, SPAN_WARNING("You have successfully removed access restrictions in [src].")) if(user && is_mainship_level(z)) SSclues.create_print(get_turf(user), user, "A small piece of cut wire is found on the fingerprint.") else @@ -468,7 +472,7 @@ GLOBAL_LIST_EMPTY(vending_products) to_chat(user, SPAN_WARNING("Only specialists can take specialist sets.")) vend_fail() return FALSE - else if(!user.skills || user.skills.get_skill_level(SKILL_SPEC_WEAPONS) != SKILL_SPEC_ALL) + else if(!user.skills || user.skills.get_skill_level(SKILL_SPEC_WEAPONS) != SKILL_SPEC_TRAINED) to_chat(user, SPAN_WARNING("You already have a specialization.")) vend_fail() return FALSE @@ -752,7 +756,7 @@ GLOBAL_LIST_EMPTY(vending_products) /obj/structure/machinery/cm_vending/gear name = "ColMarTech Automated Gear Rack" desc = "An automated equipment rack hooked up to a colossal storage of standard-issue gear." - icon_state = "gear_rack" + icon_state = "gear" use_points = TRUE vendor_theme = VENDOR_THEME_USCM vend_flags = VEND_CLUTTER_PROTECTION|VEND_CATEGORY_CHECK|VEND_TO_HAND @@ -786,7 +790,7 @@ GLOBAL_LIST_EMPTY(vending_products) /obj/structure/machinery/cm_vending/sorted name = "\improper ColMarTech generic sorted rack/vendor" desc = "This is pure vendor without points system." - icon_state = "guns_rack" + icon_state = "guns" vendor_theme = VENDOR_THEME_USCM vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_TO_HAND show_points = FALSE @@ -903,7 +907,7 @@ GLOBAL_LIST_EMPTY(vending_products) /obj/structure/machinery/cm_vending/own_points name = "\improper ColMarTech generic vendor" desc = "This is a vendor with its own points system." - icon_state = "guns_rack" + icon_state = "gear" vendor_theme = VENDOR_THEME_USCM use_points = TRUE use_snowflake_points = FALSE @@ -1059,10 +1063,10 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( var/p_name = myprod[1] //taking it's name var/p_cost = cost_index == null ? 0 : myprod[cost_index] - var/item_ref = myprod[3] + var/obj/item/item_ref = myprod[3] var/priority = myprod[priority_index] - - var/obj/item/I = item_ref + if(islist(item_ref)) // multi-vending + item_ref = item_ref[1] var/is_category = item_ref == null @@ -1073,7 +1077,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( "prod_index" = i, "prod_name" = p_name, "prod_color" = priority, - "prod_desc" = initial(I.desc), + "prod_desc" = initial(item_ref.desc), "prod_cost" = p_cost, "image" = imgid ) @@ -1123,24 +1127,23 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( var/list/stock_values = list() - var/mob/living/carbon/human/H = user - var/buy_flags = H.marine_buy_flags + var/mob/living/carbon/human/marine = user var/points = 0 if(vending_machine.instanced_vendor_points) points = vending_machine.available_points_to_display else if(vending_machine.use_snowflake_points) - points = H.marine_snowflake_points + points = marine.marine_snowflake_points else if(vending_machine.use_points) - points = H.marine_points + points = marine.marine_points for (var/i in 1 to length(ui_listed_products)) var/list/myprod = ui_listed_products[i] //we take one list from listed_products var/prod_available = FALSE var/p_cost = myprod[2] - var/avail_flag = myprod[4] - if(points >= p_cost && (!avail_flag || buy_flags & avail_flag)) + var/category = myprod[4] + if(points >= p_cost && (!category || ((category in marine.marine_buyable_categories) && (marine.marine_buyable_categories[category])))) prod_available = TRUE stock_values += list(prod_available) @@ -1153,7 +1156,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( vendor.stat |= IN_USE var/vend_flags = vendor.vend_flags - var/turf/target_turf = vendor.get_appropriate_vend_turf(user) if(LAZYLEN(itemspec)) //making sure it's not empty if(vendor.vend_delay) @@ -1164,84 +1166,106 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( sleep(vendor.vend_delay) var/prod_type = itemspec[3] - - var/obj/item/new_item - if(ispath(prod_type, /obj/item)) - if(ispath(prod_type, /obj/item/weapon/gun)) - new_item = new prod_type(target_turf, TRUE) - else - if(prod_type == /obj/item/device/radio/headset/almayer/marine) - prod_type = vendor.headset_type - else if(prod_type == /obj/item/clothing/gloves/marine) - prod_type = vendor.gloves_type - new_item = new prod_type(target_turf) - new_item.add_fingerprint(user) + if(islist(prod_type)) + for(var/each_type in prod_type) + vendor_successful_vend_one(vendor, each_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) else - new_item = new prod_type(target_turf) + vendor_successful_vend_one(vendor, prod_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) if(vend_flags & VEND_LIMITED_INVENTORY) itemspec[2]-- if(vend_flags & VEND_LOAD_AMMO_BOXES) vendor.update_derived_ammo_and_boxes(itemspec) - if(vend_flags & VEND_UNIFORM_RANKS) - // apply ranks to clothing - var/bitf = itemspec[4] - if(bitf) - if(bitf == MARINE_CAN_BUY_UNIFORM) - var/obj/item/clothing/under/underclothes = new_item - //Gives ranks to the ranked - if(user.wear_id && user.wear_id.paygrade) - var/rankpath = get_rank_pins(user.wear_id.paygrade) - if(rankpath) - var/obj/item/clothing/accessory/ranks/rank_insignia = new rankpath() - underclothes.attach_accessory(user, rank_insignia) - - if(vend_flags & VEND_UNIFORM_AUTOEQUIP) - // autoequip - if(istype(new_item, /obj/item) && new_item.flags_equip_slot != NO_FLAGS) //auto-equipping feature here - if(new_item.flags_equip_slot == SLOT_ACCESSORY) - if(user.w_uniform) - var/obj/item/clothing/clothing = user.w_uniform - if(clothing.can_attach_accessory(new_item)) - clothing.attach_accessory(user, new_item) - else - user.equip_to_appropriate_slot(new_item) - - if(vend_flags & VEND_TO_HAND) - if(user.client?.prefs && (user.client?.prefs?.toggle_prefs & TOGGLE_VEND_ITEM_TO_HAND)) - if(vendor.Adjacent(user)) - user.put_in_any_hand_if_possible(new_item, disable_warning = TRUE) else to_chat(user, SPAN_WARNING("ERROR: itemspec is missing. Please report this to admins.")) sleep(15) vendor.stat &= ~IN_USE + vendor.icon_state = initial(vendor.icon_state) vendor.update_icon() +/proc/vendor_successful_vend_one(obj/structure/machinery/cm_vending/vendor, prod_type, mob/living/carbon/human/user, turf/target_turf, insignas_override) + var/obj/item/new_item + var/vend_flags = vendor.vend_flags + if(ispath(prod_type, /obj/item)) + if(ispath(prod_type, /obj/item/weapon/gun)) + new_item = new prod_type(target_turf, TRUE) + else + if(prod_type == /obj/item/device/radio/headset/almayer/marine) + prod_type = vendor.headset_type + else if(prod_type == /obj/item/clothing/gloves/marine) + prod_type = vendor.gloves_type + new_item = new prod_type(target_turf) + new_item.add_fingerprint(user) + else + new_item = new prod_type(target_turf) + + if(vend_flags & VEND_UNIFORM_RANKS) + if(insignas_override) + var/obj/item/clothing/under/underclothes = new_item + //Gives ranks to the ranked + if(istype(underclothes) && user.wear_id && user.wear_id.paygrade) + var/rankpath = get_rank_pins(user.wear_id.paygrade) + if(rankpath) + var/obj/item/clothing/accessory/ranks/rank_insignia = new rankpath() + underclothes.attach_accessory(user, rank_insignia) + + if(vend_flags & VEND_UNIFORM_AUTOEQUIP) + // autoequip + if(istype(new_item, /obj/item) && new_item.flags_equip_slot != NO_FLAGS) //auto-equipping feature here + if(new_item.flags_equip_slot == SLOT_ACCESSORY) + if(user.w_uniform) + var/obj/item/clothing/clothing = user.w_uniform + if(clothing.can_attach_accessory(new_item)) + clothing.attach_accessory(user, new_item) + else + user.equip_to_appropriate_slot(new_item) + + if(vend_flags & VEND_TO_HAND) + if(user.client?.prefs && (user.client?.prefs?.toggle_prefs & TOGGLE_VEND_ITEM_TO_HAND)) + if(vendor.Adjacent(user)) + user.put_in_any_hand_if_possible(new_item, disable_warning = TRUE) + + new_item.post_vendor_spawn_hook(user) + /proc/handle_vend(obj/structure/machinery/cm_vending/vendor, list/listed_products, mob/living/carbon/human/vending_human) if(vendor.vend_flags & VEND_USE_VENDOR_FLAGS) return TRUE - var/can_buy_flags = listed_products[4] - if(!(vending_human.marine_buy_flags & can_buy_flags)) - return FALSE - - if(can_buy_flags == (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH)) - if(vending_human.marine_buy_flags & MARINE_CAN_BUY_R_POUCH) - vending_human.marine_buy_flags &= ~MARINE_CAN_BUY_R_POUCH - else - vending_human.marine_buy_flags &= ~MARINE_CAN_BUY_L_POUCH - return TRUE - if(can_buy_flags == (MARINE_CAN_BUY_COMBAT_R_POUCH|MARINE_CAN_BUY_COMBAT_L_POUCH)) - if(vending_human.marine_buy_flags & MARINE_CAN_BUY_COMBAT_R_POUCH) - vending_human.marine_buy_flags &= ~MARINE_CAN_BUY_COMBAT_R_POUCH - else - vending_human.marine_buy_flags &= ~MARINE_CAN_BUY_COMBAT_L_POUCH - return TRUE - - vending_human.marine_buy_flags &= ~can_buy_flags + var/buying_category = listed_products[4] + if(buying_category) + if(!(buying_category in vending_human.marine_buyable_categories)) + return FALSE + if(!vending_human.marine_buyable_categories[buying_category]) + return FALSE + vending_human.marine_buyable_categories[buying_category] -= 1 return TRUE +// Unload ALL the items throwing them around randomly, optionally destroying the vendor +/obj/structure/machinery/cm_vending/proc/catastrophic_failure(throw_objects = TRUE, destroy = FALSE) + stat |= IN_USE + var/list/products = get_listed_products() + var/i = 1 + while(i <= length(products)) + sleep(0.5) + var/list/itemspec = products[i] + if(!itemspec[2] || itemspec[2] <= 0) + i++ + continue + itemspec[2] -= 1 + var/list/spawned = list() + if(islist(itemspec[3])) + for(var/path in itemspec[3]) + spawned += new path(loc) + else if(itemspec[3]) + var/path = itemspec[3] + spawned += new path(loc) + if(throw_objects) + for(var/atom/movable/spawned_atom in spawned) + INVOKE_ASYNC(spawned_atom, TYPE_PROC_REF(/atom/movable, throw_atom), pick(orange(src, 4)), 4, SPEED_FAST) + stat &= ~IN_USE + if(destroy) + qdel(src) //------------HACKING--------------- diff --git a/code/game/machinery/vending/essential_sets.dm b/code/game/machinery/vending/essential_sets.dm index 7d28b00199b0..711b17eb2c3e 100644 --- a/code/game/machinery/vending/essential_sets.dm +++ b/code/game/machinery/vending/essential_sets.dm @@ -57,3 +57,4 @@ /obj/item/clothing/shoes/dress, /obj/item/storage/large_holster/ceremonial_sword/full, ) + diff --git a/code/game/machinery/vending/vending.dm b/code/game/machinery/vending/vending.dm index 959d10270494..a74dd923cbe7 100644 --- a/code/game/machinery/vending/vending.dm +++ b/code/game/machinery/vending/vending.dm @@ -21,7 +21,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending) /obj/structure/machinery/vending - name = "Vendomat" + name = "\improper Vendomat" desc = "A generic vending machine." icon = 'icons/obj/structures/machinery/vending.dmi' icon_state = "generic" @@ -47,7 +47,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending // To be filled out at compile time var/list/products = list() // For each, use the following pattern: - var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2) + var/list/contraband = list() // list(/type/path = amount, /type/path2 = amount2) var/list/premium = list() // No specified amount = only one in stock var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price. @@ -102,17 +102,17 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending /obj/structure/machinery/vending/Initialize(mapload, ...) . = ..() LAZYADD(GLOB.total_vending_machines, src) - src.slogan_list = splittext(src.product_slogans, ";") + slogan_list = splittext(product_slogans, ";") // So not all machines speak at the exact same time. // The first time this machine says something will be at slogantime + this random value, // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. - src.last_slogan = world.time + rand(0, slogan_delay) + last_slogan = world.time + rand(0, slogan_delay) - src.build_inventory(products) + build_inventory(products) //Add hidden inventory - src.build_inventory(contraband, 1) - src.build_inventory(premium, 0, 1) + build_inventory(contraband, 1) + build_inventory(premium, 0, 1) power_change() start_processing() @@ -123,7 +123,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending /obj/structure/machinery/vending/update_icon() overlays.Cut() if(panel_open) - overlays += image(src.icon, "[initial(icon_state)]-panel") + overlays += image(icon, "[initial(icon_state)]-panel") if(stat & BROKEN) icon_state = "[initial(icon_state)]-broken" else if(stat & NOPOWER) @@ -145,7 +145,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending /obj/structure/machinery/vending/proc/select_gamemode_equipment(gamemode) return -/obj/structure/machinery/vending/proc/build_inventory(list/productlist,hidden=0,req_coin=0) +/obj/structure/machinery/vending/proc/build_inventory(list/productlist, hidden = FALSE, req_coin = FALSE) for(var/typepath in productlist) var/amount = productlist[typepath] @@ -153,28 +153,28 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending if(isnull(amount)) amount = 1 var/obj/item/temp_path = typepath - var/datum/data/vending_product/R = new /datum/data/vending_product() + var/datum/data/vending_product/product = new /datum/data/vending_product() - R.product_path = typepath - R.amount = amount - R.price = price - R.max_amount = amount + product.product_path = typepath + product.amount = amount + product.price = price + product.max_amount = amount - if(ispath(typepath,/obj/item/weapon/gun) || ispath(typepath,/obj/item/ammo_magazine) || ispath(typepath,/obj/item/explosive/grenade) || ispath(typepath,/obj/item/weapon/gun/flamer) || ispath(typepath,/obj/item/storage) ) - R.display_color = "black" + if(ispath(typepath, /obj/item/weapon/gun) || ispath(typepath, /obj/item/ammo_magazine) || ispath(typepath, /obj/item/explosive/grenade) || ispath(typepath, /obj/item/weapon/gun/flamer) || ispath(typepath, /obj/item/storage) ) + product.display_color = "black" else - R.display_color = "white" + product.display_color = "white" if(hidden) - R.category=CAT_HIDDEN - hidden_records += R + product.category=CAT_HIDDEN + hidden_records += product else if(req_coin) - R.category=CAT_COIN - coin_records += R + product.category=CAT_COIN + coin_records += product else - product_records += R + product_records += product - R.product_name = initial(temp_path.name) + product.product_name = initial(temp_path.name) /obj/structure/machinery/vending/get_repair_move_text(include_name = TRUE) if(!stat) @@ -196,35 +196,35 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending else return "[nominative] is being affected by some power-related issue." -/obj/structure/machinery/vending/attackby(obj/item/W, mob/user) +/obj/structure/machinery/vending/attackby(obj/item/item, mob/user) if(is_tipped_over) to_chat(user, "Tip it back upright first!") return FALSE - if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) + if(HAS_TRAIT(item, TRAIT_TOOL_SCREWDRIVER)) if(stat == WORKING) - src.panel_open = !src.panel_open - to_chat(user, "You [src.panel_open ? "open" : "close"] the maintenance panel.") + panel_open = !panel_open + to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") update_icon() return TRUE else if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) to_chat(user, SPAN_WARNING("You do not understand how to repair the broken [src].")) return FALSE else if(stat & BROKEN) - to_chat(user, SPAN_NOTICE("You start to unscrew \the [src]'s broken panel.")) + to_chat(user, SPAN_NOTICE("You start to unscrew the [src]'s broken panel.")) if(!do_after(user, 3 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD, numticks = 3)) - to_chat(user, SPAN_WARNING("You stop unscrewing \the [src]'s broken panel.")) + to_chat(user, SPAN_WARNING("You stop unscrewing the [src]'s broken panel.")) return FALSE - to_chat(user, SPAN_NOTICE("You unscrew \the [src]'s broken panel and remove it, exposing many broken wires.")) + to_chat(user, SPAN_NOTICE("You unscrew the [src]'s broken panel and remove it, exposing many broken wires.")) stat &= ~BROKEN stat |= REPAIR_STEP_ONE return TRUE else if(stat & REPAIR_STEP_FOUR) - to_chat(user, SPAN_NOTICE("You start to fasten \the [src]'s new panel.")) + to_chat(user, SPAN_NOTICE("You start to fasten the [src]'s new panel.")) if(!do_after(user, 3 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD, numticks = 3)) - to_chat(user, SPAN_WARNING("You stop fastening \the [src]'s new panel.")) + to_chat(user, SPAN_WARNING("You stop fastening the [src]'s new panel.")) return FALSE - to_chat(user, SPAN_NOTICE("You fasten \the [src]'s new panel, fully repairing the vendor.")) + to_chat(user, SPAN_NOTICE("You fasten the [src]'s new panel, fully repairing the vendor.")) stat &= ~REPAIR_STEP_FOUR stat |= FULLY_REPAIRED update_icon() @@ -233,7 +233,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending var/msg = get_repair_move_text() to_chat(user, SPAN_WARNING("[msg]")) return FALSE - else if(HAS_TRAIT(W, TRAIT_TOOL_WIRECUTTERS)) + else if(HAS_TRAIT(item, TRAIT_TOOL_WIRECUTTERS)) if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) to_chat(user, SPAN_WARNING("You do not understand how to repair the broken [src].")) return FALSE @@ -241,11 +241,11 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending attack_hand(user) return else if(stat & REPAIR_STEP_ONE) - to_chat(user, SPAN_NOTICE("You start to remove \the [src]'s broken wires.")) + to_chat(user, SPAN_NOTICE("You start to remove the [src]'s broken wires.")) if(!do_after(user, 3 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD, numticks = 3)) - to_chat(user, SPAN_WARNING("You stop removing \the [src]'s broken wires.")) + to_chat(user, SPAN_WARNING("You stop removing the [src]'s broken wires.")) return FALSE - to_chat(user, SPAN_NOTICE("You remove \the [src]'s broken broken wires.")) + to_chat(user, SPAN_NOTICE("You remove the [src]'s broken broken wires.")) stat &= ~REPAIR_STEP_ONE stat |= REPAIR_STEP_TWO return TRUE @@ -253,22 +253,22 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending var/msg = get_repair_move_text() to_chat(user, SPAN_WARNING("[msg]")) return FALSE - else if(istype(W, /obj/item/stack/cable_coil)) + else if(istype(item, /obj/item/stack/cable_coil)) if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) to_chat(user, SPAN_WARNING("You do not understand how to repair the broken [src].")) return FALSE - var/obj/item/stack/cable_coil/CC = W + var/obj/item/stack/cable_coil/CC = item if(stat & REPAIR_STEP_TWO) if(CC.amount < 5) to_chat(user, SPAN_WARNING("You need more cable coil to replace the removed wires.")) - to_chat(user, SPAN_NOTICE("You start to replace \the [src]'s removed wires.")) + to_chat(user, SPAN_NOTICE("You start to replace the [src]'s removed wires.")) if(!do_after(user, 3 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD, numticks = 3)) - to_chat(user, SPAN_WARNING("You stop replacing \the [src]'s removed wires.")) + to_chat(user, SPAN_WARNING("You stop replacing the [src]'s removed wires.")) return FALSE if(!CC || !CC.use(5)) to_chat(user, SPAN_WARNING("You need more cable coil to replace the removed wires.")) return FALSE - to_chat(user, SPAN_NOTICE("You remove \the [src]'s broken broken wires.")) + to_chat(user, SPAN_NOTICE("You remove the [src]'s broken broken wires.")) stat &= ~REPAIR_STEP_TWO stat |= REPAIR_STEP_THREE return TRUE @@ -276,20 +276,20 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending var/msg = get_repair_move_text() to_chat(user, SPAN_WARNING("[msg]")) return - else if(istype(W, /obj/item/stack/sheet/metal)) + else if(istype(item, /obj/item/stack/sheet/metal)) if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) to_chat(user, SPAN_WARNING("You do not understand how to repair the broken [src].")) return FALSE - var/obj/item/stack/sheet/metal/M = W + var/obj/item/stack/sheet/metal/M = item if(stat & REPAIR_STEP_THREE) - to_chat(user, SPAN_NOTICE("You start to construct a new panel for \the [src].")) + to_chat(user, SPAN_NOTICE("You start to construct a new panel for the [src].")) if(!do_after(user, 3 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD, numticks = 3)) - to_chat(user, SPAN_WARNING("You stop constructing a new panel for \the [src].")) + to_chat(user, SPAN_WARNING("You stop constructing a new panel for the [src].")) return FALSE if(!M || !M.use(1)) to_chat(user, SPAN_WARNING("You a sheet of metal to construct a new panel.")) return FALSE - to_chat(user, SPAN_NOTICE("You construct a new panel for \the [src].")) + to_chat(user, SPAN_NOTICE("You construct a new panel for the [src].")) stat &= ~REPAIR_STEP_THREE stat |= REPAIR_STEP_FOUR return TRUE @@ -297,48 +297,55 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending var/msg = get_repair_move_text() to_chat(user, SPAN_WARNING("[msg]")) return - else if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + else if(HAS_TRAIT(item, TRAIT_TOOL_WRENCH)) if(!wrenchable) return if(do_after(user, 20, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) if(!src) return - playsound(src.loc, 'sound/items/Ratchet.ogg', 25, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 25, 1) switch (anchored) if (0) anchored = TRUE - user.visible_message("[user] tightens the bolts securing \the [src] to the floor.", "You tighten the bolts securing \the [src] to the floor.") + user.visible_message("[user] tightens the bolts securing the [src] to the floor.", "You tighten the bolts securing the [src] to the floor.") if (1) - user.visible_message("[user] unfastens the bolts securing \the [src] to the floor.", "You unfasten the bolts securing \the [src] to the floor.") + user.visible_message("[user] unfastens the bolts securing the [src] to the floor.", "You unfasten the bolts securing the [src] to the floor.") anchored = FALSE return - else if(HAS_TRAIT(W, TRAIT_TOOL_MULTITOOL) || HAS_TRAIT(W, TRAIT_TOOL_WIRECUTTERS)) - if(src.panel_open) + else if(HAS_TRAIT(item, TRAIT_TOOL_MULTITOOL) || HAS_TRAIT(item, TRAIT_TOOL_WIRECUTTERS)) + if(panel_open) attack_hand(user) return - else if(istype(W, /obj/item/coin)) + else if(istype(item, /obj/item/coin)) if(coin) user.balloon_alert(user, "already a coin!") return - if(user.drop_inv_item_to_loc(W, src)) - coin = W - to_chat(user, SPAN_NOTICE(" You insert the [W] into the [src]")) + if(user.drop_inv_item_to_loc(item, src)) + coin = item + to_chat(user, SPAN_NOTICE(" You insert the [item] into the [src]")) tgui_interact(user) return + else if(istype(item, /obj/item/spacecash)) + if(inoperable()) + return + user.set_interaction(src) + if(seconds_electrified && shock(user, 100)) + return + tgui_interact(user) + return ..() -/obj/structure/machinery/vending/proc/scan_card(obj/item/card/I) +/obj/structure/machinery/vending/proc/scan_card(obj/item/card/card) if(!currently_vending) return - if (istype(I, /obj/item/card/id)) - var/obj/item/card/id/C = I + if (istype(card, /obj/item/card/id)) visible_message(SPAN_INFO("[usr] swipes a card through [src].")) - var/datum/money_account/CH = get_account(C.associated_account_number) + var/datum/money_account/CH = get_account(card.associated_account_number) if (CH) // Only proceed if card contains proper account number. if(!CH.suspended) if(CH.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) if(vendor_account) var/attempt_pin = tgui_input_number(usr, "Enter pin code", "Vendor transaction") - var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2) + var/datum/money_account/D = attempt_account_access(card.associated_account_number, attempt_pin, 2) transfer_and_vend(D) else to_chat(usr, "[icon2html(src, usr)] [SPAN_WARNING("Unable to access account. Check security settings and try again.")]") @@ -361,13 +368,13 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending //create entries in the two account transaction logs var/datum/transaction/T = new() - T.target_name = "[vendor_account.owner_name] (via [src.name])" + T.target_name = "[vendor_account.owner_name] (via [name])" T.purpose = "Purchase of [currently_vending.product_name]" if(transaction_amount > 0) T.amount = "([transaction_amount])" else T.amount = "[transaction_amount]" - T.source_terminal = src.name + T.source_terminal = name T.date = current_date_string T.time = worldtime2text() acc.transaction_log.Add(T) @@ -376,22 +383,22 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending T.target_name = acc.owner_name T.purpose = "Purchase of [currently_vending.product_name]" T.amount = "[transaction_amount]" - T.source_terminal = src.name + T.source_terminal = name T.date = current_date_string T.time = worldtime2text() vendor_account.transaction_log.Add(T) // Vend the item - src.vend(src.currently_vending, usr) + vend(currently_vending, usr) currently_vending = null else to_chat(usr, "[icon2html(src, usr)] [SPAN_WARNING("You don't have that much money!")]") else to_chat(usr, "[icon2html(src, usr)] [SPAN_WARNING("Error: Unable to access your account. Please contact technical support if problem persists.")]") -/obj/structure/machinery/vending/proc/GetProductIndex(datum/data/vending_product/P) +/obj/structure/machinery/vending/proc/GetProductIndex(datum/data/vending_product/product) var/list/plist - switch(P.category) + switch(product.category) if(CAT_NORMAL) plist=product_records if(CAT_HIDDEN) @@ -399,8 +406,8 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending if(CAT_COIN) plist=coin_records else - warning("UNKNOWN CATEGORY [P.category] IN TYPE [P.product_path] INSIDE [type]!") - return plist.Find(P) + warning("UNKNOWN CATEGORY [product.category] IN TYPE [product.product_path] INSIDE [type]!") + return plist.Find(product) /obj/structure/machinery/vending/proc/GetProductByID(pid, category) switch(category) @@ -418,9 +425,9 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending if(is_tipped_over) if(user.action_busy) return - user.visible_message(SPAN_NOTICE("[user] begins to heave the vending machine back into place!"),SPAN_NOTICE("You start heaving the vending machine back into place...")) + user.visible_message(SPAN_NOTICE("[user] begins to heave the [src] back into place!"), SPAN_NOTICE("You start heaving the [src] back into place...")) if(do_after(user, 80, INTERRUPT_NO_NEEDHAND, BUSY_ICON_FRIENDLY)) - user.visible_message(SPAN_NOTICE("[user] rights the [src]!"),SPAN_NOTICE("You right the [src]!")) + user.visible_message(SPAN_NOTICE("[user] rights the [src]!"), SPAN_NOTICE("You right the [src]!")) flip_back() return @@ -429,9 +436,8 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending user.set_interaction(src) - if(src.seconds_electrified != 0) - if(shock(user, 100)) - return + if(seconds_electrified && shock(user, 100)) + return tgui_interact(user) @@ -456,7 +462,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending return FALSE var/obj/item/held_item = user.get_held_item() if (!held_item || !HAS_TRAIT(held_item, TRAIT_TOOL_WIRECUTTERS)) - to_chat(user, "You need wirecutters!") + to_chat(user, "You need some wirecutters!") return TRUE var/wire = params["wire"] @@ -467,7 +473,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending return FALSE var/obj/item/held_item = user.get_held_item() if (!held_item || !HAS_TRAIT(held_item, TRAIT_TOOL_WIRECUTTERS)) - to_chat(user, "You need wirecutters!") + to_chat(user, "You need some wirecutters!") return TRUE var/wire = params["wire"] mend(wire) @@ -477,7 +483,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending return FALSE var/obj/item/held_item = user.get_held_item() if (!held_item || !HAS_TRAIT(held_item, TRAIT_TOOL_MULTITOOL)) - to_chat(user, "You need multitool!") + to_chat(user, "You need a multitool!") return TRUE var/wire = params["wire"] if (isWireCut(wire)) @@ -520,23 +526,10 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending return if(record.amount <= 0) speak("Sold out of [record.name].") - flick(icon_deny,src) - vend_ready = TRUE - return - var/obj/item/card/id/user_id - if(ishuman(user)) - var/mob/living/carbon/human/human_user = user - user_id = human_user.get_idcard() - if(!user_id) - speak("No card found.") - flick(icon_deny,src) - vend_ready = TRUE - return - else if(!get_account(user_id.associated_account_number) && price_to_use) - speak("No account found.") - flick(icon_deny,src) + flick(icon_deny, src) vend_ready = TRUE return + if(coin_records.Find(record)) if(!coin) speak("Coin required.") @@ -551,14 +544,58 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending QDEL_NULL(coin) else QDEL_NULL(coin) - if(price_to_use) - var/datum/money_account/account = get_account(user_id.associated_account_number) - if(!transfer_money(account, record)) - speak("You do not possess the funds to purchase [record.product_name].") + + // The checking_id() proc is currently determining whether to pay or not, not exactly just ID + // So lets treat cash like an alternative ID for these greedy machines + var/sufficent_cash = FALSE + var/ripped_off = FALSE + var/obj/item/spacecash/cash = user.get_active_hand() + if(!istype(cash)) + cash = user.get_inactive_hand() + if(istype(cash)) + sufficent_cash = cash.worth >= price_to_use + + var/obj/item/card/id/user_id + if(checking_id()) + if(ishuman(user)) + var/mob/living/carbon/human/human_user = user + user_id = human_user.get_idcard() + + if(!allowed(user)) + speak("Access denied.") flick(icon_deny, src) vend_ready = TRUE return + if(!user_id && !sufficent_cash) + speak("No card found.") + flick(icon_deny, src) + vend_ready = TRUE + return + + if(price_to_use) + var/datum/money_account/account + if(user_id) + account = get_account(user_id.associated_account_number) + + if(!account && !sufficent_cash) + speak("No account found.") + flick(icon_deny, src) + vend_ready = TRUE + return + + if(!account || !transfer_money(account, record)) + if (!sufficent_cash) + speak("You do not possess the funds to purchase [record.product_name].") + flick(icon_deny, src) + vend_ready = TRUE + return + + insert_money(cash, record) + if(cash.worth && !istype(cash, /obj/item/spacecash/ewallet)) + qdel(cash) + ripped_off = TRUE + speak(vend_reply) use_power(active_power_usage) if(icon_vend) //Show the vending animation if needed @@ -566,10 +603,16 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending var/obj/item/vended_item vended_item = new record.product_path(get_turf(src)) record.amount-- + playsound(src, "sound/machines/vending.ogg", 40, TRUE) if(user.Adjacent(src) && user.put_in_hands(vended_item)) to_chat(user, SPAN_NOTICE("You take \the [record.product_name] out of the slot.")) else to_chat(user, SPAN_WARNING("\The [record.product_name] falls onto the floor!")) + if(ripped_off) + flick(icon_deny, src) + addtimer(VARSET_CALLBACK(src, vend_ready, TRUE), 1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(speak), "Insufficient change. Please contact a supervisor."), 1 SECONDS) + return vend_ready = TRUE /obj/structure/machinery/vending/proc/transfer_money(datum/money_account/user_account, datum/data/vending_product/currently_vending) @@ -586,13 +629,13 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending //create entries in the two account transaction logs var/datum/transaction/new_transaction = new() - new_transaction.target_name = "[vendor_account.owner_name] (via [src.name])" + new_transaction.target_name = "[vendor_account.owner_name] (via [name])" new_transaction.purpose = "Purchase of [currently_vending.product_name]" if(transaction_amount > 0) new_transaction.amount = "([transaction_amount])" else new_transaction.amount = "[transaction_amount]" - new_transaction.source_terminal = src.name + new_transaction.source_terminal = name new_transaction.date = current_date_string new_transaction.time = worldtime2text() user_account.transaction_log.Add(new_transaction) @@ -601,28 +644,81 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending new_transaction.target_name = user_account.owner_name new_transaction.purpose = "Purchase of [currently_vending.product_name]" new_transaction.amount = "[transaction_amount]" - new_transaction.source_terminal = src.name + new_transaction.source_terminal = name new_transaction.date = current_date_string new_transaction.time = worldtime2text() vendor_account.transaction_log.Add(new_transaction) return TRUE +/obj/structure/machinery/vending/proc/insert_money(obj/item/spacecash/cash, datum/data/vending_product/currently_vending) + var/transaction_amount = currently_vending.price + if(transaction_amount > cash.worth) + return FALSE + + //transfer the money + cash.worth -= transaction_amount + vendor_account.money += transaction_amount + + //consume the cash if needed + if(!cash.worth) + qdel(cash) + + //create entries in the account transaction logs + var/datum/transaction/new_transaction = new() + new_transaction.target_name = "CASH" + new_transaction.purpose = "Purchase of [currently_vending.product_name]" + new_transaction.amount = "[transaction_amount]" + new_transaction.source_terminal = name + new_transaction.date = current_date_string + new_transaction.time = worldtime2text() + vendor_account.transaction_log.Add(new_transaction) + + return TRUE + +/** + * Returns TRUE if this vending machine is scanning for IDs. + */ +/obj/structure/machinery/vending/proc/checking_id() + if(hacking_safety) + return TRUE + + if(isWireCut(VENDING_WIRE_IDSCAN)) + return FALSE + + return TRUE + /obj/structure/machinery/vending/ui_data(mob/user) . = list() var/obj/item/card/id/id_card + var/datum/money_account/account if(ishuman(user)) var/mob/living/carbon/human/human_user = user id_card = human_user.get_idcard() - if(id_card) - var/datum/money_account/account = get_account(id_card.associated_account_number) - if(account) - .["user"] = list() - .["user"]["name"] = account.owner_name - .["user"]["cash"] = account.money - .["user"]["job"] = id_card.assignment - .["stock"] = list() + if(id_card) + account = get_account(id_card.associated_account_number) + + var/cash_worth + var/obj/item/spacecash/cash = user.get_active_hand() + if(!istype(cash)) + cash = user.get_inactive_hand() + if(istype(cash)) + cash_worth = cash.worth + + if(account) + .["user"] = list() + .["user"]["name"] = account.owner_name + .["user"]["cash"] = max(account.money, cash_worth) + .["user"]["job"] = id_card.assignment + else if(cash_worth) + .["user"] = list() + .["user"]["name"] = "" + .["user"]["cash"] = cash.worth + .["user"]["job"] = "" + else + .["user"] = null + .["stock"] = list() for (var/datum/data/vending_product/product_record in product_records + coin_records + hidden_records) var/list/product_data = list( name = product_record.product_name, @@ -646,6 +742,10 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending "powered" = TRUE, ) + .["checking_id"] = checking_id() + + .["access"] = allowed(user) + /obj/structure/machinery/vending/ui_state(mob/user) return GLOB.not_incapacitated_and_adjacent_strict_state @@ -698,7 +798,7 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending /obj/structure/machinery/vending/ui_assets(mob/user) return list(get_asset_datum(/datum/asset/spritesheet/vending)) -/obj/structure/machinery/vending/proc/release_item(datum/data/vending_product/R, delay_vending = 0, mob/living/carbon/human/user) +/obj/structure/machinery/vending/proc/release_item(datum/data/vending_product/product, delay_vending = 0, mob/living/carbon/human/user) set waitfor = 0 //We interact with the UI only if a user is present @@ -709,14 +809,14 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending if (delay_vending) use_power(vend_power_usage) //actuators and stuff if (icon_vend) - flick(icon_vend,src) //Show the vending animation if needed + flick(icon_vend, src) //Show the vending animation if needed sleep(delay_vending) if (vending_dir == VEND_HAND && istype(user) && Adjacent(user)) - user.put_in_hands(new R.product_path) - else if (ispath(R.product_path,/obj/item/weapon/gun)) - . = new R.product_path(get_turf(src), 1) + user.put_in_hands(new product.product_path) + else if (ispath(product.product_path, /obj/item/weapon/gun)) + . = new product.product_path(get_turf(src), 1) else - . = new R.product_path(get_turf(src)) + . = new product.product_path(get_turf(src)) /obj/structure/machinery/vending/MouseDrop_T(atom/movable/A, mob/user) @@ -730,48 +830,48 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending return if(istype(A, /obj/item)) - var/obj/item/I = A - stock(I, user) + var/obj/item/item = A + stock(item, user) ui_interact(user) /obj/structure/machinery/vending/proc/stock(obj/item/item_to_stock, mob/user) - var/datum/data/vending_product/R //Let's try with a new datum. + var/datum/data/vending_product/product //Let's try with a new datum. //More accurate comparison between absolute paths. - for(R in (product_records + hidden_records + coin_records)) - if(item_to_stock.type == R.product_path && !istype(item_to_stock,/obj/item/storage)) //Nice try, specialists/engis + for(product in (product_records + hidden_records + coin_records)) + if(item_to_stock.type == product.product_path && !istype(item_to_stock, /obj/item/storage)) //Nice try, specialists/engis if(isgun(item_to_stock)) - var/obj/item/weapon/gun/G = item_to_stock - if(G.in_chamber || (G.current_mag && !istype(G.current_mag, /obj/item/ammo_magazine/internal)) || (istype(G.current_mag, /obj/item/ammo_magazine/internal) && G.current_mag.current_rounds > 0) ) - to_chat(user, SPAN_WARNING("[G] is still loaded. Unload it before you can restock it.")) + var/obj/item/weapon/gun/gun = item_to_stock + if(gun.in_chamber || (gun.current_mag && !istype(gun.current_mag, /obj/item/ammo_magazine/internal)) || (istype(gun.current_mag, /obj/item/ammo_magazine/internal) && gun.current_mag.current_rounds > 0) ) + to_chat(user, SPAN_WARNING("\The [gun] is still loaded. Unload it before you can restock it.")) return - for(var/obj/item/attachable/A in G.contents) //Search for attachments on the gun. This is the easier method - if((A.flags_attach_features & ATTACH_REMOVABLE) && !(is_type_in_list(A, G.starting_attachment_types))) //There are attachments that are default and others that can't be removed - to_chat(user, SPAN_WARNING("[G] has non-standard attachments equipped. Detach them before you can restock it.")) + for(var/obj/item/attachable/attach in gun.contents) //Search for attachments on the gun. This is the easier method + if((attach.flags_attach_features & ATTACH_REMOVABLE) && !(is_type_in_list(attach, gun.starting_attachment_types))) //There are attachments that are default and others that can't be removed + to_chat(user, SPAN_WARNING("\The [gun] has non-standard attachments equipped. Detach them before you can restock it.")) return if(istype(item_to_stock, /obj/item/ammo_magazine)) - var/obj/item/ammo_magazine/A = item_to_stock - if(A.current_rounds < A.max_rounds) - to_chat(user, SPAN_WARNING("[A] isn't full. Fill it before you can restock it.")) + var/obj/item/ammo_magazine/mag = item_to_stock + if(mag.current_rounds < mag.max_rounds) + to_chat(user, SPAN_WARNING("\The [mag] isn't full. Fill it before you can restock it.")) return - if(istype(item_to_stock,/obj/item/device/walkman)) - var/obj/item/device/walkman/W = item_to_stock - if(W.tape) - to_chat(user,SPAN_WARNING("Remove the tape first!")) + if(istype(item_to_stock, /obj/item/device/walkman)) + var/obj/item/device/walkman/item = item_to_stock + if(item.tape) + to_chat(user, SPAN_WARNING("Remove the tape first!")) return if(istype(item_to_stock, /obj/item/device/defibrillator)) - var/obj/item/device/defibrillator/D = item_to_stock - if(!D.dcell) + var/obj/item/device/defibrillator/defib = item_to_stock + if(!defib.dcell) to_chat(user, SPAN_WARNING("\The [item_to_stock] needs a cell in it to be restocked!")) return - if(D.dcell.charge < D.dcell.maxcharge) + if(defib.dcell.charge < defib.dcell.maxcharge) to_chat(user, SPAN_WARNING("\The [item_to_stock] needs to be fully charged to restock it!")) return if(istype(item_to_stock, /obj/item/cell)) - var/obj/item/cell/C = item_to_stock - if(C.charge < C.maxcharge) + var/obj/item/cell/cell = item_to_stock + if(cell.charge < cell.maxcharge) to_chat(user, SPAN_WARNING("\The [item_to_stock] needs to be fully charged to restock it!")) return @@ -785,29 +885,29 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending S.remove_from_storage(item_to_stock, user.loc) qdel(item_to_stock) - user.visible_message(SPAN_NOTICE("[user] stocks [src] with \a [R.product_name]."), - SPAN_NOTICE("You stock [src] with \a [R.product_name].")) - R.amount++ + user.visible_message(SPAN_NOTICE("[user] stocks the [src] with \a [product.product_name]."), + SPAN_NOTICE("You stock the [src] with \a [product.product_name].")) + product.amount++ return //We found our item, no reason to go on. /obj/structure/machinery/vending/process() if(inoperable()) return - if(!src.active) + if(!active) return - if(src.seconds_electrified > 0) - src.seconds_electrified-- + if(seconds_electrified > 0) + seconds_electrified-- //Pitch to the people! Really sell it! - if(((src.last_slogan + src.slogan_delay) <= world.time) && (src.slogan_list.len > 0) && (!src.shut_up) && prob(5)) - var/slogan = pick(src.slogan_list) - src.speak(slogan) - src.last_slogan = world.time + if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5)) + var/slogan = pick(slogan_list) + speak(slogan) + last_slogan = world.time - if(src.shoot_inventory && prob(2) && !hacking_safety) - src.throw_item() + if(shoot_inventory && prob(2) && !hacking_safety) + throw_item() return @@ -818,8 +918,8 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending if (!message) return - for(var/mob/O in hearers(src, null)) - O.show_message("[src] beeps, \"[message]\"", SHOW_MESSAGE_AUDIBLE) + for(var/mob/mob in hearers(src, null)) + mob.show_message("[src] beeps, \"[message]\"", SHOW_MESSAGE_AUDIBLE) return /obj/structure/machinery/vending/power_change() @@ -833,17 +933,17 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending /obj/structure/machinery/vending/proc/malfunction() if(stat & BROKEN) return - var/release_amt = rand(3,4) - for(var/datum/data/vending_product/R in src.product_records) - if (R.amount <= 0) //Try to use a record that actually has something to dump. + var/release_amt = rand(3, 4) + for(var/datum/data/vending_product/product in product_records) + if (product.amount <= 0) //Try to use a record that actually has something to dump. continue - var/dump_path = R.product_path + var/dump_path = product.product_path if (!dump_path) continue - while(R.amount > 0 && release_amt > 0) - release_item(R, 0) - R.amount-- + while(product.amount > 0 && release_amt > 0) + release_item(product, 0) + product.amount-- release_amt-- break stat |= BROKEN @@ -853,24 +953,25 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending //Somebody cut an important wire and now we're following a new definition of "pitch." /obj/structure/machinery/vending/proc/throw_item() var/obj/throw_item = null - var/mob/living/target = locate() in view(7,src) + var/mob/living/target = locate() in view(7, src) if(!target) return 0 - for(var/datum/data/vending_product/R in product_records) - if (R.amount <= 0) //Try to use a record that actually has something to dump. + for(var/datum/data/vending_product/product in product_records) + if (product.amount <= 0) //Try to use a record that actually has something to dump. continue - var/dump_path = R.product_path + var/dump_path = product.product_path if (!dump_path) continue - R.amount-- - throw_item = release_item(R, 0) + product.amount-- + throw_item = release_item(product, 0) break if (!throw_item) return 0 INVOKE_ASYNC(throw_item, /atom/movable/proc/throw_atom, target, 16, SPEED_AVERAGE, src) - src.visible_message(SPAN_WARNING("[src] launches [throw_item.name] at [target]!")) + visible_message(SPAN_WARNING("The [src] launches \the [throw_item] at [target]!")) + playsound(src, "sound/machines/vending.ogg", 40, TRUE) return 1 /obj/structure/machinery/vending/proc/get_wire_descriptions() @@ -889,40 +990,40 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending switch(wire) if(VENDING_WIRE_EXTEND) - src.extended_inventory = TRUE - visible_message(SPAN_NOTICE("A weak yellow light turns off underneath \the [src].")) + extended_inventory = TRUE + visible_message(SPAN_NOTICE("A weak yellow light turns off underneath the [src].")) if(VENDING_WIRE_SHOCK) - src.seconds_electrified = -1 - visible_message(SPAN_DANGER("Electric arcs shoot off from \the [src]!")) + seconds_electrified = -1 + visible_message(SPAN_DANGER("Electric arcs shoot off from the [src]!")) if (VENDING_WIRE_SHOOT_INV) - if(!src.shoot_inventory) - src.shoot_inventory = TRUE - visible_message(SPAN_WARNING("\The [src] begins whirring noisily.")) + if(!shoot_inventory) + shoot_inventory = TRUE + visible_message(SPAN_WARNING("The [src] begins whirring noisily.")) /obj/structure/machinery/vending/proc/mend(wire) wires |= getWireFlag(wire) switch(wire) if(VENDING_WIRE_EXTEND) - src.extended_inventory = FALSE - visible_message(SPAN_NOTICE("A weak yellow light turns on underneath \the [src].")) + extended_inventory = FALSE + visible_message(SPAN_NOTICE("A weak yellow light turns on underneath the [src].")) if(VENDING_WIRE_SHOCK) - src.seconds_electrified = 0 + seconds_electrified = 0 if (VENDING_WIRE_SHOOT_INV) - src.shoot_inventory = FALSE - visible_message(SPAN_NOTICE("\The [src] stops whirring.")) + shoot_inventory = FALSE + visible_message(SPAN_NOTICE("The [src] stops whirring.")) /obj/structure/machinery/vending/proc/pulse(wire) switch(wire) if(VENDING_WIRE_EXTEND) - src.extended_inventory = !src.extended_inventory - visible_message(SPAN_NOTICE("A weak yellow light turns [extended_inventory ? "on" : "off"] underneath \the [src].")) + extended_inventory = !extended_inventory + visible_message(SPAN_NOTICE("A weak yellow light turns [extended_inventory ? "on" : "off"] underneath the [src].")) if (VENDING_WIRE_SHOCK) - src.seconds_electrified = 30 - visible_message(SPAN_DANGER("Electric arcs shoot off from \the [src]!")) + seconds_electrified = 30 + visible_message(SPAN_DANGER("Electric arcs shoot off from the [src]!")) if (VENDING_WIRE_SHOOT_INV) - src.shoot_inventory = !src.shoot_inventory + shoot_inventory = !shoot_inventory if(shoot_inventory) - visible_message(SPAN_WARNING("\The [src] begins whirring noisily.")) + visible_message(SPAN_WARNING("The [src] begins whirring noisily.")) else - visible_message(SPAN_NOTICE("\The [src] stops whirring.")) + visible_message(SPAN_NOTICE("The [src] stops whirring.")) diff --git a/code/game/machinery/vending/vending_types.dm b/code/game/machinery/vending/vending_types.dm index e9b0d6fd2f2c..a61934324491 100644 --- a/code/game/machinery/vending/vending_types.dm +++ b/code/game/machinery/vending/vending_types.dm @@ -17,7 +17,7 @@ */ /obj/structure/machinery/vending/coffee - name = "Hot Drinks machine" + name = "\improper Hot Drinks machine" desc = "A vending machine which dispenses hot drinks." //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" @@ -39,13 +39,13 @@ product_type = VENDOR_PRODUCT_TYPE_BEVERAGES /obj/structure/machinery/vending/coffee/simple - name = "Hot Coffee Machine" + name = "\improper Hot Coffee Machine" product_ads = "" products = list(/obj/item/reagent_container/food/drinks/coffee = 40) contraband = list(/obj/item/reagent_container/food/drinks/h_chocolate = 25) /obj/structure/machinery/vending/snack - name = "Hot Foods Machine" + name = "\improper Hot Foods Machine" desc = "A vending machine full of ready to cook meals, mhmmmm taste the nutritional goodness!" product_slogans = "Kepler Crisps! Try a snack that's out of this world!;Eat an EAT!;Eat a Weyland-Yutani brand packaged hamburger.;Eat a Weyland-Yutani brand packaged hot dog.;Eat a Weyland-Yutani brand packaged burrito.;" product_ads = "Kepler Crisps! Try a snack that's out of this world!;Eat an EAT!" @@ -55,6 +55,7 @@ /obj/item/reagent_container/food/snacks/packaged_burrito = 12, /obj/item/reagent_container/food/snacks/packaged_hdogs =12, /obj/item/reagent_container/food/snacks/kepler_crisps = 12, + /obj/item/reagent_container/food/snacks/kepler_crisps/flamehot = 12, /obj/item/reagent_container/food/snacks/wy_chips/pepper = 12, /obj/item/reagent_container/food/snacks/eat_bar = 12, /obj/item/reagent_container/food/snacks/wrapped/booniebars = 6, @@ -67,6 +68,7 @@ /obj/item/reagent_container/food/snacks/packaged_burrito = 5, /obj/item/reagent_container/food/snacks/packaged_hdogs = 5, /obj/item/reagent_container/food/snacks/kepler_crisps = 3, + /obj/item/reagent_container/food/snacks/kepler_crisps/flamehot = 5, /obj/item/reagent_container/food/snacks/wy_chips/pepper = 3, /obj/item/reagent_container/food/snacks/eat_bar = 4, /obj/item/reagent_container/food/snacks/wrapped/booniebars = 4, @@ -85,7 +87,7 @@ ) /obj/structure/machinery/vending/cola - name = "Souto Softdrinks" + name = "\improper Souto Softdrinks" desc = "A softdrink vendor provided by Souto Soda Company, Havana." icon_state = "Cola_Machine" product_slogans = "Souto Soda: Have a Souto and be taken away to a tropical paradise!;Souto Classic. You can't beat that tangerine goodness!;Souto Cherry. The sweet flavor of a cool winter morning!;Souto Lime. For that sweet and sour flavor that you know and love!;Souto Grape. There's nothing better than a grape soda.;Weyland-Yutani Fruit Beer. Nothing came from that lawsuit!" @@ -220,7 +222,7 @@ ) /obj/structure/machinery/vending/security - name = "SecTech" + name = "\improper 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" @@ -251,7 +253,7 @@ contraband = list(/obj/item/clothing/glasses/sunglasses = 2,/obj/item/storage/donut_box = 2) /obj/structure/machinery/vending/sea - name = "SeaTech" + name = "\improper SeaTech" desc = "An equipment vendor designed to save lives" product_ads = "Semper Fi!;First to Fight!;Ooh Rah.;Leathernecks!;The Few. The Proud.;Esprit de Corps;Jarhead.;Devil Dogs." icon_state = "sec" @@ -274,7 +276,7 @@ contraband = list(/obj/item/storage/fancy/cigar = 2,/obj/item/tool/lighter/zippo = 2) /obj/structure/machinery/vending/hydronutrients - name = "NutriMax" + name = "\improper NutriMax" 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..." @@ -286,7 +288,7 @@ idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. /obj/structure/machinery/vending/hydroseeds - name = "MegaSeed Servitor" + name = "\improper 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 on the station!;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!" @@ -309,7 +311,7 @@ premium = list(/obj/item/toy/waterflower = 1) /obj/structure/machinery/vending/dinnerware - name = "Dinnerware" + name = "\improper 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" @@ -317,7 +319,7 @@ contraband = list(/obj/item/tool/kitchen/utensil/spoon = 2,/obj/item/tool/kitchen/utensil/knife = 2,/obj/item/tool/kitchen/rollingpin = 2, /obj/item/tool/kitchen/knife/butcher = 2) /obj/structure/machinery/vending/sovietsoda - name = "BODA" + name = "\improper BODA" desc = "An old sweet water vending machine, how did this end up here?" icon_state = "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." diff --git a/code/game/machinery/vending/vendor_types/crew/commanding_officer.dm b/code/game/machinery/vending/vendor_types/crew/commanding_officer.dm index 5b985443cd84..fac4182ea5fe 100644 --- a/code/game/machinery/vending/vendor_types/crew/commanding_officer.dm +++ b/code/game/machinery/vending/vendor_types/crew/commanding_officer.dm @@ -1,7 +1,7 @@ //------------GEAR VENDOR--------------- GLOBAL_LIST_INIT(cm_vending_gear_commanding_officer, list( - list("CAPTAIN'S PRIMARY (CHOOSE 1)", 0, null, null, null), + list("COMMANDING OFFICER'S PRIMARY (CHOOSE 1)", 0, null, null, null), list("M46C pulse rifle", 0, /obj/effect/essentials_set/co/riflepreset, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), list("M56C Smartgun", 0, /obj/item/storage/box/m56c_system, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), @@ -42,7 +42,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_commanding_officer, list( list("Underbarrel Flamethrower", 15, /obj/item/attachable/attached_gun/flamer, null, VENDOR_ITEM_REGULAR), list("BARREL ATTACHMENTS", 0, null, null, null), - list("Barrel Charger", 25, /obj/item/attachable/heavy_barrel, null, VENDOR_ITEM_RECOMMENDED), list("Suppressor", 15, /obj/item/attachable/suppressor, null, VENDOR_ITEM_REGULAR), list("Extended Barrel", 15, /obj/item/attachable/extended_barrel, null, VENDOR_ITEM_REGULAR), list("Recoil Compensator", 15, /obj/item/attachable/compensator, null, VENDOR_ITEM_REGULAR), @@ -89,17 +88,17 @@ GLOBAL_LIST_INIT(cm_vending_clothing_commanding_officer, list( list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), )) /obj/structure/machinery/cm_vending/clothing/commanding_officer diff --git a/code/game/machinery/vending/vendor_types/crew/medical.dm b/code/game/machinery/vending/vendor_types/crew/medical.dm index ed0c2bba0e01..f1574c8104ff 100644 --- a/code/game/machinery/vending/vendor_types/crew/medical.dm +++ b/code/game/machinery/vending/vendor_types/crew/medical.dm @@ -29,119 +29,165 @@ //------------ DOCTOR --------------- GLOBAL_LIST_INIT(cm_vending_clothing_doctor, list( + list("MEDICAL SET (MANDATORY)", 0, null, null, null), + list("Essential Medical Set", 0, /obj/effect/essentials_set/medical/doctor, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), + list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/latex, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/doc, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Medical HUD Glasses", 0, /obj/item/clothing/glasses/hud/health, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_MANDATORY), - list("Labcoat", 0, /obj/item/clothing/suit/storage/labcoat, MARINE_CAN_BUY_MRE, VENDOR_ITEM_RECOMMENDED), list("UNIFORM (CHOOSE 1)", 0, null, null, null), list("Green Scrubs", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED), list("Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/blue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), list("Purple Scrubs", 0, /obj/item/clothing/under/rank/medical/purple, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), - list("Doctor Uniform", 0, /obj/item/clothing/under/rank/medical, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), + + list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("Labcoat", 0, /obj/item/clothing/suit/storage/labcoat, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("Snowcoat", 0, /obj/item/clothing/suit/storage/snow_suit/doctor, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), + + list("HELMET", 0, null, null, null), + list("Surgical Cap, Blue", 0, /obj/item/clothing/head/surgery/blue, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), + list("Surgical Cap, Purple", 0, /obj/item/clothing/head/surgery/purple, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), + list("Surgical Cap, Green", 0, /obj/item/clothing/head/surgery/green, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), list("BAG (CHOOSE 1)", 0, null, null, null), list("Medical Satchel", 0, /obj/item/storage/backpack/marine/satchel/medic, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), list("Medical Backpack", 0, /obj/item/storage/backpack/marine/medic, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("USCM Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("USCM Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), + + list("BELT (CHOOSE 1)", 0, null, null, null), + list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - )) + )) -///If there are no issues with docs getting nurse uniforms and vice-versa, or we remove Nurse role, this will be nuked -///Only difference is available uniforms, and removal of surgical webbing from accessory list //------------ NURSE --------------- GLOBAL_LIST_INIT(cm_vending_clothing_nurse, list( + list("MEDICAL SET (MANDATORY)", 0, null, null, null), + list("Essential Medical Set", 0, /obj/effect/essentials_set/medical, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), + list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/latex, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/doc, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Medical HUD Glasses", 0, /obj/item/clothing/glasses/hud/health, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_MANDATORY), + + list("UNIFORM (CHOOSE 1)", 0, null, null, null), + list("Green Scrubs", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED), + list("Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/blue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), + list("Purple Scrubs", 0, /obj/item/clothing/under/rank/medical/purple, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), list("Medical Nurse Scrubs", 0, /obj/item/clothing/under/rank/medical/nurse, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), + list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("Labcoat", 0, /obj/item/clothing/suit/storage/labcoat, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("Snowcoat", 0, /obj/item/clothing/suit/storage/snow_suit/doctor, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), + + list("HELMET", 0, null, null, null), + list("Surgical Cap, Blue", 0, /obj/item/clothing/head/surgery/blue, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), + list("Surgical Cap, Purple", 0, /obj/item/clothing/head/surgery/purple, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), + list("Surgical Cap, Green", 0, /obj/item/clothing/head/surgery/green, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), + list("BAG (CHOOSE 1)", 0, null, null, null), list("Medical Satchel", 0, /obj/item/storage/backpack/marine/satchel/medic, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), list("Medical Backpack", 0, /obj/item/storage/backpack/marine/medic, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("USCM Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("USCM Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), + + list("BELT (CHOOSE 1)", 0, null, null, null), + list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - )) - + )) //------------ RESEARCHER --------------- GLOBAL_LIST_INIT(cm_vending_clothing_researcher, list( + list("MEDICAL SET (MANDATORY)", 0, null, null, null), + list("Essential Medical Set", 0, /obj/effect/essentials_set/medical/doctor, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), + list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/latex, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/doc, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), + list("Headset", 0, /obj/item/device/radio/headset/almayer/research, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Medical HUD Glasses", 0, /obj/item/clothing/glasses/hud/health, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_MANDATORY), list("Reagent Scanner HUD Goggles", 0, /obj/item/clothing/glasses/science, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_RECOMMENDED), + + list("UNIFORM (CHOOSE 1)", 0, null, null, null), + list("Green Scrubs", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED), + list("Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/blue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), + list("Purple Scrubs", 0, /obj/item/clothing/under/rank/medical/purple, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), list("Researcher Uniform", 0, /obj/item/clothing/under/marine/officer/researcher, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Labcoat", 0, /obj/item/clothing/suit/storage/labcoat/researcher, MARINE_CAN_BUY_MRE, VENDOR_ITEM_RECOMMENDED), + + list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("Labcoat", 0, /obj/item/clothing/suit/storage/labcoat/researcher, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), + list("Snowcoat", 0, /obj/item/clothing/suit/storage/snow_suit/doctor, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), + + list("HELMET", 0, null, null, null), + list("Surgical Cap, Blue", 0, /obj/item/clothing/head/surgery/blue, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), + list("Surgical Cap, Purple", 0, /obj/item/clothing/head/surgery/purple, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), + list("Surgical Cap, Green", 0, /obj/item/clothing/head/surgery/green, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), list("BAG (CHOOSE 1)", 0, null, null, null), list("Medical Satchel", 0, /obj/item/storage/backpack/marine/satchel/medic, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), list("Medical Backpack", 0, /obj/item/storage/backpack/marine/medic, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("USCM Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("USCM Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), + + list("BELT (CHOOSE 1)", 0, null, null, null), + list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Vials Pouch", 0, /obj/item/storage/pouch/vials, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_MANDATORY), - list("Chemist Pouch", 0, /obj/item/storage/pouch/chem, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_MANDATORY), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Vials Pouch", 0, /obj/item/storage/pouch/vials, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_MANDATORY), + list("Chemist Pouch", 0, /obj/item/storage/pouch/chem, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_MANDATORY), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), @@ -149,3 +195,23 @@ GLOBAL_LIST_INIT(cm_vending_clothing_researcher, list( list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), )) + +/obj/effect/essentials_set/medical + spawned_gear_list = list( + /obj/item/device/defibrillator, + /obj/item/storage/firstaid/adv, + /obj/item/device/healthanalyzer, + /obj/item/tool/surgery/surgical_line, + /obj/item/tool/surgery/synthgraft, + ) + +/obj/effect/essentials_set/medical/doctor + spawned_gear_list = list( + /obj/item/device/defibrillator, + /obj/item/storage/firstaid/adv, + /obj/item/device/healthanalyzer, + /obj/item/tool/surgery/surgical_line, + /obj/item/tool/surgery/synthgraft, + /obj/item/device/flashlight/pen, + /obj/item/clothing/accessory/stethoscope, + ) diff --git a/code/game/machinery/vending/vendor_types/crew/mp.dm b/code/game/machinery/vending/vendor_types/crew/mp.dm index d29385721f8c..b63a02248168 100644 --- a/code/game/machinery/vending/vendor_types/crew/mp.dm +++ b/code/game/machinery/vending/vendor_types/crew/mp.dm @@ -1,40 +1,50 @@ //------------ MP CLOTHING VENDOR--------------- GLOBAL_LIST_INIT(cm_vending_clothing_military_police, list( + list("POLICE SET (MANDATORY)", 0, null, null, null), + list("Essential Police Set", 0, /obj/effect/essentials_set/police, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), + list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Uniform", 0, /obj/item/clothing/under/marine/mp, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/mmpo, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Satchel", 0, /obj/item/storage/backpack/satchel/sec, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), - - list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), - list("M44 Revolver", 0, /obj/item/storage/belt/gun/m44/mp, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M4A3 Pistol", 0, /obj/item/storage/belt/gun/m4a3/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("Mod 88 Pistol", 0, /obj/item/storage/belt/gun/m4a3/mod88, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("ARMOR (TAKE ALL)", 0, null, null, null), list("Military Police M2 Armor", 0, /obj/item/clothing/suit/storage/marine/MP, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), - list("Military Police M2 Armor and Service Jacket", 0, /obj/item/clothing/suit/storage/marine/MP/jacket, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), - list("Military Police M2 Padless Armor", 0, /obj/item/clothing/suit/storage/marine/MP/padless, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), + list("MP Beret", 0, /obj/item/clothing/head/beret/marine/mp, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("COMBAT EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Military Police M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/MP, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("HANDGUN CASE (CHOOSE 1)", 0, null, null, null), + list("88 mod 4 Combat Pistol Case", 0, /obj/item/storage/box/guncase/mod88, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), + list("M44 Combat Revolver Case", 0, /obj/item/storage/box/guncase/m44, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), + list("M4A3 Service Pistol Case", 0, /obj/item/storage/box/guncase/m4a3, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), - list("EYEWEAR (TAKE ALL)", 0, null, null, null), - list("Security HUD Glasses", 0, /obj/item/clothing/glasses/sunglasses/sechud, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_REGULAR), + list("BACKPACK (CHOOSE 1)", 0, null, null, null), + list("Military Police Satchel", 0, /obj/item/storage/backpack/satchel/sec, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), + + list("BELT (CHOOSE 1)", 0, null, null, null), + list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Full)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + + list("MASK (CHOOSE 1)", 0, null, null, null), + list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Rebreather", 0, /obj/item/clothing/mask/rebreather, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), + list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), + list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Shoulder Holster", 0, /obj/item/clothing/accessory/storage/holster, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - - list("HAT (CHOOSE 1)", 0, null, null, null), - list("MP Beret", 0, /obj/item/clothing/head/beret/marine/mp, MARINE_CAN_BUY_MASK, VENDOR_ITEM_MANDATORY), - )) /obj/structure/machinery/cm_vending/clothing/military_police @@ -49,40 +59,50 @@ GLOBAL_LIST_INIT(cm_vending_clothing_military_police, list( //------------ Warden CLOTHING VENDOR--------------- GLOBAL_LIST_INIT(cm_vending_clothing_military_police_warden, list( + list("POLICE SET (MANDATORY)", 0, null, null, null), + list("Essential Police Set", 0, /obj/effect/essentials_set/police, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Warden Uniform", 0, /obj/item/clothing/under/marine/warden, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/cmpcom, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Satchel", 0, /obj/item/storage/backpack/satchel/sec, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), - - list("PERSONAL SIDEARM (Take ALL)", 0, null, null, null), - list("M4A3 Service Pistol ", 0, /obj/item/storage/belt/gun/m4a3/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("Mod 88 Pistol", 0, /obj/item/storage/belt/gun/m4a3/mod88, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M44 Revolver", 0, /obj/item/storage/belt/gun/m44/mp, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("ARMOR (TAKE ALL)", 0, null, null, null), list("Military Warden M3 Armor", 0, /obj/item/clothing/suit/storage/marine/MP/warden, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), - list("Military Warden M3 Armor and Service Jacket", 0, /obj/item/clothing/suit/storage/marine/MP/warden/jacket, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), - list("Military Warden M3 Padless Armor", 0, /obj/item/clothing/suit/storage/marine/MP/warden/padless, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), + list("Warden Peaked Cap", 0, /obj/item/clothing/head/beret/marine/mp/warden, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("COMBAT EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Military Police M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/MP, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("HANDGUN CASE (CHOOSE 1)", 0, null, null, null), + list("88 mod 4 Combat Pistol Case", 0, /obj/item/storage/box/guncase/mod88, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), + list("M44 Combat Revolver Case", 0, /obj/item/storage/box/guncase/m44, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), + list("M4A3 Service Pistol Case", 0, /obj/item/storage/box/guncase/m4a3, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), - list("EYEWEAR (TAKE ALL)", 0, null, null, null), - list("Security HUD Glasses", 0, /obj/item/clothing/glasses/sunglasses/sechud, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_REGULAR), + list("BACKPACK (CHOOSE 1)", 0, null, null, null), + list("Military Police Satchel", 0, /obj/item/storage/backpack/satchel/sec, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), + + list("BELT (CHOOSE 1)", 0, null, null, null), + list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Full)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + + list("MASK (CHOOSE 1)", 0, null, null, null), + list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Rebreather", 0, /obj/item/clothing/mask/rebreather, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), + list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), + list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Shoulder Holster", 0, /obj/item/clothing/accessory/storage/holster, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - - list("HAT (CHOOSE 1)", 0, null, null, null), - list("Warden Peaked Cap", 0, /obj/item/clothing/head/beret/marine/mp/warden, MARINE_CAN_BUY_MASK, VENDOR_ITEM_MANDATORY), )) /obj/structure/machinery/cm_vending/clothing/military_police_warden @@ -93,3 +113,10 @@ GLOBAL_LIST_INIT(cm_vending_clothing_military_police_warden, list( /obj/structure/machinery/cm_vending/clothing/military_police_warden/get_listed_products(mob/user) return GLOB.cm_vending_clothing_military_police_warden + +/obj/effect/essentials_set/police + spawned_gear_list = list( + /obj/item/clothing/glasses/sunglasses/sechud, + /obj/item/storage/belt/security/MP/full, + /obj/item/clothing/head/helmet/marine/MP, + ) diff --git a/code/game/machinery/vending/vendor_types/crew/pilot_officer.dm b/code/game/machinery/vending/vendor_types/crew/pilot_officer.dm index 50eebd1851c1..8d86669a1f70 100644 --- a/code/game/machinery/vending/vendor_types/crew/pilot_officer.dm +++ b/code/game/machinery/vending/vendor_types/crew/pilot_officer.dm @@ -62,11 +62,14 @@ GLOBAL_LIST_INIT(cm_vending_clothing_pilot_officer, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/yellow, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("M70 Flak Jacket", 0, /obj/item/clothing/suit/armor/vest/pilot, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("M30 Tactical Helmet", 0, /obj/item/clothing/head/helmet/marine/pilot, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("Leather Satchel", 0, /obj/item/storage/backpack/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("M70 Flak Jacket", 0, /obj/item/clothing/suit/armor/vest/pilot, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), + list("M3-VL Pattern Flak Vest", 0, /obj/item/clothing/suit/storage/marine/light/vest/dcc, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), + list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), list("88 Mod 4 Combat Pistol", 0, /obj/item/weapon/gun/pistol/mod88, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_REGULAR), list("VP78 Pistol", 0, /obj/item/weapon/gun/pistol/vp78, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_REGULAR), @@ -76,26 +79,26 @@ GLOBAL_LIST_INIT(cm_vending_clothing_pilot_officer, list( list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), @@ -148,11 +151,14 @@ GLOBAL_LIST_INIT(cm_vending_clothing_pilot_officer, list( GLOBAL_LIST_INIT(cm_vending_clothing_dropship_crew_chief, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/yellow, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("M3-VL Pattern Flak Vest", 0, /obj/item/clothing/suit/storage/marine/light/vest/dcc, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Patrol Cap", 0, /obj/item/clothing/head/cmcap, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("Leather Satchel", 0, /obj/item/storage/backpack/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("M70 Flak Jacket", 0, /obj/item/clothing/suit/armor/vest/pilot, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), + list("M3-VL Pattern Flak Vest", 0, /obj/item/clothing/suit/storage/marine/light/vest/dcc, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), + list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), list("88 Mod 4 Combat Pistol", 0, /obj/item/weapon/gun/pistol/mod88, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_REGULAR), list("VP78 Pistol", 0, /obj/item/weapon/gun/pistol/vp78, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_REGULAR), @@ -162,26 +168,26 @@ GLOBAL_LIST_INIT(cm_vending_clothing_dropship_crew_chief, list( list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/crew/sea.dm b/code/game/machinery/vending/vendor_types/crew/sea.dm index d6776a0a4c5d..ee583828ec44 100644 --- a/code/game/machinery/vending/vendor_types/crew/sea.dm +++ b/code/game/machinery/vending/vendor_types/crew/sea.dm @@ -39,16 +39,17 @@ GLOBAL_LIST_INIT(cm_vending_clothing_sea, list( list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 Toolbelt Rig (Full)", 0, /obj/item/storage/belt/utility/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 Combat Toolbelt Rig (Full)", 0, /obj/item/storage/belt/gun/utility, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("COMBAT ARMOR (CHOOSE 1)", 0, null, null, null), list("M3-VL Pattern Ballistics Vest", 0, /obj/item/clothing/suit/storage/marine/light/vest, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/crew/senior_officers.dm b/code/game/machinery/vending/vendor_types/crew/senior_officers.dm index 4baa1efd72cb..55053bd724bd 100644 --- a/code/game/machinery/vending/vendor_types/crew/senior_officers.dm +++ b/code/game/machinery/vending/vendor_types/crew/senior_officers.dm @@ -2,7 +2,7 @@ name = "\improper ColMarTech Senior Officer Equipment Rack" desc = "An automated equipment vendor for Senior Officers." req_access = list(ACCESS_MARINE_SENIOR) - vendor_role = list(JOB_CHIEF_POLICE,JOB_CMO,JOB_XO,JOB_CHIEF_ENGINEER,JOB_CHIEF_REQUISITION) + vendor_role = list(JOB_CHIEF_POLICE, JOB_CMO, JOB_XO, JOB_CHIEF_ENGINEER, JOB_CHIEF_REQUISITION, JOB_AUXILIARY_OFFICER) /obj/structure/machinery/cm_vending/clothing/senior_officer/get_listed_products(mob/user) if(!user) @@ -23,55 +23,62 @@ return GLOB.cm_vending_clothing_cmo else if(user.job == JOB_CHIEF_POLICE) return GLOB.cm_vending_clothing_military_police_chief + else if(user.job == JOB_AUXILIARY_OFFICER) + return GLOB.cm_vending_clothing_auxiliary_officer return ..() - //------------ CHIEF MP --------------- GLOBAL_LIST_INIT(cm_vending_clothing_military_police_chief, list( + list("POLICE SET (MANDATORY)", 0, null, null, null), + list("Essential Police Set", 0, /obj/effect/essentials_set/chiefmilitarypolice, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("CMP Uniform", 0, /obj/item/clothing/under/marine/officer/warrant, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/cmpcom, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Satchel", 0, /obj/item/storage/backpack/satchel/sec, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), - list("Gear Belt", 0, /obj/item/storage/belt/security/MP/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_MANDATORY), - - list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), - list("M4A3 Service Pistol", 0, /obj/item/storage/belt/gun/m4a3/full, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_REGULAR), - list("Mod 88 Pistol", 0, /obj/item/storage/belt/gun/m4a3/mod88, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_REGULAR), - list("M44 Revolver", 0, /obj/item/storage/belt/gun/m44/mp, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), + list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("ARMOR (TAKE ALL)", 0, null, null, null), list("Military Police Chief M3 Armor", 0, /obj/item/clothing/suit/storage/marine/MP/WO, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), - list("Military Police Chief M3 Armor and Service Jacket", 0, /obj/item/clothing/suit/storage/marine/MP/WO/jacket, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), - list("Military Police Chief M3 Padless Armor", 0, /obj/item/clothing/suit/storage/marine/MP/WO/padless, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("Chief MP M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/MP/WO, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), + list("CMP Beret", 0, /obj/item/clothing/head/beret/marine/mp/cmp, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("COMBAT EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Military Police M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/MP, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("HANDGUN CASE (CHOOSE 1)", 0, null, null, null), + list("88 mod 4 Combat Pistol Case", 0, /obj/item/storage/box/guncase/mod88, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), + list("M44 Combat Revolver Case", 0, /obj/item/storage/box/guncase/m44, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), + list("M4A3 Service Pistol Case", 0, /obj/item/storage/box/guncase/m4a3, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), + + list("BACKPACK (CHOOSE 1)", 0, null, null, null), + list("Military Police Satchel", 0, /obj/item/storage/backpack/satchel/sec, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), - list("EYEWEAR (TAKE ALL)", 0, null, null, null), - list("Security HUD Glasses", 0, /obj/item/clothing/glasses/sunglasses/sechud, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_MANDATORY), + list("BELT (CHOOSE 1)", 0, null, null, null), + list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + + list("MASK (CHOOSE 1)", 0, null, null, null), + list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Rebreather", 0, /obj/item/clothing/mask/rebreather, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), - list("Shoulder Holster", 0, /obj/item/clothing/accessory/storage/holster, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Shoulder Holster", 0, /obj/item/clothing/accessory/storage/holster, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - - list("HAT (CHOOSE 1)", 0, null, null, null), - list("CMP Beret", 0, /obj/item/clothing/head/beret/marine/mp/cmp, MARINE_CAN_BUY_MASK, VENDOR_ITEM_MANDATORY), )) - //------------ CHIEF ENGINEER --------------- GLOBAL_LIST_INIT(cm_vending_clothing_chief_engineer, list( @@ -109,13 +116,19 @@ GLOBAL_LIST_INIT(cm_vending_clothing_chief_engineer, list( list("Welding Kit", 0, /obj/item/tool/weldpack, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Construction Pouch", 0, /obj/item/storage/pouch/construction, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Construction Pouch", 0, /obj/item/storage/pouch/construction, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), list("M4A3 Service Pistol", 0, /obj/item/storage/belt/gun/m4a3/full, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), @@ -140,13 +153,6 @@ GLOBAL_LIST_INIT(cm_vending_clothing_chief_engineer, list( list("Officer M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/MP/SO, MARINE_CAN_BUY_COMBAT_HELMET, VENDOR_ITEM_REGULAR), list("M10 Technician Helmet", 0, /obj/item/clothing/head/helmet/marine/tech, MARINE_CAN_BUY_COMBAT_HELMET, VENDOR_ITEM_REGULAR), - list("COMBAT POUCHES (CHOOSE 2)", 0, null, null, null), - list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, (MARINE_CAN_BUY_COMBAT_R_POUCH|MARINE_CAN_BUY_COMBAT_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_COMBAT_R_POUCH|MARINE_CAN_BUY_COMBAT_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_COMBAT_R_POUCH|MARINE_CAN_BUY_COMBAT_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_COMBAT_R_POUCH|MARINE_CAN_BUY_COMBAT_L_POUCH), VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, (MARINE_CAN_BUY_COMBAT_R_POUCH|MARINE_CAN_BUY_COMBAT_L_POUCH), VENDOR_ITEM_REGULAR), - list("MASK (CHOOSE 1)", 0, null, null, null), list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), @@ -164,11 +170,11 @@ GLOBAL_LIST_INIT(cm_vending_clothing_req_officer, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Insulated Gloves", 0, /obj/item/clothing/gloves/yellow, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("RO Uniform", 0, /obj/item/clothing/under/rank/ro_suit, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/ro, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), + list("Quartermaster Uniform", 0, /obj/item/clothing/under/rank/qm_suit, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), + list("Headset", 0, /obj/item/device/radio/headset/almayer/qm, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Satchel", 0, /obj/item/storage/backpack/marine/satchel/tech, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), list("Req Cap", 0, /obj/item/clothing/head/cmcap/req, MARINE_CAN_BUY_MASK, VENDOR_ITEM_MANDATORY), - list("RO Jacket", 0, /obj/item/clothing/suit/storage/RO, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("Quartermaster Jacket", 0, /obj/item/clothing/suit/storage/RO, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), list("M4A3 Service Pistol", 0, /obj/item/storage/belt/gun/m4a3/full, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), @@ -181,12 +187,12 @@ GLOBAL_LIST_INIT(cm_vending_clothing_req_officer, list( list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Empty)", 0, /obj/item/storage/pouch/tools, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Construction Pouch", 0, /obj/item/storage/pouch/construction, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Empty)", 0, /obj/item/storage/pouch/tools, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Construction Pouch", 0, /obj/item/storage/pouch/construction, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), @@ -204,9 +210,12 @@ GLOBAL_LIST_INIT(cm_vending_clothing_cmo, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/latex, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/cmo, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Medical HUD Glasses", 0, /obj/item/clothing/glasses/hud/health, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_MANDATORY), list("Labcoat", 0, /obj/item/clothing/suit/storage/labcoat, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("EYEWARE (CHOOSE 1)", 0, null, null, null), + list("Medical HUD Glasses", 0, /obj/item/clothing/glasses/hud/health, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_MANDATORY), + list("Reagent Scanner HUD Goggles", 0, /obj/item/clothing/glasses/science, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_REGULAR), + list("UNIFORM (CHOOSE 1)", 0, null, null, null), list("Green Scrubs", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED), list("Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/blue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), @@ -230,20 +239,20 @@ GLOBAL_LIST_INIT(cm_vending_clothing_cmo, list( list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), @@ -287,15 +296,15 @@ GLOBAL_LIST_INIT(cm_vending_clothing_xo, list( list("USCM Shoulder Patch", 0, /obj/item/clothing/accessory/patch, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Document Pouch", 0, /obj/item/storage/pouch/document, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Document Pouch", 0, /obj/item/storage/pouch/document, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), @@ -311,3 +320,47 @@ GLOBAL_LIST_INIT(cm_vending_clothing_xo, list( list("Patrol Cap", 0, /obj/item/clothing/head/cmcap, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), list("Officer Cap", 0, /obj/item/clothing/head/cmcap/ro, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), )) + + + +//------------ AUXILIARY SUPPORT OFFICER --------------- +GLOBAL_LIST_INIT(cm_vending_clothing_auxiliary_officer, list( + + list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), + list("Insulated Gloves", 0, /obj/item/clothing/gloves/yellow, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), + list("Officer Uniform", 0, /obj/item/clothing/under/marine/officer/bridge, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), + list("Headset", 0, /obj/item/device/radio/headset/almayer/qm, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), + list("Satchel", 0, /obj/item/storage/backpack/marine/satchel/tech, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), + list("Patrol Cap", 0, /obj/item/clothing/head/cmcap, MARINE_CAN_BUY_MASK, VENDOR_ITEM_MANDATORY), + list("Auxiliary Support Officer Jacket", 0, /obj/item/clothing/suit/storage/jacket/marine/service/aso, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + + list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), + list("M4A3 Service Pistol", 0, /obj/item/storage/belt/gun/m4a3/full, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), + list("Mod 88 Pistol", 0, /obj/item/storage/belt/gun/m4a3/mod88, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), + list("M44 Custom Revolver", 0, /obj/item/storage/belt/gun/m44/custom, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), + + list("COMBAT EQUIPMENT (TAKE ALL)", 0, null, null, null), + list("Officer M3 Armor", 0, /obj/item/clothing/suit/storage/marine/MP/SO, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), + list("Officer M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/MP/SO, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), + list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + + list("POUCHES (CHOOSE 2)", 0, null, null, null), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Empty)", 0, /obj/item/storage/pouch/tools, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Construction Pouch", 0, /obj/item/storage/pouch/construction, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + + list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), + list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), + list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + )) + +/obj/effect/essentials_set/chiefmilitarypolice + spawned_gear_list = list( + /obj/item/clothing/glasses/sunglasses/sechud, + /obj/item/storage/belt/security/MP/full, + /obj/item/clothing/head/helmet/marine/MP/WO, + ) diff --git a/code/game/machinery/vending/vendor_types/crew/staff_officer.dm b/code/game/machinery/vending/vendor_types/crew/staff_officer.dm index ee5e4c27fe90..3edbee6bbc47 100644 --- a/code/game/machinery/vending/vendor_types/crew/staff_officer.dm +++ b/code/game/machinery/vending/vendor_types/crew/staff_officer.dm @@ -11,11 +11,21 @@ GLOBAL_LIST_INIT(cm_vending_clothing_staff_officer, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), + list("Uniform", 0, /obj/item/clothing/under/marine/officer/bridge, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/mcom, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Helmet", 0, /obj/item/clothing/head/helmet/marine/MP/SO, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("JACKET (CHOOSE 1)", 0, null, null, null), + list("Service Jacket", 0, /obj/item/clothing/suit/storage/jacket/marine/service, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), + + list("HAT (CHOOSE 1)", 0, null, null, null), + list("Beret, Green", 0, /obj/item/clothing/head/beret/cm, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_RECOMMENDED), + list("Beret, Tan", 0, /obj/item/clothing/head/beret/cm/tan, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_RECOMMENDED), + list("Patrol Cap", 0, /obj/item/clothing/head/cmcap, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_RECOMMENDED), + + list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), list("M44 Revolver", 0, /obj/item/storage/belt/gun/m44/mp, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M4A3 Pistol", 0, /obj/item/storage/belt/gun/m4a3/commander, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), @@ -23,38 +33,39 @@ GLOBAL_LIST_INIT(cm_vending_clothing_staff_officer, list( list("BACKPACK (CHOOSE 1)", 0, null, null, null), list("Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), + list("Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), + list("Radio Telephone Pack", 0, /obj/item/storage/backpack/marine/satchel/rto, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), list("BELT (CHOOSE 1)", 0, null, null, null), list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 Lifesaver Bag", 0, /obj/item/storage/belt/medical/lifesaver, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 Medical Storage Rig", 0, /obj/item/storage/belt/medical, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M40 Grenade Rig", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Construction Pouch", 0, /obj/item/storage/pouch/construction, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Document Pouch", 0, /obj/item/storage/pouch/document, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Construction Pouch", 0, /obj/item/storage/pouch/construction, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Document Pouch", 0, /obj/item/storage/pouch/document, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/crew/synthetic.dm b/code/game/machinery/vending/vendor_types/crew/synthetic.dm index f08a43812b25..0496530be861 100644 --- a/code/game/machinery/vending/vendor_types/crew/synthetic.dm +++ b/code/game/machinery/vending/vendor_types/crew/synthetic.dm @@ -21,6 +21,7 @@ list("Industrial Blowtorch", 2, /obj/item/tool/weldingtool/largetank, null, VENDOR_ITEM_REGULAR), list("High-Capacity Industrial Blowtorch", 4, /obj/item/tool/weldingtool/hugetank, null, VENDOR_ITEM_REGULAR), list("Plastic Explosive", 3, /obj/item/explosive/plastic, null, VENDOR_ITEM_REGULAR), + list("Toolkit", 1, /obj/item/storage/firstaid/toolkit/empty, null, VENDOR_ITEM_REGULAR), list("FIRSTAID KITS", 0, null, null, null), list("Advanced Firstaid Kit", 12, /obj/item/storage/firstaid/adv, null, VENDOR_ITEM_REGULAR), @@ -31,8 +32,8 @@ list("Radiation Firstaid Kit", 6, /obj/item/storage/firstaid/rad, null, VENDOR_ITEM_REGULAR), list("MEDICAL SUPPLIES", 0, null, null, null), - list("Adv Burn Kit", 2, /obj/item/stack/medical/advanced/ointment, null, VENDOR_ITEM_REGULAR), - list("Adv Trauma Kit", 2, /obj/item/stack/medical/advanced/bruise_pack, null, VENDOR_ITEM_REGULAR), + list("Burn Kit", 2, /obj/item/stack/medical/advanced/ointment, null, VENDOR_ITEM_REGULAR), + list("Trauma Kit", 2, /obj/item/stack/medical/advanced/bruise_pack, null, VENDOR_ITEM_REGULAR), list("Medevac Bed", 6, /obj/item/roller/medevac, null, VENDOR_ITEM_REGULAR), list("Medical Splints", 1, /obj/item/stack/medical/splint, null, VENDOR_ITEM_REGULAR), list("Roller Bed", 4, /obj/item/roller, null, VENDOR_ITEM_REGULAR), @@ -45,7 +46,6 @@ list("Pillbottle (Inaprovaline)", 5, /obj/item/storage/pill_bottle/inaprovaline, null, VENDOR_ITEM_REGULAR), list("Pillbottle (Kelotane)", 5, /obj/item/storage/pill_bottle/kelotane, null, VENDOR_ITEM_RECOMMENDED), list("Pillbottle (Peridaxon)", 5, /obj/item/storage/pill_bottle/peridaxon, null, VENDOR_ITEM_REGULAR), - list("Pillbottle (QuickClot)", 5, /obj/item/storage/pill_bottle/quickclot, null, VENDOR_ITEM_REGULAR), list("Pillbottle (Tramadol)", 5, /obj/item/storage/pill_bottle/tramadol, null, VENDOR_ITEM_RECOMMENDED), list("Injector (Bicaridine)", 1, /obj/item/reagent_container/hypospray/autoinjector/bicaridine, null, VENDOR_ITEM_REGULAR), @@ -54,7 +54,6 @@ list("Injector (Inaprovaline)", 1, /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, null, VENDOR_ITEM_REGULAR), list("Injector (Kelotane)", 1, /obj/item/reagent_container/hypospray/autoinjector/kelotane, null, VENDOR_ITEM_REGULAR), list("Injector (Oxycodone)", 2, /obj/item/reagent_container/hypospray/autoinjector/oxycodone, null, VENDOR_ITEM_REGULAR), - list("Injector (QuickClot)", 1, /obj/item/reagent_container/hypospray/autoinjector/quickclot, null, VENDOR_ITEM_REGULAR), list("Injector (Tramadol)", 1, /obj/item/reagent_container/hypospray/autoinjector/tramadol, null, VENDOR_ITEM_REGULAR), list("Injector (Tricord)", 1, /obj/item/reagent_container/hypospray/autoinjector/tricord, null, VENDOR_ITEM_REGULAR), @@ -77,7 +76,8 @@ list("Motion Detector", 5, /obj/item/device/motiondetector, null, VENDOR_ITEM_REGULAR), list("Space Cleaner", 2, /obj/item/reagent_container/spray/cleaner, null, VENDOR_ITEM_REGULAR), list("Whistle", 5, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), - list("Machete Scabbard (Full)", 2, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR) + list("Machete Scabbard (Full)", 2, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR), + list("Stethoscope", 2, /obj/item/clothing/accessory/stethoscope, null, VENDOR_ITEM_REGULAR) ) @@ -91,12 +91,10 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth, list( list("Headset", 0, /obj/item/device/radio/headset/almayer/mcom/cdrcom, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("UNIFORM (CHOOSE 1)", 0, null, null, null), - list("Medical Scrubs, Green", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), list("Uniform, Outdated Synth", 0, /obj/item/clothing/under/rank/synthetic/old, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), list("Uniform, Standard Synth", 0, /obj/item/clothing/under/rank/synthetic, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("USCM Standard Uniform", 0, /obj/item/clothing/under/marine, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), list("USCM Medical Uniform", 0, /obj/item/clothing/under/marine/medic, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), - list("Working Joe Uniform", 0, /obj/item/clothing/under/rank/synthetic/joe, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), list("WEBBING (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), @@ -114,7 +112,6 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth, list( list("HELMET (CHOOSE 1)", 0, null, null, null), list("Expedition Cap", 0, /obj/item/clothing/head/cmcap/flap, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), list("Hard Hat, Orange", 0, /obj/item/clothing/head/hardhat/orange, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), - list("Surgical Cap, Green", 0, /obj/item/clothing/head/surgery/green, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), list("Welding Helmet", 0, /obj/item/clothing/head/welding, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), list("SUIT (CHOOSE 1)", 0, null, null, null), @@ -141,26 +138,26 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth, list( list("M276 Toolbelt Rig (Full)", 0, /obj/item/storage/belt/utility/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Construction Pouch", 0, /obj/item/storage/pouch/construction, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Document Pouch", 0, /obj/item/storage/pouch/document, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Machete Pouch (Full)", 0, /obj/item/storage/pouch/machete/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Construction Pouch", 0, /obj/item/storage/pouch/construction, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Document Pouch", 0, /obj/item/storage/pouch/document, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Machete Pouch (Full)", 0, /obj/item/storage/pouch/machete/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("MASK", 0, null, null, null), list("Sterile mask", 0, /obj/item/clothing/mask/surgical, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR) @@ -184,14 +181,21 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Medical Scrubs, Purple", 12, /obj/item/clothing/under/rank/medical/purple, null, VENDOR_ITEM_REGULAR), list("Medical Scrubs, White", 12, /obj/item/clothing/under/rank/medical, null, VENDOR_ITEM_REGULAR), list("USCM Service Uniform", 12, /obj/item/clothing/under/marine/officer/bridge, null, VENDOR_ITEM_REGULAR), - list("USCM Flightsuit", 12, /obj/item/clothing/under/marine/officer/pilot/flight, null, VENDOR_ITEM_REGULAR), - list("Engineer Uniform", 12, /obj/item/clothing/under/marine/officer/engi, null, VENDOR_ITEM_REGULAR), + list("USCM Flightsuit", 12, /obj/item/clothing/under/rank/synthetic/flight, null, VENDOR_ITEM_REGULAR), + list("USCM Engineer Uniform", 12, /obj/item/clothing/under/marine/officer/engi, null, VENDOR_ITEM_REGULAR), list("White T-Shirt and Brown Jeans", 12, /obj/item/clothing/under/tshirt/w_br, null, VENDOR_ITEM_REGULAR), list("Gray T-Shirt and Blue Jeans", 12, /obj/item/clothing/under/tshirt/gray_blu, null, VENDOR_ITEM_REGULAR), list("Red T-Shirt and Black Jeans", 12, /obj/item/clothing/under/tshirt/r_bla, null, VENDOR_ITEM_REGULAR), - list("Gray Utilities", 12, /obj/item/clothing/under/colonist/ua_civvies, null, VENDOR_ITEM_REGULAR), - list("Brown Utilities", 12, /obj/item/clothing/under/colonist/wy_davisone, null, VENDOR_ITEM_REGULAR), - list("Steward Utilities", 12, /obj/item/clothing/under/colonist/wy_joliet_shopsteward, null, VENDOR_ITEM_REGULAR), + list("Frontier Jumpsuit", 12, /obj/item/clothing/under/rank/synthetic/frontier, null, VENDOR_ITEM_REGULAR), + list("UA Grey Jumpsuit", 12, /obj/item/clothing/under/colonist/ua_civvies, null, VENDOR_ITEM_REGULAR), + list("UA Brown Jumpsuit", 12, /obj/item/clothing/under/colonist/wy_davisone, null, VENDOR_ITEM_REGULAR), + list("UA Green Utility Uniform", 12, /obj/item/clothing/under/rank/synthetic/utility, null, VENDOR_ITEM_REGULAR), + list("Grey Utilities", 12, /obj/item/clothing/under/rank/synthetic/utility/yellow, null, VENDOR_ITEM_REGULAR), + list("Grey Utilities and Blue Jeans", 12, /obj/item/clothing/under/rank/synthetic/utility/red, null, VENDOR_ITEM_REGULAR), + list("Blue Utilities and Brown Jeans", 12, /obj/item/clothing/under/rank/synthetic/utility/blue, null, VENDOR_ITEM_REGULAR), + list("Steward Clothes", 12, /obj/item/clothing/under/colonist/wy_joliet_shopsteward, null, VENDOR_ITEM_REGULAR), + list("Red Dress Skirt", 12, /obj/item/clothing/under/blackskirt, null, VENDOR_ITEM_REGULAR), + list("Working Joe Uniform", 36, /obj/item/clothing/under/rank/synthetic/joe, null, VENDOR_ITEM_REGULAR), list("GLASSES", 0, null, null, null), list("HealthMate HUD", 12, /obj/item/clothing/glasses/hud/health, null, VENDOR_ITEM_REGULAR), @@ -211,6 +215,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Shoes, Red", 12, /obj/item/clothing/shoes/red, null, VENDOR_ITEM_REGULAR), list("Shoes, White", 12, /obj/item/clothing/shoes/white, null, VENDOR_ITEM_REGULAR), list("Shoes, Yellow", 12, /obj/item/clothing/shoes/yellow, null, VENDOR_ITEM_REGULAR), + list("Shoes, Seegson", 24, /obj/item/clothing/shoes/dress, null, VENDOR_ITEM_REGULAR), list("HELMET", 0, null, null, null), list("Beanie", 12, /obj/item/clothing/head/beanie, null, VENDOR_ITEM_REGULAR), @@ -219,46 +224,53 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Beret, Red", 12, /obj/item/clothing/head/beret/cm/red, null, VENDOR_ITEM_REGULAR), list("Beret, Standard", 12, /obj/item/clothing/head/beret/cm, null, VENDOR_ITEM_REGULAR), list("Beret, Tan", 12, /obj/item/clothing/head/beret/cm/tan, null, VENDOR_ITEM_REGULAR), - list("Cap", 12, /obj/item/clothing/head/cmcap, null, VENDOR_ITEM_REGULAR), list("Surgical Cap, Blue", 12, /obj/item/clothing/head/surgery/blue, null, VENDOR_ITEM_REGULAR), list("Surgical Cap, Blue", 12, /obj/item/clothing/head/surgery/purple, null, VENDOR_ITEM_REGULAR), list("Surgical Cap, Green", 12, /obj/item/clothing/head/surgery/green, null, VENDOR_ITEM_REGULAR), list("Ushanka", 12, /obj/item/clothing/head/ushanka, null, VENDOR_ITEM_REGULAR), + list("Cap", 12, /obj/item/clothing/head/cmcap, null, VENDOR_ITEM_REGULAR), list("MP Cap", 12, /obj/item/clothing/head/beret/marine/mp/mpcap, null, VENDOR_ITEM_REGULAR), list("RO Cap", 12, /obj/item/clothing/head/cmcap/req, null, VENDOR_ITEM_REGULAR), list("Officer Cap", 12, /obj/item/clothing/head/cmcap/ro, null, VENDOR_ITEM_REGULAR), list("SUIT", 0, null, null, null), - list("Brown Bomber Jacket", 12, /obj/item/clothing/suit/storage/bomber, null, VENDOR_ITEM_REGULAR), - list("Black Bomber Jacket", 12, /obj/item/clothing/suit/storage/bomber/alt, null, VENDOR_ITEM_REGULAR), - list("External webbing", 12, /obj/item/clothing/suit/storage/webbing, null, VENDOR_ITEM_REGULAR), - list("Orange Hazard Vest", 12, /obj/item/clothing/suit/storage/hazardvest, null, VENDOR_ITEM_REGULAR), - list("Blue Hazard Vest", 12, /obj/item/clothing/suit/storage/hazardvest/blue, null, VENDOR_ITEM_REGULAR), - list("Yellow Hazard Vest", 12, /obj/item/clothing/suit/storage/hazardvest/yellow, null, VENDOR_ITEM_REGULAR), - list("Black Hazard Vest", 12, /obj/item/clothing/suit/storage/hazardvest/black, null, VENDOR_ITEM_REGULAR), + list("Bomber Jacket, Brown", 12, /obj/item/clothing/suit/storage/bomber, null, VENDOR_ITEM_REGULAR), + list("Bomber Jacket, Black", 12, /obj/item/clothing/suit/storage/bomber/alt, null, VENDOR_ITEM_REGULAR), + list("External Webbing", 12, /obj/item/clothing/suit/storage/webbing, null, VENDOR_ITEM_REGULAR), + list("Utility Vest", 12, /obj/item/clothing/suit/storage/utility_vest, null, VENDOR_ITEM_REGULAR), + list("Hazard Vest(Orange)", 12, /obj/item/clothing/suit/storage/hazardvest, null, VENDOR_ITEM_REGULAR), + list("Hazard Vest(Blue)", 12, /obj/item/clothing/suit/storage/hazardvest/blue, null, VENDOR_ITEM_REGULAR), + list("Hazard Vest(Yellow)", 12, /obj/item/clothing/suit/storage/hazardvest/yellow, null, VENDOR_ITEM_REGULAR), + list("Hazard Vest(Black)", 12, /obj/item/clothing/suit/storage/hazardvest/black, null, VENDOR_ITEM_REGULAR), list("Synthetic's Snow Suit", 12, /obj/item/clothing/suit/storage/snow_suit/synth, null, VENDOR_ITEM_REGULAR), list("USCM Service Jacket", 12, /obj/item/clothing/suit/storage/jacket/marine/service, null, VENDOR_ITEM_REGULAR), list("USCM MP Service Jacket", 12, /obj/item/clothing/suit/storage/jacket/marine/service/mp, null, VENDOR_ITEM_REGULAR), - list("Brown Windbreaker", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_brown, null, VENDOR_ITEM_REGULAR), - list("Gray Windbreaker", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_gray, null, VENDOR_ITEM_REGULAR), - list("Green Windbreaker", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_green, null, VENDOR_ITEM_REGULAR), - list("First Responder Windbreaker", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_fr, null, VENDOR_ITEM_REGULAR), - list("Exploration Windbreaker", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_covenant, null, VENDOR_ITEM_REGULAR), + list("Windbreaker, Brown", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_brown, null, VENDOR_ITEM_REGULAR), + list("Windbreaker, Grey", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_gray, null, VENDOR_ITEM_REGULAR), + list("Windbreaker, Green", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_green, null, VENDOR_ITEM_REGULAR), + list("Windbreaker, First Responder", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_fr, null, VENDOR_ITEM_REGULAR), + list("Windbreaker, Exploration", 12, /obj/item/clothing/suit/storage/windbreaker/windbreaker_covenant, null, VENDOR_ITEM_REGULAR), list("Labcoat", 12, /obj/item/clothing/suit/storage/labcoat, null, VENDOR_ITEM_REGULAR), list("Labcoat, Researcher", 12, /obj/item/clothing/suit/storage/labcoat/researcher, null, VENDOR_ITEM_REGULAR), - list("RO Jacket", 12, /obj/item/clothing/suit/storage/RO, null, VENDOR_ITEM_REGULAR), + list("Quartermaster Jacket", 12, /obj/item/clothing/suit/storage/RO, null, VENDOR_ITEM_REGULAR), + list("USCM Poncho", 12, /obj/item/clothing/accessory/poncho, null, VENDOR_ITEM_REGULAR), list("BACKPACK", 0, null, null, null), list("Backpack, Industrial", 12, /obj/item/storage/backpack/industrial, null, VENDOR_ITEM_REGULAR), - list("Backpack, USCM IMB", 12, /obj/item/storage/backpack/marine, null, VENDOR_ITEM_REGULAR), list("Backpack, USCM Medical", 12, /obj/item/storage/backpack/marine/medic, null, VENDOR_ITEM_REGULAR), - list("Backpack, USCM Technician", 12, /obj/item/storage/backpack/marine/tech, null, VENDOR_ITEM_REGULAR), + list("Chestrig, Technician", 12, /obj/item/storage/backpack/marine/satchel/tech, null, VENDOR_ITEM_REGULAR), list("Satchel, USCM", 12, /obj/item/storage/backpack/marine/satchel, null, VENDOR_ITEM_REGULAR), list("Satchel, Leather", 12, /obj/item/storage/backpack/satchel, null, VENDOR_ITEM_REGULAR), list("Satchel, Medical", 12, /obj/item/storage/backpack/satchel/med, null, VENDOR_ITEM_REGULAR), - list("USCM Mini-RTO Pack", 12, /obj/item/storage/backpack/marine/satchel/rto/small,null, VENDOR_ITEM_REGULAR), + list("USCM RTO Pack", 12, /obj/item/storage/backpack/marine/satchel/rto, null, VENDOR_ITEM_REGULAR), list("USCM Welderpack", 12, /obj/item/storage/backpack/marine/engineerpack, null, VENDOR_ITEM_REGULAR), - list("USCM Weldersatchel", 12, /obj/item/storage/backpack/marine/engineerpack/satchel, VENDOR_ITEM_REGULAR), + list("USCM Weldersatchel", 12, /obj/item/storage/backpack/marine/engineerpack/satchel, null, VENDOR_ITEM_REGULAR), + + list("OTHER", 0, null, null, null), + list("Red Armband", 6, /obj/item/clothing/accessory/armband, null, VENDOR_ITEM_REGULAR), + list("Yellow Armband", 6, /obj/item/clothing/accessory/armband/engine, null, VENDOR_ITEM_REGULAR), + list("Green Armband", 6, /obj/item/clothing/accessory/armband/medgreen, null, VENDOR_ITEM_REGULAR), + )) /obj/structure/machinery/cm_vending/clothing/synth/snowflake @@ -269,7 +281,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( use_snowflake_points = TRUE vendor_theme = VENDOR_THEME_COMPANY req_access = list(ACCESS_MARINE_SYNTH) - vendor_role = list(JOB_SYNTH, JOB_SYNTH_SURVIVOR) + vendor_role = list(JOB_SYNTH, JOB_SYNTH_SURVIVOR, JOB_WORKING_JOE) vend_delay = 1 SECONDS @@ -291,7 +303,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( /obj/structure/machinery/cm_vending/own_points/experimental_tools/attackby(obj/item/W, mob/user) if(istype(W, /obj/item/coin/marine/synth)) if(user.drop_inv_item_to_loc(W, src)) - available_points = available_points + 45 + available_points = 45 available_points_to_display = available_points to_chat(user, SPAN_NOTICE("You insert \the [W] into \the [src].")) return diff --git a/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm b/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm index 4cc491cecf1d..fb9b662be1bc 100644 --- a/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm +++ b/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm @@ -319,24 +319,24 @@ GLOBAL_LIST_INIT(cm_vending_clothing_vehicle_crew, list( list("M103 Vehicle-Ammo Rig", 0, /obj/item/storage/belt/tank, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Toolbelt Rig (Full)", 0, /obj/item/storage/belt/utility/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/tank, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/tank, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), diff --git a/code/game/machinery/vending/vendor_types/dress.dm b/code/game/machinery/vending/vendor_types/dress.dm index 937caef85089..aff221260d03 100644 --- a/code/game/machinery/vending/vendor_types/dress.dm +++ b/code/game/machinery/vending/vendor_types/dress.dm @@ -74,7 +74,7 @@ if(uniform_path in vended_items) can_vend = FALSE var/name = sanitize(initial(O.name)) - var/flags = can_vend ? NO_FLAGS : MARINE_CAN_BUY_ALL + var/flags = can_vend ? null : MARINE_CAN_BUY_DRESS display_list += list( list(name, 0, uniform_path, flags, VENDOR_ITEM_REGULAR) ) diff --git a/code/game/machinery/vending/vendor_types/engineering.dm b/code/game/machinery/vending/vendor_types/engineering.dm index 83f69ae09889..2fe6962e93bb 100644 --- a/code/game/machinery/vending/vendor_types/engineering.dm +++ b/code/game/machinery/vending/vendor_types/engineering.dm @@ -25,6 +25,7 @@ list("Utility Tool Belt", round(scale * 2), /obj/item/storage/belt/utility, VENDOR_ITEM_REGULAR), list("Welding Goggles", round(scale * 2), /obj/item/clothing/glasses/welding, VENDOR_ITEM_REGULAR), list("Welding Helmet", round(scale * 2), /obj/item/clothing/head/welding, VENDOR_ITEM_REGULAR), + list("Toolkit", round(scale * 4), /obj/item/storage/firstaid/toolkit/empty, VENDOR_ITEM_REGULAR), list("SCANNERS", -1, null, null), list("Atmos Scanner", round(scale * 2), /obj/item/device/analyzer, VENDOR_ITEM_REGULAR), @@ -54,6 +55,8 @@ list("EQUIPMENT", -1, null, null), list("Utility Tool Belt", round(scale * 4), /obj/item/storage/belt/utility, VENDOR_ITEM_REGULAR), list("Cable Coil", round(scale * 4), /obj/item/stack/cable_coil/random, VENDOR_ITEM_REGULAR), + list("Welding Goggles", round(scale * 2), /obj/item/clothing/glasses/welding, VENDOR_ITEM_REGULAR), + list("Toolkit", round(scale * 12), /obj/item/storage/firstaid/toolkit/empty, VENDOR_ITEM_REGULAR), list("TOOLS", -1, null, null), list("Blowtorch", round(scale * 4), /obj/item/tool/weldingtool, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/intelligence_officer.dm b/code/game/machinery/vending/vendor_types/intelligence_officer.dm index b2ef87dea0ee..a2afe897b495 100644 --- a/code/game/machinery/vending/vendor_types/intelligence_officer.dm +++ b/code/game/machinery/vending/vendor_types/intelligence_officer.dm @@ -52,7 +52,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_intelligence_officer, list( GLOBAL_LIST_INIT(cm_vending_clothing_intelligence_officer, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Gloves", 0, /obj/item/clothing/gloves/marine/insulated, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/mcom, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), + list("Headset", 0, /obj/item/device/radio/headset/almayer/intel, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("ARMOR (CHOOSE 1)", 0, null, null, null), @@ -73,27 +73,27 @@ GLOBAL_LIST_INIT(cm_vending_clothing_intelligence_officer, list( list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Toolbelt Rig (Full)", 0, /obj/item/storage/belt/utility/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Document Pouch", 0, /obj/item/storage/pouch/document, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pills)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Document Pouch", 0, /obj/item/storage/pouch/document, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pills)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index a2b76be06618..70ac7701973b 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -24,7 +24,6 @@ /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, /obj/item/reagent_container/hypospray/autoinjector/kelotane, /obj/item/reagent_container/hypospray/autoinjector/oxycodone, - /obj/item/reagent_container/hypospray/autoinjector/quickclot, /obj/item/reagent_container/hypospray/autoinjector/tramadol, /obj/item/reagent_container/hypospray/autoinjector/tricord, /obj/item/reagent_container/hypospray/autoinjector/emergency, @@ -134,8 +133,8 @@ /obj/structure/machinery/cm_vending/sorted/medical/populate_product_list(scale) listed_products = list( list("FIELD SUPPLIES", -1, null, null), - list("Advanced Burn Kit", round(scale * 7), /obj/item/stack/medical/advanced/ointment, VENDOR_ITEM_REGULAR), - list("Advanced Trauma Kit", round(scale * 7), /obj/item/stack/medical/advanced/bruise_pack, VENDOR_ITEM_REGULAR), + list("Burn Kit", round(scale * 7), /obj/item/stack/medical/advanced/ointment, VENDOR_ITEM_REGULAR), + list("Trauma Kit", round(scale * 7), /obj/item/stack/medical/advanced/bruise_pack, VENDOR_ITEM_REGULAR), list("Ointment", round(scale * 7), /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), list("Roll of Gauze", round(scale * 7), /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), list("Splints", round(scale * 7), /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), @@ -147,7 +146,6 @@ list("Autoinjector (Inaprovaline)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, VENDOR_ITEM_REGULAR), list("Autoinjector (Kelotane)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/kelotane, VENDOR_ITEM_REGULAR), list("Autoinjector (Oxycodone)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/oxycodone, VENDOR_ITEM_REGULAR), - list("Autoinjector (QuickClot)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/quickclot, VENDOR_ITEM_REGULAR), list("Autoinjector (Tramadol)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/tramadol, VENDOR_ITEM_REGULAR), list("Autoinjector (Tricord)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/tricord, VENDOR_ITEM_REGULAR), @@ -168,7 +166,6 @@ list("Pill Bottle (Inaprovaline)", round(scale * 3), /obj/item/storage/pill_bottle/inaprovaline, VENDOR_ITEM_REGULAR), list("Pill Bottle (Kelotane)", round(scale * 3), /obj/item/storage/pill_bottle/kelotane, VENDOR_ITEM_REGULAR), list("Pill Bottle (Peridaxon)", round(scale * 2), /obj/item/storage/pill_bottle/peridaxon, VENDOR_ITEM_REGULAR), - list("Pill Bottle (QuickClot)", round(scale * 2), /obj/item/storage/pill_bottle/quickclot, VENDOR_ITEM_REGULAR), list("Pill Bottle (Tramadol)", round(scale * 3), /obj/item/storage/pill_bottle/tramadol, VENDOR_ITEM_REGULAR), list("MEDICAL UTILITIES", -1, null, null), @@ -275,7 +272,7 @@ /obj/structure/machinery/cm_vending/sorted/medical/blood name = "\improper MM Blood Dispenser" - desc = "Marine Med brand Blood Pack Dispensary" + desc = "The Marine Med Brand Blood Pack Dispensary is the premier, top-of-the-line blood dispenser of 2105! Get yours today!" //Don't update this year, the joke is it's old. icon_state = "blood" wrenchable = TRUE hackable = TRUE @@ -368,8 +365,8 @@ list("Health Analyzer", 8, /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR), list("FIELD SUPPLIES", -1, null, null), - list("Advanced Burn Kit", 8, /obj/item/stack/medical/advanced/ointment, VENDOR_ITEM_REGULAR), - list("Advanced Trauma Kit", 8, /obj/item/stack/medical/advanced/bruise_pack, VENDOR_ITEM_REGULAR), + list("Burn Kit", 8, /obj/item/stack/medical/advanced/ointment, VENDOR_ITEM_REGULAR), + list("Trauma Kit", 8, /obj/item/stack/medical/advanced/bruise_pack, VENDOR_ITEM_REGULAR), list("Ointment", 8, /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), list("Roll of Gauze", 8, /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), list("Splints", 8, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR) diff --git a/code/game/machinery/vending/vendor_types/requisitions.dm b/code/game/machinery/vending/vendor_types/requisitions.dm index 10d5112132e4..b979fe4a03a9 100644 --- a/code/game/machinery/vending/vendor_types/requisitions.dm +++ b/code/game/machinery/vending/vendor_types/requisitions.dm @@ -35,7 +35,7 @@ list("SU-6 Smart Pistol", round(scale * 3), /obj/item/storage/box/guncase/smartpistol, VENDOR_ITEM_REGULAR), list("MOU-53 Shotgun", round(scale * 2), /obj/item/storage/box/guncase/mou53, VENDOR_ITEM_REGULAR), list("XM88 Heavy Rifle", round(scale * 3), /obj/item/storage/box/guncase/xm88, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", round(scale * 2), /obj/item/storage/box/guncase/lmg, VENDOR_ITEM_REGULAR), + list("M41AE2 Heavy Pulse Rifle", round(scale * 2.5), /obj/item/storage/box/guncase/lmg, VENDOR_ITEM_REGULAR), list("M41A Pulse Rifle MK1", round(scale * 3), /obj/item/storage/box/guncase/m41aMK1, VENDOR_ITEM_REGULAR), list("M56D Heavy Machine Gun", round(scale * 2), /obj/item/storage/box/guncase/m56d, VENDOR_ITEM_REGULAR), list("M2C Heavy Machine Gun", round(scale * 2), /obj/item/storage/box/guncase/m2c, VENDOR_ITEM_REGULAR), @@ -74,14 +74,15 @@ list("Technician Welderpack", round(scale * 2), /obj/item/storage/backpack/marine/engineerpack, VENDOR_ITEM_REGULAR), list("Mortar Shell Backpack", round(scale * 1), /obj/item/storage/backpack/marine/mortarpack, VENDOR_ITEM_REGULAR), list("Technician Welder-Satchel", round(scale * 5), /obj/item/storage/backpack/marine/engineerpack/satchel, VENDOR_ITEM_REGULAR), - list("Small Radio Telephone Pack", round(scale * 4), /obj/item/storage/backpack/marine/satchel/rto/small, VENDOR_ITEM_REGULAR), + list("IMP Ammo Rack", round(scale * 2), /obj/item/storage/backpack/marine/ammo_rack, VENDOR_ITEM_REGULAR), + list("Radio Telephone Pack", round(scale * 2), /obj/item/storage/backpack/marine/satchel/rto, VENDOR_ITEM_REGULAR), list("BELTS", -1, null, null), list("G8-A General Utility Pouch", round(scale * 2), /obj/item/storage/backpack/general_belt, VENDOR_ITEM_REGULAR), list("M276 Ammo Load Rig", round(scale * 15), /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), list("M276 General Pistol Holster Rig", round(scale * 10), /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), list("M276 Knife Rig", round(scale * 5), /obj/item/storage/belt/knifepouch, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", round(scale * 5), /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", round(scale * 5), /obj/item/storage/belt/gun/m39, VENDOR_ITEM_REGULAR), list("M276 M40 Grenade Rig", round(scale * 2), /obj/item/storage/belt/grenade, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", round(scale * 5), /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", round(scale * 2), /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), @@ -91,25 +92,27 @@ list("POUCHES", -1, null, null), list("Autoinjector Pouch", round(scale * 2), /obj/item/storage/pouch/autoinjector, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", round(scale * 2), /obj/item/storage/pouch/medkit, VENDOR_ITEM_REGULAR), + list("Medical Pouch", round(scale * 2), /obj/item/storage/pouch/medical, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Full)", round(scale * 5), /obj/item/storage/pouch/firstaid/full, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", round(scale * 2), /obj/item/storage/pouch/first_responder, VENDOR_ITEM_REGULAR), + list("Syringe Pouch", round(scale * 2), /obj/item/storage/pouch/syringe, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", round(scale * 2), /obj/item/storage/pouch/tools/full, VENDOR_ITEM_REGULAR), list("Construction Pouch", round(scale * 2), /obj/item/storage/pouch/construction, VENDOR_ITEM_REGULAR), - list("Document Pouch", round(scale * 2), /obj/item/storage/pouch/document/small, VENDOR_ITEM_REGULAR), list("Electronics Pouch", round(scale * 2), /obj/item/storage/pouch/electronics, VENDOR_ITEM_REGULAR), list("Explosive Pouch", round(scale * 2), /obj/item/storage/pouch/explosive, VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Full)", round(scale * 5), /obj/item/storage/pouch/firstaid/full, VENDOR_ITEM_REGULAR), - list("First Responder Pouch", round(scale * 2), /obj/item/storage/pouch/first_responder, VENDOR_ITEM_REGULAR), list("Flare Pouch (Full)", round(scale * 5), /obj/item/storage/pouch/flare/full, VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", round(scale * 4), /obj/item/storage/pouch/flamertank, VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", round(scale * 5), /obj/item/storage/pouch/magazine/pistol/large, VENDOR_ITEM_REGULAR), - list("Magazine Pouch", round(scale * 5), /obj/item/storage/pouch/magazine, VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", round(scale * 5), /obj/item/storage/pouch/shotgun, VENDOR_ITEM_REGULAR), + list("Document Pouch", round(scale * 2), /obj/item/storage/pouch/document/small, VENDOR_ITEM_REGULAR), + list("Sling Pouch", round(scale * 2), /obj/item/storage/pouch/sling, VENDOR_ITEM_REGULAR), list("Machete Pouch (Full)", round(scale * 4), /obj/item/storage/pouch/machete/full, VENDOR_ITEM_REGULAR), - list("Medical Pouch", round(scale * 2), /obj/item/storage/pouch/medical, VENDOR_ITEM_REGULAR), + list("Bayonet Pouch", round(scale * 2), /obj/item/storage/pouch/bayonet, VENDOR_ITEM_REGULAR), list("Medium General Pouch", round(scale * 2), /obj/item/storage/pouch/general/medium, VENDOR_ITEM_REGULAR), - list("Medkit Pouch", round(scale * 2), /obj/item/storage/pouch/medkit, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", round(scale * 5), /obj/item/storage/pouch/magazine, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", round(scale * 5), /obj/item/storage/pouch/shotgun, VENDOR_ITEM_REGULAR), list("Sidearm Pouch", round(scale * 5), /obj/item/storage/pouch/pistol, VENDOR_ITEM_REGULAR), - list("Syringe Pouch", round(scale * 2), /obj/item/storage/pouch/syringe, VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", round(scale * 2), /obj/item/storage/pouch/tools/full, VENDOR_ITEM_REGULAR), - list("Sling Pouch", round(scale * 2), /obj/item/storage/pouch/sling, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", round(scale * 5), /obj/item/storage/pouch/magazine/pistol/large, VENDOR_ITEM_REGULAR), + list("Fuel Tank Strap Pouch", round(scale * 4), /obj/item/storage/pouch/flamertank, VENDOR_ITEM_REGULAR), + list("Large General Pouch", round(scale * 2), /obj/item/storage/pouch/general/large, VENDOR_ITEM_REGULAR), list("Large Magazine Pouch", round(scale * 2), /obj/item/storage/pouch/magazine/large, VENDOR_ITEM_REGULAR), list("Large Shotgun Shell Pouch", round(scale * 2), /obj/item/storage/pouch/shotgun/large, VENDOR_ITEM_REGULAR), @@ -198,73 +201,6 @@ /turf/closed/wall/almayer, ) -/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad - name = "\improper ColMarTech Automated Armaments Squad Vendor" - desc = "An automated supply rack hooked up to a small storage of various firearms and explosives. Can be accessed by any Marine Rifleman." - req_access = list(ACCESS_MARINE_ALPHA) - req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_SPECPREP, ACCESS_MARINE_RO) - hackable = TRUE - - vend_x_offset = 2 - vend_y_offset = 1 - vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_TO_HAND - -/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad/ui_state(mob/user) - return GLOB.not_incapacitated_and_adjacent_strict_state - -/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad/populate_product_list(scale) - listed_products = list( - list("WEBBINGS", -1, null, null), - list("Brown Webbing Vest", round(scale * 2), /obj/item/clothing/accessory/storage/black_vest/brown_vest, VENDOR_ITEM_REGULAR), - list("Black Webbing Vest", round(scale * 1), /obj/item/clothing/accessory/storage/black_vest, VENDOR_ITEM_REGULAR), - list("Webbing", round(scale * 3), /obj/item/clothing/accessory/storage/webbing, VENDOR_ITEM_REGULAR), - list("Drop Pouch", round(scale * 1), /obj/item/clothing/accessory/storage/droppouch, VENDOR_ITEM_REGULAR), - list("Shoulder Holster", round(scale * 1), /obj/item/clothing/accessory/storage/holster, VENDOR_ITEM_REGULAR), - - list("BACKPACKS", -1, null, null), - list("Lightweight IMP Backpack", round(scale * 15), /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), - list("Shotgun Scabbard", round(scale * 5), /obj/item/storage/large_holster/m37, VENDOR_ITEM_REGULAR), - list("USCM Technician Welderpack", round(scale * 2), /obj/item/storage/backpack/marine/engineerpack, VENDOR_ITEM_REGULAR), - list("Technician Welder-Satchel", round(scale * 3), /obj/item/storage/backpack/marine/engineerpack/satchel, VENDOR_ITEM_REGULAR), - list("Small Radio Telephone Backpack", round(scale * 2), /obj/item/storage/backpack/marine/satchel/rto/small, VENDOR_ITEM_REGULAR), - - list("BELTS", -1, null, null), - list("G8-A General Utility Pouch", round(scale * 2), /obj/item/storage/backpack/general_belt, VENDOR_ITEM_REGULAR), - list("M276 General Pistol Holster Rig", round(scale * 10), /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", round(scale * 2), /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), - list("M276 M44 Holster Rig", round(scale * 5), /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), - list("M276 M82F Holster Rig", round(scale * 2), /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), - list("M276 M40 Grenade Rig", round(scale * 3), /obj/item/storage/belt/grenade, VENDOR_ITEM_REGULAR), - - list("POUCHES", -1, null, null), - list("Construction Pouch", round(scale * 2), /obj/item/storage/pouch/construction, VENDOR_ITEM_REGULAR), - list("Document Pouch", round(scale * 2), /obj/item/storage/pouch/document/small, VENDOR_ITEM_REGULAR), - list("Explosive Pouch", round(scale * 2), /obj/item/storage/pouch/explosive, VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Full)", round(scale * 5), /obj/item/storage/pouch/firstaid/full, VENDOR_ITEM_REGULAR), - list("First Responder Pouch (Empty)", round(scale * 4), /obj/item/storage/pouch/first_responder, VENDOR_ITEM_REGULAR), - list("Flare Pouch", round(scale * 5), /obj/item/storage/pouch/flare/full, VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", round(scale * 3), /obj/item/storage/pouch/magazine/pistol/large, VENDOR_ITEM_REGULAR), - list("Magazine Pouch", round(scale * 5), /obj/item/storage/pouch/magazine, VENDOR_ITEM_REGULAR), - list("Medical Pouch (Empty)", round(scale * 4), /obj/item/storage/pouch/medical, VENDOR_ITEM_REGULAR), - list("Medium General Pouch", round(scale * 2), /obj/item/storage/pouch/general/medium, VENDOR_ITEM_REGULAR), - list("Medkit Pouch", round(scale * 2), /obj/item/storage/pouch/medkit, VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", round(scale *5), /obj/item/storage/pouch/shotgun, VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", round(scale * 15), /obj/item/storage/pouch/pistol, VENDOR_ITEM_REGULAR), - list("Syringe Pouch", round(scale * 2), /obj/item/storage/pouch/syringe, VENDOR_ITEM_REGULAR), - list("Tools Pouch", round(scale * 2), /obj/item/storage/pouch/tools, VENDOR_ITEM_REGULAR), - list("Sling Pouch", round(scale * 2), /obj/item/storage/pouch/sling, VENDOR_ITEM_REGULAR), - - list("MISCELLANEOUS", -1, null, null), - list("Combat Flashlight", round(scale * 5), /obj/item/device/flashlight/combat, VENDOR_ITEM_REGULAR), - list("Entrenching Tool (ET)", round(scale * 2), /obj/item/tool/shovel/etool/folded, VENDOR_ITEM_REGULAR), - list("M89-S Signal Flare Pack", round(scale * 1), /obj/item/storage/box/m94/signal, VENDOR_ITEM_REGULAR), - list("Machete Scabbard (Full)", round(scale * 5), /obj/item/storage/large_holster/machete/full, VENDOR_ITEM_REGULAR), - list("Binoculars", round(scale * 1), /obj/item/device/binoculars, VENDOR_ITEM_REGULAR), - list("MB-6 Folding Barricades (x3)", round(scale * 2), /obj/item/stack/folding_barricade/three, VENDOR_ITEM_REGULAR), - list("Spare PDT/L Battle Buddy Kit", round(scale * 3), /obj/item/storage/box/pdt_kit, VENDOR_ITEM_REGULAR), - list("W-Y brand rechargeable mini-battery", round(scale * 2.5), /obj/item/cell/crap, VENDOR_ITEM_REGULAR) - ) - //------------AMMUNITION VENDOR--------------- /obj/structure/machinery/cm_vending/sorted/cargo_ammo @@ -305,7 +241,7 @@ list("M41A MK2 Extended Magazine (10x24mm)", round(scale * 8.1), /obj/item/ammo_magazine/rifle/extended, VENDOR_ITEM_REGULAR), list("SPECIAL AMMUNITION", -1, null, null), - list("M56 Powerpack", 2, /obj/item/smartgun_powerpack, VENDOR_ITEM_REGULAR), + list("M56 Battery", 4, /obj/item/smartgun_battery, VENDOR_ITEM_REGULAR), list("M56 Smartgun Drum", 4, /obj/item/ammo_magazine/smartgun, VENDOR_ITEM_REGULAR), list("M44 Heavy Speed Loader (.44)", round(scale * 10.5), /obj/item/ammo_magazine/revolver/heavy, VENDOR_ITEM_REGULAR), list("M44 Marksman Speed Loader (.44)", round(scale * 5.7), /obj/item/ammo_magazine/revolver/marksman, VENDOR_ITEM_REGULAR), @@ -368,49 +304,6 @@ /obj/structure/machinery/door/airlock, /turf/closed/wall/almayer) -/obj/structure/machinery/cm_vending/sorted/cargo_ammo/squad - name = "\improper ColMarTech Automated Munition Squad Vendor" - desc = "An automated supply rack hooked up to a small storage of various ammunition types. Can be accessed by any Marine Rifleman." - req_access = list(ACCESS_MARINE_ALPHA) - req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_SPECPREP, ACCESS_MARINE_RO) - hackable = TRUE - vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_TO_HAND - - vend_x_offset = 2 - -/obj/structure/machinery/cm_vending/sorted/cargo_ammo/squad/ui_state(mob/user) - return GLOB.not_incapacitated_and_adjacent_strict_state - - -/obj/structure/machinery/cm_vending/sorted/cargo_ammo/squad/populate_product_list(scale) - listed_products = list( - - list("ARMOR-PIERCING AMMUNITION", -1, null, null), - list("M4RA AP Magazine (10x24mm)", round(scale * 3.5), /obj/item/ammo_magazine/rifle/m4ra/ap, VENDOR_ITEM_REGULAR), - list("M39 AP Magazine (10x20mm)", round(scale * 3), /obj/item/ammo_magazine/smg/m39/ap, VENDOR_ITEM_REGULAR), - list("M41A AP Magazine (10x24mm)", round(scale * 3), /obj/item/ammo_magazine/rifle/ap, VENDOR_ITEM_REGULAR), - - list("EXTENDED AMMUNITION", -1, null, null), - list("M39 Extended Magazine (10x20mm)", round(scale * 1.8), /obj/item/ammo_magazine/smg/m39/extended, VENDOR_ITEM_REGULAR), - list("M41A Extended Magazine (10x24mm)", round(scale * 1.9), /obj/item/ammo_magazine/rifle/extended, VENDOR_ITEM_REGULAR), - - list("SPECIAL AMMUNITION", -1, null, null), - list("M56 Smartgun Drum", 1, /obj/item/ammo_magazine/smartgun, VENDOR_ITEM_REGULAR), - list("M44 Heavy Speed Loader (.44)", round(scale * 2), /obj/item/ammo_magazine/revolver/heavy, VENDOR_ITEM_REGULAR), - list("M44 Marksman Speed Loader (.44)", round(scale * 2), /obj/item/ammo_magazine/revolver/marksman, VENDOR_ITEM_REGULAR), - - list("RESTRICTED FIREARM AMMUNITION", -1, null, null), - list("VP78 Magazine", round(scale * 5), /obj/item/ammo_magazine/pistol/vp78, VENDOR_ITEM_REGULAR), - list("SU-6 Smartpistol Magazine (.45)", round(scale * 5), /obj/item/ammo_magazine/pistol/smart, VENDOR_ITEM_REGULAR), - list("M240 Incinerator Tank", round(scale * 3), /obj/item/ammo_magazine/flamer_tank, VENDOR_ITEM_REGULAR), - list("M41AE2 Box Magazine (10x24mm)", round(scale * 3), /obj/item/ammo_magazine/rifle/lmg, VENDOR_ITEM_REGULAR), - list("M56D Drum Magazine", round(scale * 2), /obj/item/ammo_magazine/m56d, VENDOR_ITEM_REGULAR), - list("M2C Box Magazine", round(scale * 2), /obj/item/ammo_magazine/m2c, VENDOR_ITEM_REGULAR), - list("HIRR Baton Slugs", round(scale * 6), /obj/item/explosive/grenade/slug/baton, VENDOR_ITEM_REGULAR), - list("M74 AGM-S Star Shell", round(scale * 2), /obj/item/explosive/grenade/high_explosive/airburst/starshell, VENDOR_ITEM_REGULAR), - list("M74 AGM-S Hornet Shell", round(scale * 4), /obj/item/explosive/grenade/high_explosive/airburst/hornet_shell, VENDOR_ITEM_REGULAR), - ) - //Special cargo-specific vendor with vending offsets /obj/structure/machinery/cm_vending/sorted/cargo_ammo/cargo vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_LOAD_AMMO_BOXES //We want to vend to turf not hand, since we are in requisitions @@ -449,7 +342,6 @@ /obj/structure/machinery/cm_vending/sorted/attachments/populate_product_list(scale) listed_products = list( list("BARREL", -1, null, null), - list("Barrel Charger", round(scale * 2.5), /obj/item/attachable/heavy_barrel, VENDOR_ITEM_REGULAR), list("Extended Barrel", round(scale * 6.5), /obj/item/attachable/extended_barrel, VENDOR_ITEM_REGULAR), list("M5 Bayonet", round(scale * 10.5), /obj/item/attachable/bayonet, VENDOR_ITEM_REGULAR), list("Recoil Compensator", round(scale * 6.5), /obj/item/attachable/compensator, VENDOR_ITEM_REGULAR), @@ -513,54 +405,6 @@ ) vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY //We want to vend to turf not hand, since we are in requisitions -/obj/structure/machinery/cm_vending/sorted/attachments/squad - name = "\improper Armat Systems Squad Attachments Vendor" - desc = "An automated supply rack hooked up to a small storage of weapons attachments. Can be accessed by any Marine Rifleman." - req_access = list(ACCESS_MARINE_ALPHA) - req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_SPECPREP, ACCESS_MARINE_RO) - hackable = TRUE - - vend_y_offset = 1 - -/obj/structure/machinery/cm_vending/sorted/attachments/squad/ui_state(mob/user) - return GLOB.not_incapacitated_and_adjacent_strict_state - -/obj/structure/machinery/cm_vending/sorted/attachments/squad/populate_product_list(scale) - listed_products = list( - list("BARREL", -1, null, null), - list("Barrel Charger", round(scale * 0.9), /obj/item/attachable/heavy_barrel, VENDOR_ITEM_REGULAR), - list("Extended Barrel", round(scale * 2.5), /obj/item/attachable/extended_barrel, VENDOR_ITEM_REGULAR), - list("Recoil Compensator", round(scale * 2.5), /obj/item/attachable/compensator, VENDOR_ITEM_REGULAR), - list("Suppressor", round(scale * 2.5), /obj/item/attachable/suppressor, VENDOR_ITEM_REGULAR), - - list("RAIL", -1, null, null), - list("B8 Smart-Scope", round(scale * 1.5), /obj/item/attachable/scope/mini_iff, VENDOR_ITEM_REGULAR), - list("Magnetic Harness", round(scale * 4), /obj/item/attachable/magnetic_harness, VENDOR_ITEM_REGULAR), - list("S4 2x Telescopic Mini-Scope", round(scale * 2), /obj/item/attachable/scope/mini, VENDOR_ITEM_REGULAR), - list("S5 Red-Dot Sight", round(scale * 3), /obj/item/attachable/reddot, VENDOR_ITEM_REGULAR), - list("S6 Reflex Sight", round(scale * 3), /obj/item/attachable/reflex, VENDOR_ITEM_REGULAR), - list("S8 4x Telescopic Scope", round(scale * 2), /obj/item/attachable/scope, VENDOR_ITEM_REGULAR), - - list("UNDERBARREL", -1, null, null), - list("Angled Grip", round(scale * 2.5), /obj/item/attachable/angledgrip, VENDOR_ITEM_REGULAR), - list("Bipod", round(scale * 2.5), /obj/item/attachable/bipod, VENDOR_ITEM_REGULAR), - list("Burst Fire Assembly", round(scale * 1.5), /obj/item/attachable/burstfire_assembly, VENDOR_ITEM_REGULAR), - list("Gyroscopic Stabilizer", round(scale * 1.5), /obj/item/attachable/gyro, VENDOR_ITEM_REGULAR), - list("Laser Sight", round(scale * 3), /obj/item/attachable/lasersight, VENDOR_ITEM_REGULAR), - list("Mini Flamethrower", round(scale * 1.5), /obj/item/attachable/attached_gun/flamer, VENDOR_ITEM_REGULAR), - list("XM-VESG-1 Flamer Nozzle", round(scale * 1.5), /obj/item/attachable/attached_gun/flamer_nozzle, VENDOR_ITEM_REGULAR), - list("U7 Underbarrel Shotgun", round(scale * 1.5), /obj/item/attachable/attached_gun/shotgun, VENDOR_ITEM_REGULAR), - list("Underbarrel Extinguisher", round(scale * 1.5), /obj/item/attachable/attached_gun/extinguisher, VENDOR_ITEM_REGULAR), - list("Vertical Grip", round(scale * 3), /obj/item/attachable/verticalgrip, VENDOR_ITEM_REGULAR), - - list("STOCK", -1, null, null), - list("M37 Wooden Stock", round(scale * 1.5), /obj/item/attachable/stock/shotgun, VENDOR_ITEM_REGULAR), - list("M39 Arm Brace", round(scale * 1.5), /obj/item/attachable/stock/smg/collapsible/brace, VENDOR_ITEM_REGULAR), - list("M39 Stock", round(scale * 1.5), /obj/item/attachable/stock/smg, VENDOR_ITEM_REGULAR), - list("M41A Solid Stock", round(scale * 1.5), /obj/item/attachable/stock/rifle, VENDOR_ITEM_REGULAR), - list("M44 Magnum Sharpshooter Stock", round(scale * 1.5), /obj/item/attachable/stock/revolver, VENDOR_ITEM_REGULAR) - ) - //------------UNIFORM VENDOR--------------- /obj/structure/machinery/cm_vending/sorted/uniform_supply @@ -583,6 +427,7 @@ list("ARMOR", -1, null, null), list("M10 Pattern Marine Helmet", 20, /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), list("M10 Pattern Technician Helmet", 20, /obj/item/clothing/head/helmet/marine/tech, VENDOR_ITEM_REGULAR), + list("M10 Pattern Corpman Helmet", 20, /obj/item/clothing/head/helmet/marine/medic, VENDOR_ITEM_REGULAR), list("M3 Pattern Carrier Marine Armor", 20, /obj/item/clothing/suit/storage/marine/carrier, VENDOR_ITEM_REGULAR), list("M3 Pattern Padded Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padded, VENDOR_ITEM_REGULAR), list("M3 Pattern Padless Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless, VENDOR_ITEM_REGULAR), @@ -656,3 +501,43 @@ update_derived_ammo_and_boxes_on_add(R) updateUsrDialog() return //We found our item, no reason to go on. + +//------------TRAINING WEAPONS RACK--------------- + +/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/training //Nonlethal stuff for events. + name = "\improper ColMarTech Automated Training Weapons Rack" + desc = "An automated weapon rack hooked up to a big storage of standard-issue weapons and non-lethal ammunition." + +/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/training/populate_product_list(scale) + listed_products = list( + list("PRIMARY FIREARMS", -1, null, null), + list("M4RA Battle Rifle", round(scale * 10), /obj/item/weapon/gun/rifle/m4ra, VENDOR_ITEM_REGULAR), + list("M37A2 Pump Shotgun", round(scale * 15), /obj/item/weapon/gun/shotgun/pump, VENDOR_ITEM_REGULAR), + list("M39 Submachine Gun", round(scale * 30), /obj/item/weapon/gun/smg/m39, VENDOR_ITEM_REGULAR), + list("M41A Pulse Rifle MK2", round(scale * 30), /obj/item/weapon/gun/rifle/m41a, VENDOR_ITEM_RECOMMENDED), + + list("PRIMARY NONLETHAL AMMUNITION", -1, null, null), + list("Box of Beanbag Shells (12g)", round(scale * 15), /obj/item/ammo_magazine/shotgun/beanbag, VENDOR_ITEM_REGULAR), + list("M4RA Rubber Magazine (10x24mm)", round(scale * 15), /obj/item/ammo_magazine/rifle/m4ra/rubber, VENDOR_ITEM_REGULAR), + list("M39 Rubber Magazine (10x20mm)", round(scale * 25), /obj/item/ammo_magazine/smg/m39/rubber, VENDOR_ITEM_REGULAR), + list("M41A Rubber Magazine (10x24mm)", round(scale * 25), /obj/item/ammo_magazine/rifle/rubber, VENDOR_ITEM_REGULAR), + + list("SIDEARMS", -1, null, null), + list("88 Mod 4 Combat Pistol", round(scale * 25), /obj/item/weapon/gun/pistol/mod88, VENDOR_ITEM_REGULAR), + list("M4A3 Service Pistol", round(scale * 25), /obj/item/weapon/gun/pistol/m4a3, VENDOR_ITEM_REGULAR), + + list("SIDEARM NONLETHAL AMMUNITION", -1, null, null), + list("88M4 Rubber Magazine (9mm)", round(scale * 25), /obj/item/ammo_magazine/pistol/mod88/rubber, VENDOR_ITEM_REGULAR), + list("M4A3 Rubber Magazine (9mm)", round(scale * 25), /obj/item/ammo_magazine/pistol/rubber, VENDOR_ITEM_REGULAR), + + list("ATTACHMENTS", -1, null, null), + list("Rail Flashlight", round(scale * 25), /obj/item/attachable/flashlight, VENDOR_ITEM_RECOMMENDED), + list("Underbarrel Flashlight Grip", round(scale * 10), /obj/item/attachable/flashlight/grip, VENDOR_ITEM_RECOMMENDED), + list("Underslung Grenade Launcher", round(scale * 25), /obj/item/attachable/attached_gun/grenade, VENDOR_ITEM_REGULAR), //They already get these as on-spawns, might as well formalize some spares. + + list("UTILITIES", -1, null, null), + list("M07 Training Grenade", round(scale * 15), /obj/item/explosive/grenade/high_explosive/training, VENDOR_ITEM_REGULAR), + list("M15 Rubber Pellet Grenade", round(scale * 10), /obj/item/explosive/grenade/high_explosive/m15/rubber, VENDOR_ITEM_REGULAR), + list("M5 Bayonet", round(scale * 25), /obj/item/attachable/bayonet, VENDOR_ITEM_REGULAR), + list("M94 Marking Flare Pack", round(scale * 10), /obj/item/storage/box/m94, VENDOR_ITEM_RECOMMENDED) + ) diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm index a2089ea87bb5..faff01f7f299 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm @@ -24,7 +24,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( list("Laser Designator", 15, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_REGULAR), list("Sandbags x25", 10, /obj/item/stack/sandbags_empty/half, null, VENDOR_ITEM_RECOMMENDED), list("Super-Capacity Power Cell", 10, /obj/item/cell/super, null, VENDOR_ITEM_REGULAR), - list("Welding Goggles", 5, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_MANDATORY), + list("Welding Goggles", 5, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_REGULAR), list("ES-11 Mobile Fuel Canister", 4, /obj/item/tool/weldpack/minitank, null, VENDOR_ITEM_REGULAR), list("EXPLOSIVES", 0, null, null, null), @@ -50,7 +50,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( list("VP78 Pistol", 8, /obj/item/storage/box/guncase/vp78, null, VENDOR_ITEM_REGULAR), list("SU-6 Smart Pistol", 12, /obj/item/storage/box/guncase/smartpistol, null, VENDOR_ITEM_REGULAR), list("M240 Incinerator Unit", 12, /obj/item/storage/box/guncase/flamer, null, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", 18, /obj/item/storage/box/guncase/lmg, null, VENDOR_ITEM_REGULAR), list("M79 Grenade Launcher", 24, /obj/item/storage/box/guncase/m79, null, VENDOR_ITEM_REGULAR), list("M56D Heavy Machine Gun", 24, /obj/item/storage/box/guncase/m56d, null, VENDOR_ITEM_REGULAR), @@ -62,7 +61,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( list("M4 Pattern Armor", 30, /obj/item/clothing/suit/storage/marine/rto, null, VENDOR_ITEM_REGULAR), list("Large General Pouch", 6, /obj/item/storage/pouch/general/large, null, VENDOR_ITEM_REGULAR), list("Sling Pouch", 6, /obj/item/storage/pouch/sling, null, VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 6, /obj/item/storage/pouch/magazine/large, null, VENDOR_ITEM_REGULAR), list("Fuel Tank Strap Pouch", 4, /obj/item/storage/pouch/flamertank, null, VENDOR_ITEM_REGULAR), list("Machete Pouch (Full)", 8, /obj/item/storage/pouch/machete/full, null, VENDOR_ITEM_REGULAR), list("Fire Extinguisher (Portable)", 3, /obj/item/tool/extinguisher/mini, null, VENDOR_ITEM_REGULAR), @@ -70,7 +68,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( list("Whistle", 3, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), list("JTAC Pamphlet", 15, /obj/item/pamphlet/skill/jtac, null, VENDOR_ITEM_REGULAR), list("Powerloader Certification", 45, /obj/item/pamphlet/skill/powerloader, null, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 10, /obj/item/storage/pouch/shotgun/large, null, VENDOR_ITEM_RECOMMENDED), list("M276 Pattern Combat Toolbelt Rig", 15, /obj/item/storage/belt/gun/utility, null, VENDOR_ITEM_REGULAR), list("RADIO KEYS", 0, null, null, null), @@ -100,6 +97,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_engi, list( list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Helmet", 0, /obj/item/clothing/head/helmet/marine/tech, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), list("ARMOR (CHOOSE 1)", 0, null, null, null), list("Light Armor", 0, /obj/item/clothing/suit/storage/marine/light, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), @@ -112,12 +110,13 @@ GLOBAL_LIST_INIT(cm_vending_clothing_engi, list( list("Technician Satchel", 0, /obj/item/storage/backpack/marine/satchel/tech, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), list("Technician Welderpack", 0, /obj/item/storage/backpack/marine/engineerpack, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), list("Technician Welder-Satchel", 0, /obj/item/storage/backpack/marine/engineerpack/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), + list("Technician Welder Chestrig", 0, /obj/item/storage/backpack/marine/engineerpack/welder_chestrig, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), list("BELT (CHOOSE 1)", 0, null, null, null), list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), @@ -126,19 +125,19 @@ GLOBAL_LIST_INIT(cm_vending_clothing_engi, list( list("M276 M40 Grenade Rig", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Construction Pouch", 0, /obj/item/storage/pouch/construction, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Explosive Pouch", 0, /obj/item/storage/pouch/explosive, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Construction Pouch", 0, /obj/item/storage/pouch/construction, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Explosive Pouch", 0, /obj/item/storage/pouch/explosive, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_leader.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_leader.dm index dc270d57a0d8..9757576e6d0b 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_leader.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_leader.dm @@ -6,9 +6,9 @@ GLOBAL_LIST_INIT(cm_vending_gear_leader, list( list("SQUAD KIT (CHOOSE 1, for yourself or your squad)", 0, null, null, null), list("M4RA Sniper Kit", 0, /obj/item/storage/box/kit/mini_sniper, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), + list("M41A Standard Kit", 0, /obj/item/storage/box/kit/m41a_kit , MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), list("M240 Pyrotechnician Support Kit", 0, /obj/item/storage/box/kit/mini_pyro, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), list("M2C Heavy Machine Gun", 0, /obj/item/storage/box/guncase/m2c, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", 0, /obj/item/storage/box/guncase/lmg, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), list("M56D Heavy Machine Gun", 0, /obj/item/storage/box/guncase/m56d, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), list("M79 Grenade Launcher", 0, /obj/item/storage/box/guncase/m79, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), list("MOU-53 Shotgun", 0, /obj/item/storage/box/guncase/mou53, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), @@ -26,8 +26,8 @@ GLOBAL_LIST_INIT(cm_vending_gear_leader, list( list("Motion Detector", 5, /obj/item/device/motiondetector, null, VENDOR_ITEM_REGULAR), list("M4 Pattern Armor", 30, /obj/item/clothing/suit/storage/marine/rto, null, VENDOR_ITEM_REGULAR), list("Powerloader Certification", 45, /obj/item/pamphlet/skill/powerloader, null, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 10, /obj/item/storage/pouch/shotgun/large, null, VENDOR_ITEM_RECOMMENDED), list("Fulton Device Stack", 5, /obj/item/stack/fulton, null, VENDOR_ITEM_REGULAR), + list("Radio Telephone Pack", 5, /obj/item/storage/backpack/marine/satchel/rto, null, VENDOR_ITEM_REGULAR), list("ENGINEERING SUPPLIES", 0, null, null, null), list("Insulated Gloves", 3, /obj/item/clothing/gloves/yellow, null, VENDOR_ITEM_REGULAR), @@ -53,8 +53,8 @@ GLOBAL_LIST_INIT(cm_vending_gear_leader, list( list("M40 MFHS Metal Foam Grenade", 5, /obj/item/explosive/grenade/metal_foam, null, VENDOR_ITEM_REGULAR), list("MEDICAL SUPPLIES", 0, null, null, null), - list("Adv Burn Kit", 2, /obj/item/stack/medical/advanced/ointment, null, VENDOR_ITEM_REGULAR), - list("Adv Trauma Kit", 2, /obj/item/stack/medical/advanced/bruise_pack, null, VENDOR_ITEM_REGULAR), + list("Burn Kit", 2, /obj/item/stack/medical/advanced/ointment, null, VENDOR_ITEM_REGULAR), + list("Trauma Kit", 2, /obj/item/stack/medical/advanced/bruise_pack, null, VENDOR_ITEM_REGULAR), list("Advanced Firstaid Kit", 12, /obj/item/storage/firstaid/adv, null, VENDOR_ITEM_REGULAR), list("Medical Splints", 1, /obj/item/stack/medical/splint, null, VENDOR_ITEM_REGULAR), @@ -63,7 +63,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_leader, list( list("Injector (Inaprovaline)", 1, /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, null, VENDOR_ITEM_REGULAR), list("Injector (Kelotane)", 1, /obj/item/reagent_container/hypospray/autoinjector/kelotane, null, VENDOR_ITEM_REGULAR), list("Injector (Oxycodone)", 2, /obj/item/reagent_container/hypospray/autoinjector/oxycodone, null, VENDOR_ITEM_REGULAR), - list("Injector (QuickClot)", 1, /obj/item/reagent_container/hypospray/autoinjector/quickclot, null, VENDOR_ITEM_REGULAR), list("Injector (Tramadol)", 1, /obj/item/reagent_container/hypospray/autoinjector/tramadol, null, VENDOR_ITEM_REGULAR), list("Injector (Tricord)", 1, /obj/item/reagent_container/hypospray/autoinjector/tricord, null, VENDOR_ITEM_REGULAR), @@ -84,7 +83,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_leader, list( list("M240 Incinerator Unit", 18, /obj/item/storage/box/guncase/flamer, null, VENDOR_ITEM_REGULAR), list("VP78 Pistol", 8, /obj/item/storage/box/guncase/vp78, null, VENDOR_ITEM_REGULAR), list("SU-6 Smart Pistol", 12, /obj/item/storage/box/guncase/smartpistol, null, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", 18, /obj/item/storage/box/guncase/lmg, null, VENDOR_ITEM_REGULAR), list("M79 Grenade Launcher", 18, /obj/item/storage/box/guncase/m79, null, VENDOR_ITEM_REGULAR), list("RADIO KEYS", 0, null, null, null), @@ -116,6 +114,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_leader, list( list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Helmet", 0, /obj/item/clothing/head/helmet/marine/leader, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_MANDATORY), list("BACKPACK (CHOOSE 1)", 0, null, null, null), list("Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), @@ -128,7 +127,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_leader, list( list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Lifesaver Bag", 0, /obj/item/storage/belt/medical/lifesaver, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Medical Storage Rig", 0, /obj/item/storage/belt/medical, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), @@ -136,18 +135,18 @@ GLOBAL_LIST_INIT(cm_vending_clothing_leader, list( list("M276 M40 Grenade Rig", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch (Full)", 0, /obj/item/storage/pouch/autoinjector/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch (Full)", 0, /obj/item/storage/pouch/autoinjector/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), @@ -196,7 +195,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_leader, list( spawned_gear_list = list( /obj/item/explosive/plastic, /obj/item/device/binoculars/range/designator, - /obj/item/map/current_map, + /obj/item/storage/box/m94/signal, /obj/item/tool/extinguisher/mini, /obj/item/storage/box/zipcuffs, ) diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm index 5b20872dd2af..7c9682985298 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm @@ -5,11 +5,12 @@ GLOBAL_LIST_INIT(cm_vending_gear_medic, list( list("Essential Medical Set", 0, /obj/effect/essentials_set/medic, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), list("FIELD SUPPLIES", 0, null, null, null), - list("Adv Burn Kit", 2, /obj/item/stack/medical/advanced/ointment, null, VENDOR_ITEM_RECOMMENDED), - list("Adv Trauma Kit", 2, /obj/item/stack/medical/advanced/bruise_pack, null, VENDOR_ITEM_RECOMMENDED), + list("Burn Kit", 2, /obj/item/stack/medical/advanced/ointment, null, VENDOR_ITEM_RECOMMENDED), + list("Trauma Kit", 2, /obj/item/stack/medical/advanced/bruise_pack, null, VENDOR_ITEM_RECOMMENDED), list("Medical Splints", 1, /obj/item/stack/medical/splint, null, VENDOR_ITEM_RECOMMENDED), list("Gauze", 1, /obj/item/stack/medical/bruise_pack, null, VENDOR_ITEM_REGULAR), list("Ointment", 1, /obj/item/stack/medical/ointment, null, VENDOR_ITEM_REGULAR), + list("Blood Bag (O-)", 4, /obj/item/reagent_container/blood/OMinus, null, VENDOR_ITEM_REGULAR), list("FIRSTAID KITS", 0, null, null, null), list("Advanced Firstaid Kit", 12, /obj/item/storage/firstaid/adv, null, VENDOR_ITEM_RECOMMENDED), @@ -26,9 +27,9 @@ GLOBAL_LIST_INIT(cm_vending_gear_medic, list( list("Autoinjector (Inaprovaline)", 1, /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, null, VENDOR_ITEM_REGULAR), list("Autoinjector (Kelotane)", 1, /obj/item/reagent_container/hypospray/autoinjector/kelotane, null, VENDOR_ITEM_REGULAR), list("Autoinjector (Oxycodone)", 2, /obj/item/reagent_container/hypospray/autoinjector/oxycodone, null, VENDOR_ITEM_REGULAR), - list("Autoinjector (QuickClot)", 1, /obj/item/reagent_container/hypospray/autoinjector/quickclot, null, VENDOR_ITEM_REGULAR), list("Autoinjector (Tramadol)", 1, /obj/item/reagent_container/hypospray/autoinjector/tramadol, null, VENDOR_ITEM_REGULAR), list("Autoinjector (Tricord)", 1, /obj/item/reagent_container/hypospray/autoinjector/tricord, null, VENDOR_ITEM_REGULAR), + list("Autoinjector (Emergency)", 2, /obj/item/reagent_container/hypospray/autoinjector/emergency, null, VENDOR_ITEM_REGULAR), list("PILL BOTTLES", 0, null, null, null), list("Pill Bottle (Bicaridine)", 5, /obj/item/storage/pill_bottle/bicaridine, null, VENDOR_ITEM_RECOMMENDED), @@ -37,7 +38,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_medic, list( list("Pill Bottle (Inaprovaline)", 5, /obj/item/storage/pill_bottle/inaprovaline, null, VENDOR_ITEM_REGULAR), list("Pill Bottle (Kelotane)", 5, /obj/item/storage/pill_bottle/kelotane, null, VENDOR_ITEM_RECOMMENDED), list("Pill Bottle (Peridaxon)", 5, /obj/item/storage/pill_bottle/peridaxon, null, VENDOR_ITEM_REGULAR), - list("Pill Bottle (QuickClot)", 5, /obj/item/storage/pill_bottle/quickclot, null, VENDOR_ITEM_REGULAR), list("Pill Bottle (Tramadol)", 5, /obj/item/storage/pill_bottle/tramadol, null, VENDOR_ITEM_RECOMMENDED), list("MEDICAL UTILITIES", 0, null, null, null), @@ -70,16 +70,12 @@ GLOBAL_LIST_INIT(cm_vending_gear_medic, list( list("RESTRICTED FIREARMS", 0, null, null, null), list("VP78 Pistol", 8, /obj/item/storage/box/guncase/vp78, null, VENDOR_ITEM_REGULAR), list("SU-6 Smart Pistol", 12, /obj/item/storage/box/guncase/smartpistol, null, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", 18, /obj/item/storage/box/guncase/lmg, null, VENDOR_ITEM_REGULAR), list("UTILITIES", 0, null, null, null), list("M3 B12 Pattern Armor", 28, /obj/item/clothing/suit/storage/marine/leader, null, VENDOR_ITEM_REGULAR), list("M4 Pattern Armor", 28, /obj/item/clothing/suit/storage/marine/rto, null, VENDOR_ITEM_REGULAR), list("Range Finder", 6, /obj/item/device/binoculars/range, null, VENDOR_ITEM_REGULAR), list("Laser Designator", 8, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_REGULAR), - list("Large General Pouch", 6, /obj/item/storage/pouch/general/large, null, VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 6, /obj/item/storage/pouch/magazine/large, null, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 6, /obj/item/storage/pouch/shotgun/large, null, VENDOR_ITEM_REGULAR), list("Fuel Tank Strap Pouch", 4, /obj/item/storage/pouch/flamertank, null, VENDOR_ITEM_REGULAR), list("Shoulder Holster", 6, /obj/item/clothing/accessory/storage/holster, null, VENDOR_ITEM_REGULAR), list("Machete Scabbard (Full)", 6, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR), @@ -118,6 +114,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_medic, list( list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Helmet", 0, /obj/item/clothing/head/helmet/marine/medic, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), list("ARMOR (CHOOSE 1)", 0, null, null, null), list("Light Armor", 0, /obj/item/clothing/suit/storage/marine/light, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), @@ -133,34 +130,34 @@ GLOBAL_LIST_INIT(cm_vending_clothing_medic, list( list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M40 Grenade Rig", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Vial Pouch (Full)", 0, /obj/item/storage/pouch/vials/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Bicaridine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/bicaridine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Kelotane)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/kelotane, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Revival Mix)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/revival, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (Tricordrazine)", 0, /obj/item/storage/pouch/pressurized_reagent_canister/tricordrazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Pressurized Reagent Canister Pouch (EMPTY)", 0, /obj/item/storage/pouch/pressurized_reagent_canister, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Vial Pouch (Full)", 0, /obj/item/storage/pouch/vials/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), @@ -215,5 +212,8 @@ GLOBAL_LIST_INIT(cm_vending_clothing_medic, list( /obj/item/roller/medevac, /obj/item/roller, /obj/item/tool/surgery/surgical_line, //obj/item/storage/firstaid/surgical once broader medic surgeries are done, but for now suturing is the only good one. - /obj/item/tool/surgery/synthgraft + /obj/item/tool/surgery/synthgraft, + /obj/item/storage/surgical_case/regular, + /obj/item/reagent_container/blood/OMinus, + /obj/item/reagent_container/blood/OMinus, ) diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm index d2945bc98691..b82daa527289 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm @@ -1,3 +1,5 @@ +//------------SQUAD PREP VENDORS ------------------- + //------------SQUAD PREP WEAPON RACKS--------------- /obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep @@ -77,285 +79,9 @@ list("M94 Marking Flare Pack", round(scale * 10), /obj/item/storage/box/m94, VENDOR_ITEM_RECOMMENDED) ) - -/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/training //Nonlethal stuff for events. - name = "\improper ColMarTech Automated Training Weapons Rack" - desc = "An automated weapon rack hooked up to a big storage of standard-issue weapons and non-lethal ammunition." - -/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/training/populate_product_list(scale) - listed_products = list( - list("PRIMARY FIREARMS", -1, null, null), - list("M4RA Battle Rifle", round(scale * 10), /obj/item/weapon/gun/rifle/m4ra, VENDOR_ITEM_REGULAR), - list("M37A2 Pump Shotgun", round(scale * 15), /obj/item/weapon/gun/shotgun/pump, VENDOR_ITEM_REGULAR), - list("M39 Submachine Gun", round(scale * 30), /obj/item/weapon/gun/smg/m39, VENDOR_ITEM_REGULAR), - list("M41A Pulse Rifle MK2", round(scale * 30), /obj/item/weapon/gun/rifle/m41a, VENDOR_ITEM_RECOMMENDED), - - list("PRIMARY NONLETHAL AMMUNITION", -1, null, null), - list("Box of Beanbag Shells (12g)", round(scale * 15), /obj/item/ammo_magazine/shotgun/beanbag, VENDOR_ITEM_REGULAR), - list("M4RA Rubber Magazine (10x24mm)", round(scale * 15), /obj/item/ammo_magazine/rifle/m4ra/rubber, VENDOR_ITEM_REGULAR), - list("M39 Rubber Magazine (10x20mm)", round(scale * 25), /obj/item/ammo_magazine/smg/m39/rubber, VENDOR_ITEM_REGULAR), - list("M41A Rubber Magazine (10x24mm)", round(scale * 25), /obj/item/ammo_magazine/rifle/rubber, VENDOR_ITEM_REGULAR), - - list("SIDEARMS", -1, null, null), - list("88 Mod 4 Combat Pistol", round(scale * 25), /obj/item/weapon/gun/pistol/mod88, VENDOR_ITEM_REGULAR), - list("M4A3 Service Pistol", round(scale * 25), /obj/item/weapon/gun/pistol/m4a3, VENDOR_ITEM_REGULAR), - - list("SIDEARM NONLETHAL AMMUNITION", -1, null, null), - list("88M4 Rubber Magazine (9mm)", round(scale * 25), /obj/item/ammo_magazine/pistol/mod88/rubber, VENDOR_ITEM_REGULAR), - list("M4A3 Rubber Magazine (9mm)", round(scale * 25), /obj/item/ammo_magazine/pistol/rubber, VENDOR_ITEM_REGULAR), - - list("ATTACHMENTS", -1, null, null), - list("Rail Flashlight", round(scale * 25), /obj/item/attachable/flashlight, VENDOR_ITEM_RECOMMENDED), - list("Underbarrel Flashlight Grip", round(scale * 10), /obj/item/attachable/flashlight/grip, VENDOR_ITEM_RECOMMENDED), - list("Underslung Grenade Launcher", round(scale * 25), /obj/item/attachable/attached_gun/grenade, VENDOR_ITEM_REGULAR), //They already get these as on-spawns, might as well formalize some spares. - - list("UTILITIES", -1, null, null), - list("M07 Training Grenade", round(scale * 15), /obj/item/explosive/grenade/high_explosive/training, VENDOR_ITEM_REGULAR), - list("M15 Rubber Pellet Grenade", round(scale * 10), /obj/item/explosive/grenade/high_explosive/m15/rubber, VENDOR_ITEM_REGULAR), - list("M5 Bayonet", round(scale * 25), /obj/item/attachable/bayonet, VENDOR_ITEM_REGULAR), - list("M94 Marking Flare Pack", round(scale * 10), /obj/item/storage/box/m94, VENDOR_ITEM_RECOMMENDED) - ) - -//------------SQUAD MARINE UNIFORM AND GEAR VENDOR--------------- - -GLOBAL_LIST_INIT(cm_vending_clothing_marine_standard_issue, list( - list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Helmet", 0, /obj/item/clothing/head/helmet/marine, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), - - list("ARMOR (CHOOSE 1)", 0, null, null, null), - list("Medium Armor", 0, /obj/item/clothing/suit/storage/marine/medium, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), - - list("BACKPACK (CHOOSE 1)", 0, null, null, null), - list("Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - - list("BELT (CHOOSE 1)", 0, null, null, null), - list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 Knife Rig (Full)", 0, /obj/item/storage/belt/knifepouch, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - - list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Bayonet Sheath (Full)", 0, /obj/item/storage/pouch/bayonet, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Small Document Pouch", 0, /obj/item/storage/pouch/document/small, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - - list("MASK (CHOOSE 1)", 0, null, null, null), - list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), - list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), - list("Rebreather", 0, /obj/item/clothing/mask/rebreather, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), - - list("RESTRICTED FIREARMS", 0, null, null, null), - list("VP78 Pistol", 15, /obj/item/storage/box/guncase/vp78, null, VENDOR_ITEM_REGULAR), - list("SU-6 Smart Pistol", 15, /obj/item/storage/box/guncase/smartpistol, null, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", 30, /obj/item/storage/box/guncase/lmg, null, VENDOR_ITEM_REGULAR), - list("M79 Grenade Launcher", 30, /obj/item/storage/box/guncase/m79, null, VENDOR_ITEM_REGULAR), - - list("EXPLOSIVES", 0, null, null, null), - list("M40 HEDP High Explosive Packet (x3 grenades)", 20, /obj/item/storage/box/packet/high_explosive, null, VENDOR_ITEM_REGULAR), - list("M40 HIDP Incendiary Packet (x3 grenades)", 20, /obj/item/storage/box/packet/incendiary, null, VENDOR_ITEM_REGULAR), - list("M40 HPDP White Phosphorus Packet (x3 grenades)", 20, /obj/item/storage/box/packet/phosphorus, null, VENDOR_ITEM_REGULAR), - list("M40 HSDP Smoke Packet (x3 grenades)", 10, /obj/item/storage/box/packet/smoke, null, VENDOR_ITEM_REGULAR), - list("M74 AGM-Frag Airburst Packet (x3 airburst grenades)", 15, /obj/item/storage/box/packet/airburst_he, null, VENDOR_ITEM_REGULAR), - list("M74 AGM-Incendiary Airburst Packet (x3 airburst grenades)", 15, /obj/item/storage/box/packet/airburst_incen, null, VENDOR_ITEM_REGULAR), - list("M74 AGM-Smoke Airburst Packet (x3 airburst grenades)", 10, /obj/item/storage/box/packet/airburst_smoke, null, VENDOR_ITEM_REGULAR), - list("M74 AGM-Hornet Airburst Packet (x3 airburst grenades", 15, /obj/item/storage/box/packet/hornet, null, VENDOR_ITEM_REGULAR), - list("M20 Mine Box (x4 mines)", 20, /obj/item/storage/box/explosive_mines, null, VENDOR_ITEM_REGULAR), - - list("AMMUNITION", 0, null, null, null), - list("L42A AP Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/l42a/ap, null, VENDOR_ITEM_REGULAR), - list("M39 AP Magazine (10x20mm)", 10, /obj/item/ammo_magazine/smg/m39/ap , null, VENDOR_ITEM_REGULAR), - list("M39 Extended Magazine (10x20mm)", 10, /obj/item/ammo_magazine/smg/m39/extended , null, VENDOR_ITEM_REGULAR), - list("M41A AP Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/ap , null, VENDOR_ITEM_REGULAR), - list("M41A Extended Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/extended , null, VENDOR_ITEM_REGULAR), - list("M44 Heavy Speed Loader (.44)", 10, /obj/item/ammo_magazine/revolver/heavy, null, VENDOR_ITEM_REGULAR), - - list("UTILITIES", 0, null, null, null), - list("Webbing", 10, /obj/item/clothing/accessory/storage/webbing, null, VENDOR_ITEM_REGULAR), - list("Brown Webbing Vest", 15, /obj/item/clothing/accessory/storage/black_vest/brown_vest, null, VENDOR_ITEM_REGULAR), - list("Black Webbing Vest", 15, /obj/item/clothing/accessory/storage/black_vest, null, VENDOR_ITEM_REGULAR), - list("SensorMate Medical HUD", 15, /obj/item/clothing/glasses/hud/sensor, null, VENDOR_ITEM_REGULAR), - list("Roller Bed", 5, /obj/item/roller, null, VENDOR_ITEM_REGULAR), - list("Fulton Device Stack", 5, /obj/item/stack/fulton, null, VENDOR_ITEM_REGULAR), - list("B12 Pattern Marine Armor", 30, /obj/item/clothing/suit/storage/marine/leader, null, VENDOR_ITEM_REGULAR), - list("Range Finder", 10, /obj/item/device/binoculars/range, null, VENDOR_ITEM_REGULAR), - list("Laser Designator", 15, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_REGULAR), - list("Large General Pouch", 15, /obj/item/storage/pouch/general/large, null, VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 15, /obj/item/storage/pouch/magazine/large, null, VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", 5, /obj/item/storage/pouch/flamertank, null, VENDOR_ITEM_REGULAR), - list("Shoulder Holster", 15, /obj/item/clothing/accessory/storage/holster, null, VENDOR_ITEM_REGULAR), - list("Machete Scabbard (Full)", 15, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR), - list("Machete Pouch (Full)", 15, /obj/item/storage/pouch/machete/full, null, VENDOR_ITEM_REGULAR), - list("Fire Extinguisher (Portable)", 5, /obj/item/tool/extinguisher/mini, null, VENDOR_ITEM_REGULAR), - list("Motion Detector", 15, /obj/item/device/motiondetector, null, VENDOR_ITEM_REGULAR), - list("Data Detector", 15, /obj/item/device/motiondetector/intel, null, VENDOR_ITEM_REGULAR), - list("Whistle", 5, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), - list("Welding Goggles", 5, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_REGULAR), - list("JTAC Pamphlet", 15, /obj/item/pamphlet/skill/jtac, null, VENDOR_ITEM_REGULAR), - list("Engineering Pamphlet", 15, /obj/item/pamphlet/skill/engineer, null, VENDOR_ITEM_REGULAR), - list("Powerloader Certification", 45, /obj/item/pamphlet/skill/powerloader, null, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 10, /obj/item/storage/pouch/shotgun/large, null, VENDOR_ITEM_REGULAR), - - list("RADIO KEYS", 0, null, null, null), - list("Engineering Radio Encryption Key", 5, /obj/item/device/encryptionkey/engi, null, VENDOR_ITEM_REGULAR), - list("Intel Radio Encryption Key", 5, /obj/item/device/encryptionkey/intel, null, VENDOR_ITEM_REGULAR), - list("JTAC Radio Encryption Key", 5, /obj/item/device/encryptionkey/jtac, null, VENDOR_ITEM_REGULAR), - list("Supply Radio Encryption Key", 5, /obj/item/device/encryptionkey/req, null, VENDOR_ITEM_REGULAR), -)) - -GLOBAL_LIST_INIT(cm_vending_clothing_marine, list( - list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Helmet", 0, /obj/item/clothing/head/helmet/marine, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), - - list("ARMOR (CHOOSE 1)", 0, null, null, null), - list("Light Armor", 0, /obj/item/clothing/suit/storage/marine/light, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), - list("Medium Armor", 0, /obj/item/clothing/suit/storage/marine/medium, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), - list("Heavy Armor", 0, /obj/item/clothing/suit/storage/marine/heavy, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), - - list("BACKPACK (CHOOSE 1)", 0, null, null, null), - list("Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), - list("Shotgun Scabbard", 0, /obj/item/storage/large_holster/m37, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - - list("BELT (CHOOSE 1)", 0, null, null, null), - list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 Knife Rig (Full)", 0, /obj/item/storage/belt/knifepouch, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M40 Grenade Rig (Empty)", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - - list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Bayonet Sheath (Full)", 0, /obj/item/storage/pouch/bayonet, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Small Document Pouch", 0, /obj/item/storage/pouch/document/small, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - - list("MASK (CHOOSE 1)", 0, null, null, null), - list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), - list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), - list("Rebreather", 0, /obj/item/clothing/mask/rebreather, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), - - list("RESTRICTED FIREARMS", 0, null, null, null), - list("VP78 Pistol", 15, /obj/item/storage/box/guncase/vp78, null, VENDOR_ITEM_REGULAR), - list("SU-6 Smart Pistol", 15, /obj/item/storage/box/guncase/smartpistol, null, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", 30, /obj/item/storage/box/guncase/lmg, null, VENDOR_ITEM_REGULAR), - list("M79 Grenade Launcher", 30, /obj/item/storage/box/guncase/m79, null, VENDOR_ITEM_REGULAR), - - list("EXPLOSIVES", 0, null, null, null), - list("M40 HEDP High Explosive Packet (x3 grenades)", 20, /obj/item/storage/box/packet/high_explosive, null, VENDOR_ITEM_REGULAR), - list("M40 HIDP Incendiary Packet (x3 grenades)", 20, /obj/item/storage/box/packet/incendiary, null, VENDOR_ITEM_REGULAR), - list("M40 HPDP White Phosphorus Packet (x3 grenades)", 20, /obj/item/storage/box/packet/phosphorus, null, VENDOR_ITEM_REGULAR), - list("M40 HSDP Smoke Packet (x3 grenades)", 10, /obj/item/storage/box/packet/smoke, null, VENDOR_ITEM_REGULAR), - list("M74 AGM-Frag Airburst Packet (x3 airburst grenades)", 15, /obj/item/storage/box/packet/airburst_he, null, VENDOR_ITEM_REGULAR), - list("M74 AGM-Incendiary Airburst Packet (x3 airburst grenades)", 15, /obj/item/storage/box/packet/airburst_incen, null, VENDOR_ITEM_REGULAR), - list("M74 AGM-Smoke Airburst Packet (x3 airburst grenades)", 10, /obj/item/storage/box/packet/airburst_smoke, null, VENDOR_ITEM_REGULAR), - list("M74 AGM-Hornet Airburst Packet (x3 airburst grenades", 15, /obj/item/storage/box/packet/hornet, null, VENDOR_ITEM_REGULAR), - list("M20 Mine Box (x4 mines)", 20, /obj/item/storage/box/explosive_mines, null, VENDOR_ITEM_REGULAR), - - list("AMMUNITION", 0, null, null, null), - list("M4RA AP Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/m4ra/ap, null, VENDOR_ITEM_REGULAR), - list("M39 AP Magazine (10x20mm)", 10, /obj/item/ammo_magazine/smg/m39/ap , null, VENDOR_ITEM_REGULAR), - list("M39 Extended Magazine (10x20mm)", 10, /obj/item/ammo_magazine/smg/m39/extended , null, VENDOR_ITEM_REGULAR), - list("M41A AP Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/ap , null, VENDOR_ITEM_REGULAR), - list("M41A Extended Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/extended , null, VENDOR_ITEM_REGULAR), - list("M44 Heavy Speed Loader (.44)", 10, /obj/item/ammo_magazine/revolver/heavy, null, VENDOR_ITEM_REGULAR), - - list("UTILITIES", 0, null, null, null), - list("Webbing", 10, /obj/item/clothing/accessory/storage/webbing, null, VENDOR_ITEM_REGULAR), - list("Brown Webbing Vest", 15, /obj/item/clothing/accessory/storage/black_vest/brown_vest, null, VENDOR_ITEM_REGULAR), - list("Black Webbing Vest", 15, /obj/item/clothing/accessory/storage/black_vest, null, VENDOR_ITEM_REGULAR), - list("SensorMate Medical HUD", 15, /obj/item/clothing/glasses/hud/sensor, null, VENDOR_ITEM_REGULAR), - list("Roller Bed", 5, /obj/item/roller, null, VENDOR_ITEM_REGULAR), - list("Fulton Device Stack", 5, /obj/item/stack/fulton, null, VENDOR_ITEM_REGULAR), - list("B12 Pattern Marine Armor", 30, /obj/item/clothing/suit/storage/marine/leader, null, VENDOR_ITEM_REGULAR), - list("Range Finder", 10, /obj/item/device/binoculars/range, null, VENDOR_ITEM_REGULAR), - list("Laser Designator", 15, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_REGULAR), - list("Large General Pouch", 15, /obj/item/storage/pouch/general/large, null, VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 15, /obj/item/storage/pouch/magazine/large, null, VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", 5, /obj/item/storage/pouch/flamertank, null, VENDOR_ITEM_REGULAR), - list("Shoulder Holster", 15, /obj/item/clothing/accessory/storage/holster, null, VENDOR_ITEM_REGULAR), - list("Machete Scabbard (Full)", 15, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR), - list("Machete Pouch (Full)", 15, /obj/item/storage/pouch/machete/full, null, VENDOR_ITEM_REGULAR), - list("Fire Extinguisher (Portable)", 5, /obj/item/tool/extinguisher/mini, null, VENDOR_ITEM_REGULAR), - list("Motion Detector", 15, /obj/item/device/motiondetector, null, VENDOR_ITEM_REGULAR), - list("Data Detector", 15, /obj/item/device/motiondetector/intel, null, VENDOR_ITEM_REGULAR), - list("Whistle", 5, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), - list("Welding Goggles", 5, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_REGULAR), - list("JTAC Pamphlet", 15, /obj/item/pamphlet/skill/jtac, null, VENDOR_ITEM_REGULAR), - list("Engineering Pamphlet", 15, /obj/item/pamphlet/skill/engineer, null, VENDOR_ITEM_REGULAR), - list("Powerloader Certification", 45, /obj/item/pamphlet/skill/powerloader, null, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 10, /obj/item/storage/pouch/shotgun/large, null, VENDOR_ITEM_REGULAR), - - list("RADIO KEYS", 0, null, null, null), - list("Engineering Radio Encryption Key", 5, /obj/item/device/encryptionkey/engi, null, VENDOR_ITEM_REGULAR), - list("Intel Radio Encryption Key", 5, /obj/item/device/encryptionkey/intel, null, VENDOR_ITEM_REGULAR), - list("JTAC Radio Encryption Key", 5, /obj/item/device/encryptionkey/jtac, null, VENDOR_ITEM_REGULAR), - list("Supply Radio Encryption Key", 5, /obj/item/device/encryptionkey/req, null, VENDOR_ITEM_REGULAR), - )) - -/obj/structure/machinery/cm_vending/clothing/marine - name = "\improper ColMarTech Automated Marine Equipment Rack" - desc = "An automated rack hooked up to a colossal storage of Marine Rifleman standard-issue equipment." - icon_state = "mar_rack" - show_points = TRUE - vendor_theme = VENDOR_THEME_USCM - - vendor_role = list(JOB_SQUAD_MARINE) - -/obj/structure/machinery/cm_vending/clothing/marine/get_listed_products(mob/user) - if(HAS_TRAIT(SSround, TRAIT_ROUND_STANDARD_ISSUE)) - return GLOB.cm_vending_clothing_marine_standard_issue - return GLOB.cm_vending_clothing_marine - -/obj/structure/machinery/cm_vending/clothing/marine/alpha - squad_tag = SQUAD_MARINE_1 - req_access = list(ACCESS_MARINE_ALPHA) - headset_type = /obj/item/device/radio/headset/almayer/marine/alpha - -/obj/structure/machinery/cm_vending/clothing/marine/bravo - squad_tag = SQUAD_MARINE_2 - req_access = list(ACCESS_MARINE_BRAVO) - headset_type = /obj/item/device/radio/headset/almayer/marine/bravo - -/obj/structure/machinery/cm_vending/clothing/marine/charlie - squad_tag = SQUAD_MARINE_3 - req_access = list(ACCESS_MARINE_CHARLIE) - headset_type = /obj/item/device/radio/headset/almayer/marine/charlie - -/obj/structure/machinery/cm_vending/clothing/marine/delta - squad_tag = SQUAD_MARINE_4 - req_access = list(ACCESS_MARINE_DELTA) - headset_type = /obj/item/device/radio/headset/almayer/marine/delta - //------------SQUAD PREP UNIFORM VENDOR--------------- + /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep name = "\improper ColMarTech Surplus Uniform Vendor" desc = "An automated supply rack hooked up to a small storage of standard marine uniforms." @@ -369,85 +95,106 @@ GLOBAL_LIST_INIT(cm_vending_clothing_marine, list( /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/populate_product_list(scale) listed_products = list( - list("UNIFORM & STORAGE", -1, null, null), - list("Lightweight IMP Backpack", 10, /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), - list("Marine Radio Headset", 10, /obj/item/device/radio/headset/almayer, VENDOR_ITEM_REGULAR), - list("Marine Combat Gloves", 10, /obj/item/clothing/gloves/marine, VENDOR_ITEM_REGULAR), - list("Marine Black Combat Gloves", 10, /obj/item/clothing/gloves/marine/black, VENDOR_ITEM_REGULAR), - list("Marine Combat Boots", 20, /obj/item/clothing/shoes/marine, VENDOR_ITEM_REGULAR), - list("Shotgun Scabbard", 5, /obj/item/storage/large_holster/m37, VENDOR_ITEM_REGULAR), - list("USCM Satchel", 10, /obj/item/storage/backpack/marine/satchel, VENDOR_ITEM_REGULAR), - list("USCM Technical Satchel", 10, /obj/item/storage/backpack/marine/satchel/tech, VENDOR_ITEM_REGULAR), - list("USCM Uniform", 20, /obj/item/clothing/under/marine, VENDOR_ITEM_REGULAR), - - list("BELTS", -1, null, null), - list("M276 Pattern Ammo Load Rig", 10, /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern M40 Grenade Rig", 8, /obj/item/storage/belt/grenade, VENDOR_ITEM_REGULAR), - list("M276 Pattern Shotgun Shell Loading Rig", 10, /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), - list("M276 Pattern General Pistol Holster Rig", 10, /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 Pattern M39 Holster Rig", 10, /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), - list("M276 Pattern M44 Holster Rig", 10, /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), - list("M276 Pattern M82F Holster Rig", 5, /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), + list("STANDARD EQUIPMENT", -1, null, null, null), + list("Marine Combat Boots", round(scale * 15), /obj/item/clothing/shoes/marine, VENDOR_ITEM_REGULAR), + list("USCM Uniform", round(scale * 15), /obj/item/clothing/under/marine, VENDOR_ITEM_REGULAR), + list("Marine Combat Gloves", round(scale * 15), /obj/item/clothing/gloves/marine, VENDOR_ITEM_REGULAR), + list("Marine Black Combat Gloves", round(scale * 15), /obj/item/clothing/gloves/marine/black, VENDOR_ITEM_REGULAR), + list("Marine Radio Headset", round(scale * 15), /obj/item/device/radio/headset/almayer, VENDOR_ITEM_REGULAR), + list("M10 Pattern Marine Helmet", round(scale * 15), /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), + + list("WEBBINGS", -1, null, null), + list("Brown Webbing Vest", round(scale * 1.25), /obj/item/clothing/accessory/storage/black_vest/brown_vest, VENDOR_ITEM_REGULAR), + list("Black Webbing Vest", round(scale * 0.5), /obj/item/clothing/accessory/storage/black_vest, VENDOR_ITEM_REGULAR), + list("Webbing", round(scale * 2), /obj/item/clothing/accessory/storage/webbing, VENDOR_ITEM_REGULAR), + list("Drop Pouch", round(scale * 0.5), /obj/item/clothing/accessory/storage/droppouch, VENDOR_ITEM_REGULAR), + list("Shoulder Holster", round(scale * 0.5), /obj/item/clothing/accessory/storage/holster, VENDOR_ITEM_REGULAR), list("ARMOR", -1, null, null), - list("M10 Pattern Marine Helmet", 20, /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), - list("M3 Pattern Carrier Marine Armor", 20, /obj/item/clothing/suit/storage/marine/carrier, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padded Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padded, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padless Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless, VENDOR_ITEM_REGULAR), - list("M3 Pattern Ridged Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless_lines, VENDOR_ITEM_REGULAR), - list("M3 Pattern Skull Marine Armor", 20, /obj/item/clothing/suit/storage/marine/skull, VENDOR_ITEM_REGULAR), - list("M3 Pattern Smooth Marine Armor", 20, /obj/item/clothing/suit/storage/marine/smooth, VENDOR_ITEM_REGULAR), - list("M3-EOD Pattern Heavy Armor", 10, /obj/item/clothing/suit/storage/marine/heavy, VENDOR_ITEM_REGULAR), - list("M3-L Pattern Light Armor", 10, /obj/item/clothing/suit/storage/marine/light, VENDOR_ITEM_REGULAR), + list("M3 Pattern Carrier Marine Armor", round(scale * 15), /obj/item/clothing/suit/storage/marine/carrier, VENDOR_ITEM_REGULAR), + list("M3 Pattern Padded Marine Armor", round(scale * 15), /obj/item/clothing/suit/storage/marine/padded, VENDOR_ITEM_REGULAR), + list("M3 Pattern Padless Marine Armor", round(scale * 15), /obj/item/clothing/suit/storage/marine/padless, VENDOR_ITEM_REGULAR), + list("M3 Pattern Ridged Marine Armor", round(scale * 15), /obj/item/clothing/suit/storage/marine/padless_lines, VENDOR_ITEM_REGULAR), + list("M3 Pattern Skull Marine Armor", round(scale * 15), /obj/item/clothing/suit/storage/marine/skull, VENDOR_ITEM_REGULAR), + list("M3 Pattern Smooth Marine Armor", round(scale * 15), /obj/item/clothing/suit/storage/marine/smooth, VENDOR_ITEM_REGULAR), + list("M3-EOD Pattern Heavy Armor", round(scale * 10), /obj/item/clothing/suit/storage/marine/heavy, VENDOR_ITEM_REGULAR), + list("M3-L Pattern Light Armor", round(scale * 10), /obj/item/clothing/suit/storage/marine/light, VENDOR_ITEM_REGULAR), + + list("BACKPACK", -1, null, null, null), + list("Lightweight IMP Backpack", round(scale * 15), /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), + list("Technician Backpack", round(scale * 15), /obj/item/storage/backpack/marine/tech, VENDOR_ITEM_REGULAR), + list("Medical Backpack", round(scale * 15), /obj/item/storage/backpack/marine/medic, VENDOR_ITEM_REGULAR), + list("USCM Satchel", round(scale * 15), /obj/item/storage/backpack/marine/satchel, VENDOR_ITEM_REGULAR), + list("USCM Technical Satchel", round(scale * 15), /obj/item/storage/backpack/marine/satchel/tech, VENDOR_ITEM_REGULAR), + list("USCM Technical Chestrig", round(scale * 15), /obj/item/storage/backpack/marine/engineerpack/welder_chestrig, VENDOR_ITEM_REGULAR), + list("Medical Satchel", round(scale * 15), /obj/item/storage/backpack/marine/satchel/medic, VENDOR_ITEM_REGULAR), + list("Shotgun Scabbard", round(scale * 5), /obj/item/storage/large_holster/m37, VENDOR_ITEM_REGULAR), + + list("RESTRICTED BACKPACKS", -1, null, null), + list("USCM Technician Welderpack", round(scale * 1.25), /obj/item/storage/backpack/marine/engineerpack, VENDOR_ITEM_REGULAR), + list("Technician Welder-Satchel", round(scale * 2), /obj/item/storage/backpack/marine/engineerpack/satchel, VENDOR_ITEM_REGULAR), + list("Radio Telephone Backpack", round(scale * 0.5), /obj/item/storage/backpack/marine/satchel/rto, VENDOR_ITEM_REGULAR), + + list("BELTS", -1, null, null), + list("M276 Pattern Ammo Load Rig", round(scale * 15), /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), + list("M276 Pattern M40 Grenade Rig", round(scale * 10), /obj/item/storage/belt/grenade, VENDOR_ITEM_REGULAR), + list("M276 Pattern Shotgun Shell Loading Rig", round(scale * 15), /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), + list("M276 Pattern General Pistol Holster Rig", round(scale * 15), /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), + list("M276 Pattern M39 Holster Rig", round(scale * 15), /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), + list("M276 Pattern M39 Holster Rig And Pouch", round(scale * 10), /obj/item/storage/belt/gun/m39, VENDOR_ITEM_REGULAR), + list("M276 Pattern M44 Holster Rig", round(scale * 15), /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), + list("M276 Pattern M82F Holster Rig", round(scale * 5), /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), + list("M276 Knife Rig (Full)", round(scale * 15), /obj/item/storage/belt/knifepouch, VENDOR_ITEM_REGULAR), + list("M276 G8-A General Utility Pouch", round(scale * 15), /obj/item/storage/backpack/general_belt, VENDOR_ITEM_REGULAR), + + list("POUCHES", -1, null, null, null), + list("Bayonet Sheath (Full)",round(scale * 15), /obj/item/storage/pouch/bayonet, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", round(scale * 15), /obj/item/storage/pouch/firstaid/full/alternate, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", round(scale * 15), /obj/item/storage/pouch/firstaid/full/pills, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", round(scale * 15), /obj/item/storage/pouch/flare/full, VENDOR_ITEM_REGULAR), + list("Small Document Pouch", round(scale * 15), /obj/item/storage/pouch/document/small, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", round(scale * 15), /obj/item/storage/pouch/magazine, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", round(scale * 15), /obj/item/storage/pouch/shotgun, VENDOR_ITEM_REGULAR), + list("Medium General Pouch", round(scale * 15), /obj/item/storage/pouch/general/medium, VENDOR_ITEM_REGULAR), + list("Pistol Magazine Pouch", round(scale * 15), /obj/item/storage/pouch/magazine/pistol, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", round(scale * 15), /obj/item/storage/pouch/pistol, VENDOR_ITEM_REGULAR), + + list("RESTRICTED POUCHES", -1, null, null, null), + list("Construction Pouch", round(scale * 1.25), /obj/item/storage/pouch/construction, VENDOR_ITEM_REGULAR), + list("Explosive Pouch", round(scale * 1.25), /obj/item/storage/pouch/explosive, VENDOR_ITEM_REGULAR), + list("First Responder Pouch (Empty)", round(scale * 2.5), /obj/item/storage/pouch/first_responder, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", round(scale * 2), /obj/item/storage/pouch/magazine/pistol/large, VENDOR_ITEM_REGULAR), + list("Tools Pouch", round(scale * 1.25), /obj/item/storage/pouch/tools, VENDOR_ITEM_REGULAR), + list("Sling Pouch", round(scale * 1.25), /obj/item/storage/pouch/sling, VENDOR_ITEM_REGULAR), + + list("MASK", -1, null, null, null), + list("Gas Mask", round(scale * 15), /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR), + list("Heat Absorbent Coif", round(scale * 10), /obj/item/clothing/mask/rebreather/scarf, VENDOR_ITEM_REGULAR), + list("Rebreather", round(scale * 10), /obj/item/clothing/mask/rebreather, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), list("MISCELLANEOUS", -1, null, null, null), - list("Gas Mask", 20, /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR), - list("Heat Absorbent Coif", 10, /obj/item/clothing/mask/rebreather/scarf, VENDOR_ITEM_REGULAR), - list("M5 Integrated Gas Mask", 10, /obj/item/prop/helmetgarb/helmet_gasmask, VENDOR_ITEM_REGULAR), - list("M10 Helmet Netting", 10, /obj/item/prop/helmetgarb/netting, VENDOR_ITEM_REGULAR), - list("M10 Helmet Rain Cover", 10, /obj/item/prop/helmetgarb/raincover, VENDOR_ITEM_REGULAR), - list("Firearm Lubricant", 20, /obj/item/prop/helmetgarb/gunoil, VENDOR_ITEM_REGULAR), - list("USCM Flair", 20, /obj/item/prop/helmetgarb/flair_uscm, VENDOR_ITEM_REGULAR), + list("Ballistic goggles", round(scale * 10), /obj/item/clothing/glasses/mgoggles, VENDOR_ITEM_REGULAR), + list("Prescription ballistic goggles", round(scale * 10), /obj/item/clothing/glasses/mgoggles/prescription, VENDOR_ITEM_REGULAR), + list("Marine RPG glasses", round(scale * 10), /obj/item/clothing/glasses/regular, VENDOR_ITEM_REGULAR), + list("M5 Integrated Gas Mask", round(scale * 10), /obj/item/prop/helmetgarb/helmet_gasmask, VENDOR_ITEM_REGULAR), + list("M10 Helmet Netting", round(scale * 10), /obj/item/prop/helmetgarb/netting, VENDOR_ITEM_REGULAR), + list("M10 Helmet Rain Cover", round(scale * 10), /obj/item/prop/helmetgarb/raincover, VENDOR_ITEM_REGULAR), + list("Firearm Lubricant", round(scale * 15), /obj/item/prop/helmetgarb/gunoil, VENDOR_ITEM_REGULAR), + list("USCM Flair", round(scale * 15), /obj/item/prop/helmetgarb/flair_uscm, VENDOR_ITEM_REGULAR), ) //--------------SQUAD SPECIFIC VERSIONS-------------- +//Those vendors aren't being used i will make them us the main vendor a parent to avoid having four different +// list with just the headset changed. /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/alpha req_access = list(ACCESS_MARINE_PREP) req_one_access = list(ACCESS_MARINE_ALPHA, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/alpha/populate_product_list(scale) - listed_products = list( - list("UNIFORM", -1, null, null), - list("Lightweight IMP Backpack", 10, /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern Ammo Load Rig", 10, /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern General Pistol Holster Rig", 10, /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 Pattern M39 Holster Rig", 10, /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), - list("M276 Pattern M44 Holster Rig", 10, /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), - list("M276 M82F Holster Rig", 5, /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), - list("M276 Pattern Shotgun Shell Loading Rig", 10, /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), + listed_products += list( + list("HEADSET", -1, null, null), list("Marine Alpha Radio Headset", 10, /obj/item/device/radio/headset/almayer/marine/alpha, VENDOR_ITEM_REGULAR), - list("Marine Combat Gloves", 10, /obj/item/clothing/gloves/marine, VENDOR_ITEM_REGULAR), - list("Marine Black Combat Gloves", 10, /obj/item/clothing/gloves/marine/black, VENDOR_ITEM_REGULAR), - list("Marine Combat Boots", 20, /obj/item/clothing/shoes/marine, VENDOR_ITEM_REGULAR), - list("Shotgun Scabbard", 5, /obj/item/storage/large_holster/m37, VENDOR_ITEM_REGULAR), - list("USCM Satchel", 10, /obj/item/storage/backpack/marine/satchel, VENDOR_ITEM_REGULAR), - list("USCM Uniform", 20, /obj/item/clothing/under/marine, VENDOR_ITEM_REGULAR), - - list("ARMOR", -1, null, null), - list("M10 Pattern Marine Helmet", 20, /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), - list("M3 Pattern Carrier Marine Armor", 20, /obj/item/clothing/suit/storage/marine/carrier, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padded Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padded, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padless Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless, VENDOR_ITEM_REGULAR), - list("M3 Pattern Ridged Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless_lines, VENDOR_ITEM_REGULAR), - list("M3 Pattern Skull Marine Armor", 20, /obj/item/clothing/suit/storage/marine/skull, VENDOR_ITEM_REGULAR), - list("M3 Pattern Smooth Marine Armor", 20, /obj/item/clothing/suit/storage/marine/smooth, VENDOR_ITEM_REGULAR), - list("M3-EOD Pattern Heavy Armor", 10, /obj/item/clothing/suit/storage/marine/heavy, VENDOR_ITEM_REGULAR), - list("M3-L Pattern Light Armor", 10, /obj/item/clothing/suit/storage/marine/light, VENDOR_ITEM_REGULAR), - - list("MASKS", -1, null, null, null), - list("Gas Mask", 20, /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR), - list("Heat Absorbent Coif", 10, /obj/item/clothing/mask/rebreather/scarf, VENDOR_ITEM_REGULAR), ) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/bravo @@ -455,37 +202,9 @@ GLOBAL_LIST_INIT(cm_vending_clothing_marine, list( req_one_access = list(ACCESS_MARINE_BRAVO, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/bravo/populate_product_list(scale) - listed_products = list( - list("UNIFORM", -1, null, null), - list("Lightweight IMP Backpack", 10, /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern Ammo Load Rig", 10, /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern General Pistol Holster Rig", 10, /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 Pattern M39 Holster Rig", 10, /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), - list("M276 Pattern M44 Holster Rig", 10, /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), - list("M276 M82F Holster Rig", 5, /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), - list("M276 Pattern Shotgun Shell Loading Rig", 10, /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), + listed_products += list( + list("HEADSET", -1, null, null), list("Marine Bravo Radio Headset", 10, /obj/item/device/radio/headset/almayer/marine/bravo, VENDOR_ITEM_REGULAR), - list("Marine Combat Gloves", 10, /obj/item/clothing/gloves/marine, VENDOR_ITEM_REGULAR), - list("Marine Black Combat Gloves", 10, /obj/item/clothing/gloves/marine/black, VENDOR_ITEM_REGULAR), - list("Marine Combat Boots", 20, /obj/item/clothing/shoes/marine, VENDOR_ITEM_REGULAR), - list("Shotgun Scabbard", 5, /obj/item/storage/large_holster/m37, VENDOR_ITEM_REGULAR), - list("USCM Satchel", 10, /obj/item/storage/backpack/marine/satchel, VENDOR_ITEM_REGULAR), - list("USCM Uniform", 20, /obj/item/clothing/under/marine, VENDOR_ITEM_REGULAR), - - list("ARMOR", -1, null, null), - list("M10 Pattern Marine Helmet", 20, /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), - list("M3 Pattern Carrier Marine Armor", 20, /obj/item/clothing/suit/storage/marine/carrier, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padded Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padded, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padless Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless, VENDOR_ITEM_REGULAR), - list("M3 Pattern Ridged Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless_lines, VENDOR_ITEM_REGULAR), - list("M3 Pattern Skull Marine Armor", 20, /obj/item/clothing/suit/storage/marine/skull, VENDOR_ITEM_REGULAR), - list("M3 Pattern Smooth Marine Armor", 20, /obj/item/clothing/suit/storage/marine/smooth, VENDOR_ITEM_REGULAR), - list("M3-EOD Pattern Heavy Armor", 10, /obj/item/clothing/suit/storage/marine/heavy, VENDOR_ITEM_REGULAR), - list("M3-L Pattern Light Armor", 10, /obj/item/clothing/suit/storage/marine/light, VENDOR_ITEM_REGULAR), - - list("MASKS", -1, null, null, null), - list("Gas Mask", 20, /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR), - list("Heat Absorbent Coif", 10, /obj/item/clothing/mask/rebreather/scarf, VENDOR_ITEM_REGULAR), ) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/charlie @@ -493,37 +212,9 @@ GLOBAL_LIST_INIT(cm_vending_clothing_marine, list( req_one_access = list(ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/charlie/populate_product_list(scale) - listed_products = list( - list("UNIFORM", -1, null, null), - list("Lightweight IMP Backpack", 10, /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern Ammo Load Rig", 10, /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern General Pistol Holster Rig", 10, /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 Pattern M39 Holster Rig", 10, /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), - list("M276 Pattern M44 Holster Rig", 10, /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), - list("M276 M82F Holster Rig", 5, /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), - list("M276 Pattern Shotgun Shell Loading Rig", 10, /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), + listed_products += list( + list("HEADSET", -1, null, null), list("Marine Charlie Radio Headset", 10, /obj/item/device/radio/headset/almayer/marine/charlie, VENDOR_ITEM_REGULAR), - list("Marine Combat Gloves", 10, /obj/item/clothing/gloves/marine, VENDOR_ITEM_REGULAR), - list("Marine Black Combat Gloves", 10, /obj/item/clothing/gloves/marine/black, VENDOR_ITEM_REGULAR), - list("Marine Combat Boots", 20, /obj/item/clothing/shoes/marine, VENDOR_ITEM_REGULAR), - list("Shotgun Scabbard", 5, /obj/item/storage/large_holster/m37, VENDOR_ITEM_REGULAR), - list("USCM Satchel", 10, /obj/item/storage/backpack/marine/satchel, VENDOR_ITEM_REGULAR), - list("USCM Uniform", 20, /obj/item/clothing/under/marine, VENDOR_ITEM_REGULAR), - - list("ARMOR", -1, null, null), - list("M10 Pattern Marine Helmet", 20, /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), - list("M3 Pattern Carrier Marine Armor", 20, /obj/item/clothing/suit/storage/marine/carrier, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padded Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padded, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padless Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless, VENDOR_ITEM_REGULAR), - list("M3 Pattern Ridged Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless_lines, VENDOR_ITEM_REGULAR), - list("M3 Pattern Skull Marine Armor", 20, /obj/item/clothing/suit/storage/marine/skull, VENDOR_ITEM_REGULAR), - list("M3 Pattern Smooth Marine Armor", 20, /obj/item/clothing/suit/storage/marine/smooth, VENDOR_ITEM_REGULAR), - list("M3-EOD Pattern Heavy Armor", 10, /obj/item/clothing/suit/storage/marine/heavy, VENDOR_ITEM_REGULAR), - list("M3-L Pattern Light Armor", 10, /obj/item/clothing/suit/storage/marine/light, VENDOR_ITEM_REGULAR), - - list("MASKS", -1, null, null, null), - list("Gas Mask", 20, /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR), - list("Heat Absorbent Coif", 10, /obj/item/clothing/mask/rebreather/scarf, VENDOR_ITEM_REGULAR), ) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/delta @@ -531,36 +222,169 @@ GLOBAL_LIST_INIT(cm_vending_clothing_marine, list( req_one_access = list(ACCESS_MARINE_DELTA, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/delta/populate_product_list(scale) - listed_products = list( - list("UNIFORM", -1, null, null), - list("Lightweight IMP Backpack", 10, /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern Ammo Load Rig", 10, /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern General Pistol Holster Rig", 10, /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 Pattern M39 Holster Rig", 10, /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), - list("M276 Pattern M44 Holster Rig", 10, /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), - list("M276 M82F Holster Rig", 5, /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), - list("M276 Pattern Shotgun Shell Loading Rig", 10, /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), - list("M276 Knife Rig", 5, /obj/item/storage/belt/knifepouch, VENDOR_ITEM_REGULAR), + listed_products += list( + list("HEADSET", -1, null, null), list("Marine Delta Radio Headset", 10, /obj/item/device/radio/headset/almayer/marine/delta, VENDOR_ITEM_REGULAR), - list("Marine Combat Gloves", 10, /obj/item/clothing/gloves/marine, VENDOR_ITEM_REGULAR), - list("Marine Black Combat Gloves", 10, /obj/item/clothing/gloves/marine/black, VENDOR_ITEM_REGULAR), - list("Marine Combat Boots", 20, /obj/item/clothing/shoes/marine, VENDOR_ITEM_REGULAR), - list("Shotgun Scabbard", 5, /obj/item/storage/large_holster/m37, VENDOR_ITEM_REGULAR), - list("USCM Satchel", 10, /obj/item/storage/backpack/marine/satchel, VENDOR_ITEM_REGULAR), - list("USCM Uniform", 20, /obj/item/clothing/under/marine, VENDOR_ITEM_REGULAR), + ) - list("ARMOR", -1, null, null), - list("M10 Pattern Marine Helmet", 20, /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), - list("M3 Pattern Carrier Marine Armor", 20, /obj/item/clothing/suit/storage/marine/carrier, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padded Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padded, VENDOR_ITEM_REGULAR), - list("M3 Pattern Padless Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless, VENDOR_ITEM_REGULAR), - list("M3 Pattern Ridged Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless_lines, VENDOR_ITEM_REGULAR), - list("M3 Pattern Skull Marine Armor", 20, /obj/item/clothing/suit/storage/marine/skull, VENDOR_ITEM_REGULAR), - list("M3 Pattern Smooth Marine Armor", 20, /obj/item/clothing/suit/storage/marine/smooth, VENDOR_ITEM_REGULAR), - list("M3-EOD Pattern Heavy Armor", 10, /obj/item/clothing/suit/storage/marine/heavy, VENDOR_ITEM_REGULAR), - list("M3-L Pattern Light Armor", 10, /obj/item/clothing/suit/storage/marine/light, VENDOR_ITEM_REGULAR), - - list("MASKS", -1, null, null, null), - list("Gas Mask", 20, /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR), - list("Heat Absorbent Coif", 10, /obj/item/clothing/mask/rebreather/scarf, VENDOR_ITEM_REGULAR), +//--------------SQUAD MUNITION VENDOR-------------- + +/obj/structure/machinery/cm_vending/sorted/cargo_ammo/squad + name = "\improper ColMarTech Automated Munition Squad Vendor" + desc = "An automated supply rack hooked up to a small storage of various ammunition types. Can be accessed by any Marine Rifleman." + req_access = list(ACCESS_MARINE_ALPHA) + req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_SPECPREP, ACCESS_MARINE_RO) + hackable = TRUE + vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_TO_HAND + + vend_x_offset = 2 + +/obj/structure/machinery/cm_vending/sorted/cargo_ammo/squad/ui_state(mob/user) + return GLOB.not_incapacitated_and_adjacent_strict_state + + +/obj/structure/machinery/cm_vending/sorted/cargo_ammo/squad/populate_product_list(scale) + listed_products = list( + list("ARMOR-PIERCING AMMUNITION", -1, null, null), + list("M4RA AP Magazine (10x24mm)", round(scale * 3.5), /obj/item/ammo_magazine/rifle/m4ra/ap, VENDOR_ITEM_REGULAR), + list("M39 AP Magazine (10x20mm)", round(scale * 3), /obj/item/ammo_magazine/smg/m39/ap, VENDOR_ITEM_REGULAR), + list("M41A AP Magazine (10x24mm)", round(scale * 3), /obj/item/ammo_magazine/rifle/ap, VENDOR_ITEM_REGULAR), + + list("EXTENDED AMMUNITION", -1, null, null), + list("M39 Extended Magazine (10x20mm)", round(scale * 1.8), /obj/item/ammo_magazine/smg/m39/extended, VENDOR_ITEM_REGULAR), + list("M41A Extended Magazine (10x24mm)", round(scale * 1.9), /obj/item/ammo_magazine/rifle/extended, VENDOR_ITEM_REGULAR), + + list("SPECIAL AMMUNITION", -1, null, null), + list("M56 Smartgun Drum", 1, /obj/item/ammo_magazine/smartgun, VENDOR_ITEM_REGULAR), + list("M44 Heavy Speed Loader (.44)", round(scale * 2), /obj/item/ammo_magazine/revolver/heavy, VENDOR_ITEM_REGULAR), + list("M44 Marksman Speed Loader (.44)", round(scale * 2), /obj/item/ammo_magazine/revolver/marksman, VENDOR_ITEM_REGULAR), + + list("RESTRICTED FIREARM AMMUNITION", -1, null, null), + list("VP78 Magazine", round(scale * 5), /obj/item/ammo_magazine/pistol/vp78, VENDOR_ITEM_REGULAR), + list("SU-6 Smartpistol Magazine (.45)", round(scale * 5), /obj/item/ammo_magazine/pistol/smart, VENDOR_ITEM_REGULAR), + list("M240 Incinerator Tank", round(scale * 3), /obj/item/ammo_magazine/flamer_tank, VENDOR_ITEM_REGULAR), + list("M56D Drum Magazine", round(scale * 2), /obj/item/ammo_magazine/m56d, VENDOR_ITEM_REGULAR), + list("M2C Box Magazine", round(scale * 2), /obj/item/ammo_magazine/m2c, VENDOR_ITEM_REGULAR), + list("HIRR Baton Slugs", round(scale * 6), /obj/item/explosive/grenade/slug/baton, VENDOR_ITEM_REGULAR), + list("M74 AGM-S Star Shell", round(scale * 4), /obj/item/explosive/grenade/high_explosive/airburst/starshell, VENDOR_ITEM_REGULAR), + list("M74 AGM-S Hornet Shell", round(scale * 4), /obj/item/explosive/grenade/high_explosive/airburst/hornet_shell, VENDOR_ITEM_REGULAR), + ) + +//--------------SQUAD ARMAMENTS VENDOR-------------- + +/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad + name = "\improper ColMarTech Automated Utilities Squad Vendor" + desc = "An automated supply rack hooked up to a small storage of various utilities and tools. Can be accessed by any Marine Rifleman." + req_access = list(ACCESS_MARINE_ALPHA) + req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_SPECPREP, ACCESS_MARINE_RO) + hackable = TRUE + + vend_x_offset = 2 + vend_y_offset = 1 + vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_TO_HAND + +/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad/ui_state(mob/user) + return GLOB.not_incapacitated_and_adjacent_strict_state + +/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad/populate_product_list(scale) + listed_products = list( + list("FOOD", -1, null, null), + list("MRE", round(scale * 5), /obj/item/storage/box/MRE, VENDOR_ITEM_REGULAR), + list("MRE Box", round(scale * 1), /obj/item/ammo_box/magazine/misc/mre, VENDOR_ITEM_REGULAR), + + list("TOOLS", -1, null, null), + list("Entrenching Tool (ET)", round(scale * 2), /obj/item/tool/shovel/etool/folded, VENDOR_ITEM_REGULAR), + list("Screwdriver", round(scale * 5), /obj/item/tool/screwdriver, VENDOR_ITEM_REGULAR), + list("Wirecutters", round(scale * 5), /obj/item/tool/wirecutters, VENDOR_ITEM_REGULAR), + list("Crowbar", round(scale * 5), /obj/item/tool/crowbar, VENDOR_ITEM_REGULAR), + list("Wrench", round(scale * 5), /obj/item/tool/wrench, VENDOR_ITEM_REGULAR), + list("ME3 hand welder", round(scale * 2), /obj/item/tool/weldingtool/simple, VENDOR_ITEM_REGULAR), + + list("FLARE AND LIGHT", -1, null, null), + list("Combat Flashlight", round(scale * 5), /obj/item/device/flashlight/combat, VENDOR_ITEM_REGULAR), + list("Flashlight", round(scale * 5), /obj/item/device/flashlight/combat, VENDOR_ITEM_REGULAR), + list("Box of Flashlight", round(scale * 1), /obj/item/ammo_box/magazine/misc/flashlight, VENDOR_ITEM_REGULAR), + list("Box of Flares", round(scale * 1), /obj/item/ammo_box/magazine/misc/flares, VENDOR_ITEM_REGULAR), + list("M94 Marking Flare Pack", round(scale * 10), /obj/item/storage/box/m94, VENDOR_ITEM_REGULAR), + list("M89-S Signal Flare Pack", round(scale * 1), /obj/item/storage/box/m94/signal, VENDOR_ITEM_REGULAR), + + list("MISCELLANEOUS", -1, null, null), + list("Toolkit", round(scale * 1), /obj/item/storage/firstaid/toolkit/empty, VENDOR_ITEM_REGULAR), + list("Map", round(scale * 5), /obj/item/map/current_map, VENDOR_ITEM_REGULAR), + list("Extinguisher", round(scale * 5), /obj/item/tool/extinguisher, VENDOR_ITEM_REGULAR), + list("Machete Scabbard (Full)", round(scale * 5), /obj/item/storage/large_holster/machete/full, VENDOR_ITEM_REGULAR), + list("Binoculars", round(scale * 1), /obj/item/device/binoculars, VENDOR_ITEM_REGULAR), + list("MB-6 Folding Barricades (x3)", round(scale * 2), /obj/item/stack/folding_barricade/three, VENDOR_ITEM_REGULAR), + list("Spare PDT/L Battle Buddy Kit", round(scale * 3), /obj/item/storage/box/pdt_kit, VENDOR_ITEM_REGULAR), + list("W-Y brand rechargeable mini-battery", round(scale * 2.5), /obj/item/cell/crap, VENDOR_ITEM_REGULAR) ) + +//--------------SQUAD ATTACHMENTS VENDOR-------------- + +/obj/structure/machinery/cm_vending/sorted/attachments/squad + name = "\improper Armat Systems Squad Attachments Vendor" + desc = "An automated supply rack hooked up to a small storage of weapons attachments. Can be accessed by any Marine Rifleman." + req_access = list(ACCESS_MARINE_ALPHA) + req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_SPECPREP, ACCESS_MARINE_RO) + hackable = TRUE + + vend_y_offset = 1 + +/obj/structure/machinery/cm_vending/sorted/attachments/squad/ui_state(mob/user) + return GLOB.not_incapacitated_and_adjacent_strict_state + +/obj/structure/machinery/cm_vending/sorted/attachments/squad/populate_product_list(scale) + listed_products = list( + list("BARREL", -1, null, null), + list("Extended Barrel", round(scale * 2.5), /obj/item/attachable/extended_barrel, VENDOR_ITEM_REGULAR), + list("Recoil Compensator", round(scale * 2.5), /obj/item/attachable/compensator, VENDOR_ITEM_REGULAR), + list("Suppressor", round(scale * 2.5), /obj/item/attachable/suppressor, VENDOR_ITEM_REGULAR), + + list("RAIL", -1, null, null), + list("B8 Smart-Scope", round(scale * 1.5), /obj/item/attachable/scope/mini_iff, VENDOR_ITEM_REGULAR), + list("Magnetic Harness", round(scale * 4), /obj/item/attachable/magnetic_harness, VENDOR_ITEM_REGULAR), + list("S4 2x Telescopic Mini-Scope", round(scale * 2), /obj/item/attachable/scope/mini, VENDOR_ITEM_REGULAR), + list("S5 Red-Dot Sight", round(scale * 3), /obj/item/attachable/reddot, VENDOR_ITEM_REGULAR), + list("S6 Reflex Sight", round(scale * 3), /obj/item/attachable/reflex, VENDOR_ITEM_REGULAR), + list("S8 4x Telescopic Scope", round(scale * 2), /obj/item/attachable/scope, VENDOR_ITEM_REGULAR), + + list("UNDERBARREL", -1, null, null), + list("Angled Grip", round(scale * 2.5), /obj/item/attachable/angledgrip, VENDOR_ITEM_REGULAR), + list("Bipod", round(scale * 2.5), /obj/item/attachable/bipod, VENDOR_ITEM_REGULAR), + list("Burst Fire Assembly", round(scale * 1.5), /obj/item/attachable/burstfire_assembly, VENDOR_ITEM_REGULAR), + list("Gyroscopic Stabilizer", round(scale * 1.5), /obj/item/attachable/gyro, VENDOR_ITEM_REGULAR), + list("Laser Sight", round(scale * 3), /obj/item/attachable/lasersight, VENDOR_ITEM_REGULAR), + list("Mini Flamethrower", round(scale * 1.5), /obj/item/attachable/attached_gun/flamer, VENDOR_ITEM_REGULAR), + list("XM-VESG-1 Flamer Nozzle", round(scale * 1.5), /obj/item/attachable/attached_gun/flamer_nozzle, VENDOR_ITEM_REGULAR), + list("U7 Underbarrel Shotgun", round(scale * 1.5), /obj/item/attachable/attached_gun/shotgun, VENDOR_ITEM_REGULAR), + list("Underbarrel Extinguisher", round(scale * 1.5), /obj/item/attachable/attached_gun/extinguisher, VENDOR_ITEM_REGULAR), + list("Vertical Grip", round(scale * 3), /obj/item/attachable/verticalgrip, VENDOR_ITEM_REGULAR), + + list("STOCK", -1, null, null), + list("M37 Wooden Stock", round(scale * 1.5), /obj/item/attachable/stock/shotgun, VENDOR_ITEM_REGULAR), + list("M39 Arm Brace", round(scale * 1.5), /obj/item/attachable/stock/smg/collapsible/brace, VENDOR_ITEM_REGULAR), + list("M39 Stock", round(scale * 1.5), /obj/item/attachable/stock/smg, VENDOR_ITEM_REGULAR), + list("M41A Solid Stock", round(scale * 1.5), /obj/item/attachable/stock/rifle, VENDOR_ITEM_REGULAR), + list("M44 Magnum Sharpshooter Stock", round(scale * 1.5), /obj/item/attachable/stock/revolver, VENDOR_ITEM_REGULAR) + ) + +//------------ESSENTIAL SETS--------------- +/obj/effect/essentials_set/random/uscm_light_armor + spawned_gear_list = list( + /obj/item/clothing/suit/storage/marine/light/padded, + /obj/item/clothing/suit/storage/marine/light/padless, + /obj/item/clothing/suit/storage/marine/light/padless_lines, + /obj/item/clothing/suit/storage/marine/light/carrier, + /obj/item/clothing/suit/storage/marine/light/skull, + /obj/item/clothing/suit/storage/marine/light/smooth, + ) + +/obj/effect/essentials_set/random/uscm_heavy_armor + spawned_gear_list = list( + /obj/item/clothing/suit/storage/marine/heavy/padded, + /obj/item/clothing/suit/storage/marine/heavy/padless, + /obj/item/clothing/suit/storage/marine/heavy/padless_lines, + /obj/item/clothing/suit/storage/marine/heavy/carrier, + /obj/item/clothing/suit/storage/marine/heavy/skull, + /obj/item/clothing/suit/storage/marine/heavy/smooth, + ) diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_rifleman.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_rifleman.dm new file mode 100644 index 000000000000..d92eaabf52c1 --- /dev/null +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_rifleman.dm @@ -0,0 +1,136 @@ +//------------SQUAD RIFLEMAN UNIFORM AND GEAR VENDOR--------------- + +GLOBAL_LIST_INIT(cm_vending_clothing_marine, list( + list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), + list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/device/radio/headset/almayer/marine, /obj/item/clothing/head/helmet/marine), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), + list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), + + list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("Light Armor", 0, /obj/item/clothing/suit/storage/marine/light, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("Medium Armor", 0, /obj/item/clothing/suit/storage/marine/medium, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("Heavy Armor", 0, /obj/item/clothing/suit/storage/marine/heavy, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + + list("BACKPACK (CHOOSE 1)", 0, null, null, null), + list("Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), + list("Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), + list("Shotgun Scabbard", 0, /obj/item/storage/large_holster/m37, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), + + list("BELT (CHOOSE 1)", 0, null, null, null), + list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 Knife Rig (Full)", 0, /obj/item/storage/belt/knifepouch, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M40 Grenade Rig (Empty)", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + + list("POUCHES (CHOOSE 2)", 0, null, null, null), + list("Bayonet Sheath (Full)", 0, /obj/item/storage/pouch/bayonet, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Small Document Pouch", 0, /obj/item/storage/pouch/document/small, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + + list("MASK (CHOOSE 1)", 0, null, null, null), + list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Rebreather", 0, /obj/item/clothing/mask/rebreather, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + + list("RESTRICTED FIREARMS", 0, null, null, null), + list("VP78 Pistol", 15, /obj/item/storage/box/guncase/vp78, null, VENDOR_ITEM_REGULAR), + list("SU-6 Smart Pistol", 15, /obj/item/storage/box/guncase/smartpistol, null, VENDOR_ITEM_REGULAR), + list("M79 Grenade Launcher", 30, /obj/item/storage/box/guncase/m79, null, VENDOR_ITEM_REGULAR), + + list("EXPLOSIVES", 0, null, null, null), + list("M40 HEDP High Explosive Packet (x3 grenades)", 20, /obj/item/storage/box/packet/high_explosive, null, VENDOR_ITEM_REGULAR), + list("M40 HIDP Incendiary Packet (x3 grenades)", 20, /obj/item/storage/box/packet/incendiary, null, VENDOR_ITEM_REGULAR), + list("M40 HPDP White Phosphorus Packet (x3 grenades)", 20, /obj/item/storage/box/packet/phosphorus, null, VENDOR_ITEM_REGULAR), + list("M40 HSDP Smoke Packet (x3 grenades)", 10, /obj/item/storage/box/packet/smoke, null, VENDOR_ITEM_REGULAR), + list("M74 AGM-Frag Airburst Packet (x3 airburst grenades)", 15, /obj/item/storage/box/packet/airburst_he, null, VENDOR_ITEM_REGULAR), + list("M74 AGM-Incendiary Airburst Packet (x3 airburst grenades)", 15, /obj/item/storage/box/packet/airburst_incen, null, VENDOR_ITEM_REGULAR), + list("M74 AGM-Smoke Airburst Packet (x3 airburst grenades)", 10, /obj/item/storage/box/packet/airburst_smoke, null, VENDOR_ITEM_REGULAR), + list("M74 AGM-Hornet Airburst Packet (x3 airburst grenades", 15, /obj/item/storage/box/packet/hornet, null, VENDOR_ITEM_REGULAR), + list("M20 Mine Box (x4 mines)", 20, /obj/item/storage/box/explosive_mines, null, VENDOR_ITEM_REGULAR), + + list("AMMUNITION", 0, null, null, null), + list("M4RA AP Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/m4ra/ap, null, VENDOR_ITEM_REGULAR), + list("M39 AP Magazine (10x20mm)", 10, /obj/item/ammo_magazine/smg/m39/ap , null, VENDOR_ITEM_REGULAR), + list("M39 Extended Magazine (10x20mm)", 10, /obj/item/ammo_magazine/smg/m39/extended , null, VENDOR_ITEM_REGULAR), + list("M41A AP Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/ap , null, VENDOR_ITEM_REGULAR), + list("M41A Extended Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/extended , null, VENDOR_ITEM_REGULAR), + list("M44 Heavy Speed Loader (.44)", 10, /obj/item/ammo_magazine/revolver/heavy, null, VENDOR_ITEM_REGULAR), + + list("UTILITIES", 0, null, null, null), + list("E-Tool", 5, /obj/item/tool/shovel/etool/folded, null, VENDOR_ITEM_REGULAR), + list("Sandbags", 20, /obj/item/stack/sandbags_empty/half, null, VENDOR_ITEM_REGULAR), + list("Webbing", 10, /obj/item/clothing/accessory/storage/webbing, null, VENDOR_ITEM_REGULAR), + list("Brown Webbing Vest", 15, /obj/item/clothing/accessory/storage/black_vest/brown_vest, null, VENDOR_ITEM_REGULAR), + list("Black Webbing Vest", 15, /obj/item/clothing/accessory/storage/black_vest, null, VENDOR_ITEM_REGULAR), + list("Drop Pouch", 15, /obj/item/clothing/accessory/storage/droppouch, null, VENDOR_ITEM_REGULAR), + list("SensorMate Medical HUD", 15, /obj/item/clothing/glasses/hud/sensor, null, VENDOR_ITEM_REGULAR), + list("Roller Bed", 5, /obj/item/roller, null, VENDOR_ITEM_REGULAR), + list("Fulton Device Stack", 5, /obj/item/stack/fulton, null, VENDOR_ITEM_REGULAR), + list("B12 Pattern Marine Armor", 30, /obj/item/clothing/suit/storage/marine/leader, null, VENDOR_ITEM_REGULAR), + list("Range Finder", 10, /obj/item/device/binoculars/range, null, VENDOR_ITEM_REGULAR), + list("Laser Designator", 15, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_REGULAR), + list("Fuel Tank Strap Pouch", 5, /obj/item/storage/pouch/flamertank, null, VENDOR_ITEM_REGULAR), + list("Shoulder Holster", 15, /obj/item/clothing/accessory/storage/holster, null, VENDOR_ITEM_REGULAR), + list("Machete Scabbard (Full)", 15, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR), + list("Machete Pouch (Full)", 15, /obj/item/storage/pouch/machete/full, null, VENDOR_ITEM_REGULAR), + list("Fire Extinguisher (Portable)", 5, /obj/item/tool/extinguisher/mini, null, VENDOR_ITEM_REGULAR), + list("Motion Detector", 15, /obj/item/device/motiondetector, null, VENDOR_ITEM_REGULAR), + list("Data Detector", 15, /obj/item/device/motiondetector/intel, null, VENDOR_ITEM_REGULAR), + list("Whistle", 5, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), + list("Welding Goggles", 5, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_REGULAR), + list("JTAC Pamphlet", 15, /obj/item/pamphlet/skill/jtac, null, VENDOR_ITEM_REGULAR), + list("Engineering Pamphlet", 15, /obj/item/pamphlet/skill/engineer, null, VENDOR_ITEM_REGULAR), + list("Powerloader Certification", 45, /obj/item/pamphlet/skill/powerloader, null, VENDOR_ITEM_REGULAR), + list("USCM Radio Telephone Pack", 15, /obj/item/storage/backpack/marine/satchel/rto, null, VENDOR_ITEM_REGULAR), + + list("RADIO KEYS", 0, null, null, null), + list("Engineering Radio Encryption Key", 5, /obj/item/device/encryptionkey/engi, null, VENDOR_ITEM_REGULAR), + list("Intel Radio Encryption Key", 5, /obj/item/device/encryptionkey/intel, null, VENDOR_ITEM_REGULAR), + list("JTAC Radio Encryption Key", 5, /obj/item/device/encryptionkey/jtac, null, VENDOR_ITEM_REGULAR), + list("Supply Radio Encryption Key", 5, /obj/item/device/encryptionkey/req, null, VENDOR_ITEM_REGULAR), + )) + +/obj/structure/machinery/cm_vending/clothing/marine + name = "\improper ColMarTech Automated Marine Equipment Rack" + desc = "An automated rack hooked up to a colossal storage of Marine Rifleman standard-issue equipment." + icon_state = "mar_rack" + show_points = TRUE + vendor_theme = VENDOR_THEME_USCM + + vendor_role = list(JOB_SQUAD_MARINE) + +/obj/structure/machinery/cm_vending/clothing/marine/get_listed_products(mob/user) + return GLOB.cm_vending_clothing_marine + +/obj/structure/machinery/cm_vending/clothing/marine/alpha + squad_tag = SQUAD_MARINE_1 + req_access = list(ACCESS_MARINE_ALPHA) + headset_type = /obj/item/device/radio/headset/almayer/marine/alpha + +/obj/structure/machinery/cm_vending/clothing/marine/bravo + squad_tag = SQUAD_MARINE_2 + req_access = list(ACCESS_MARINE_BRAVO) + headset_type = /obj/item/device/radio/headset/almayer/marine/bravo + +/obj/structure/machinery/cm_vending/clothing/marine/charlie + squad_tag = SQUAD_MARINE_3 + req_access = list(ACCESS_MARINE_CHARLIE) + headset_type = /obj/item/device/radio/headset/almayer/marine/charlie + +/obj/structure/machinery/cm_vending/clothing/marine/delta + squad_tag = SQUAD_MARINE_4 + req_access = list(ACCESS_MARINE_DELTA) + headset_type = /obj/item/device/radio/headset/almayer/marine/delta diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_smartgunner.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_smartgunner.dm index dc5c4f0fb272..5560508ca4c1 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_smartgunner.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_smartgunner.dm @@ -7,10 +7,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_smartgun, list( list("SMARTGUN AMMUNITION", 0, null, null, null), list("M56 Smartgun Drum", 15, /obj/item/ammo_magazine/smartgun, null, VENDOR_ITEM_RECOMMENDED), - list("SMARTGUN EXTRA UTILITIES (CHOOSE 1)", 0, null, null, null), - list("Burst Fire Assembly", 0, /obj/item/attachable/burstfire_assembly, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), - list("High-Capacity Power Cell", 0, /obj/item/cell/high, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), - list("GUN ATTACHMENTS (CHOOSE 1)", 0, null, null, null), list("Laser Sight", 0, /obj/item/attachable/lasersight, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_REGULAR), list("Red-Dot Sight", 0, /obj/item/attachable/reddot, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_REGULAR), @@ -30,15 +26,12 @@ GLOBAL_LIST_INIT(cm_vending_gear_smartgun, list( list("UTILITIES", 0, null, null, null), list("Range Finder", 10, /obj/item/device/binoculars/range, null, VENDOR_ITEM_REGULAR), list("Laser Designator", 15, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_REGULAR), - list("Large General Pouch", 15, /obj/item/storage/pouch/general/large, null, VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 15, /obj/item/storage/pouch/magazine/large, null, VENDOR_ITEM_REGULAR), list("Fuel Tank Strap Pouch", 5, /obj/item/storage/pouch/flamertank, null, VENDOR_ITEM_REGULAR), list("Fire Extinguisher (Portable)", 5, /obj/item/tool/extinguisher/mini, null, VENDOR_ITEM_REGULAR), list("Whistle", 5, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), list("JTAC Pamphlet", 15, /obj/item/pamphlet/skill/jtac, null, VENDOR_ITEM_REGULAR), list("Engineering Pamphlet", 15, /obj/item/pamphlet/skill/engineer, null, VENDOR_ITEM_REGULAR), list("Powerloader Certification", 45, /obj/item/pamphlet/skill/powerloader, null, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 10, /obj/item/storage/pouch/shotgun/large, null, VENDOR_ITEM_RECOMMENDED), list("Roller Bed", 5, /obj/item/roller, null, VENDOR_ITEM_REGULAR), list("Fulton Device Stack", 5, /obj/item/stack/fulton, null, VENDOR_ITEM_REGULAR), @@ -70,24 +63,25 @@ GLOBAL_LIST_INIT(cm_vending_clothing_smartgun, list( list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Helmet", 0, /obj/item/clothing/head/helmet/marine, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), list("BELT", 0, null, null, null), list("M802 Smartgunner Sidearm Belt", 0, /obj/item/storage/belt/gun/smartgunner/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_MANDATORY), list("M280 Smartgunner Drum Belt", 0, /obj/item/storage/belt/marine/smartgunner, MARINE_CAN_BUY_BELT, VENDOR_ITEM_MANDATORY), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Electronics Pouch", 0, /obj/item/storage/pouch/electronics, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Machete Pouch (Full)", 0, /obj/item/storage/pouch/machete/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Electronics Pouch", 0, /obj/item/storage/pouch/electronics, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Machete Pouch (Full)", 0, /obj/item/storage/pouch/machete/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm index f5ccef0ca0dc..e0900c3fd3c8 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm @@ -50,7 +50,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_spec, list( list("JTAC Pamphlet", 15, /obj/item/pamphlet/skill/jtac, null, VENDOR_ITEM_REGULAR), list("Engineering Pamphlet", 15, /obj/item/pamphlet/skill/engineer, null, VENDOR_ITEM_REGULAR), list("Powerloader Certification", 45, /obj/item/pamphlet/skill/powerloader, null, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 10, /obj/item/storage/pouch/shotgun/large, null, VENDOR_ITEM_REGULAR), list("RADIO KEYS", 0, null, null, null), list("Engineering Radio Encryption Key", 5, /obj/item/device/encryptionkey/engi, null, VENDOR_ITEM_REGULAR), @@ -81,6 +80,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_specialist, list( list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), list("BACKPACK (CHOOSE 1)", 0, null, null, null), list("Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), @@ -90,22 +90,22 @@ GLOBAL_LIST_INIT(cm_vending_clothing_specialist, list( list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medium General Pouch", 0, /obj/item/storage/pouch/general/medium, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_rto.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_tl.dm similarity index 63% rename from code/game/machinery/vending/vendor_types/squad_prep/squad_rto.dm rename to code/game/machinery/vending/vendor_types/squad_prep/squad_tl.dm index 09742b818199..ceef80ab6952 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_rto.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_tl.dm @@ -1,6 +1,6 @@ //------------GEAR VENDOR--------------- -GLOBAL_LIST_INIT(cm_vending_gear_rto, list( +GLOBAL_LIST_INIT(cm_vending_gear_tl, list( list("AMMUNITION", 0, null, null, null), list("M4RA AP Magazine (10x24mm)", 10, /obj/item/ammo_magazine/rifle/m4ra/ap, null, VENDOR_ITEM_REGULAR), @@ -27,12 +27,11 @@ GLOBAL_LIST_INIT(cm_vending_gear_rto, list( list("RESTRICTED FIREARMS", 0, null, null, null), list("VP78 Pistol", 10, /obj/item/storage/box/guncase/vp78, null, VENDOR_ITEM_REGULAR), list("SU-6 Smart Pistol", 15, /obj/item/storage/box/guncase/smartpistol, null, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", 30, /obj/item/storage/box/guncase/lmg, null, VENDOR_ITEM_REGULAR), list("M79 Grenade Launcher", 30, /obj/item/storage/box/guncase/m79, null, VENDOR_ITEM_REGULAR), list("UTILITIES", 0, null, null, null), + list("Radio Telephone Pack", 5, /obj/item/storage/backpack/marine/satchel/rto, null, VENDOR_ITEM_RECOMMENDED), list("Binoculars", 5, /obj/item/device/binoculars, null, VENDOR_ITEM_REGULAR), - list("Large Magazine Pouch", 10, /obj/item/storage/pouch/magazine/large, null, VENDOR_ITEM_REGULAR), list("Motion Detector", 15, /obj/item/device/motiondetector, null, VENDOR_ITEM_RECOMMENDED), list("Plastic Explosive", 10, /obj/item/explosive/plastic, null, VENDOR_ITEM_REGULAR), list("Breaching Charge", 10, /obj/item/explosive/plastic/breaching_charge, null, VENDOR_ITEM_REGULAR), @@ -40,7 +39,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_rto, list( list("M2 Night Vision Goggles", 30, /obj/item/prop/helmetgarb/helmet_nvg, null, VENDOR_ITEM_RECOMMENDED), list("Roller Bed", 5, /obj/item/roller, null, VENDOR_ITEM_REGULAR), list("Fulton Device Stack", 5, /obj/item/stack/fulton, null, VENDOR_ITEM_REGULAR), - list("Large General Pouch", 15, /obj/item/storage/pouch/general/large, null, VENDOR_ITEM_REGULAR), list("Shoulder Holster", 15, /obj/item/clothing/accessory/storage/holster, null, VENDOR_ITEM_REGULAR), list("Machete Scabbard (Full)", 5, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR), list("Machete Pouch (Full)", 15, /obj/item/storage/pouch/machete/full, null, VENDOR_ITEM_REGULAR), @@ -48,7 +46,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_rto, list( list("Whistle", 5, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), list("Welding Goggles", 5, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_REGULAR), list("Powerloader Certification", 45, /obj/item/pamphlet/skill/powerloader, null, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 10, /obj/item/storage/pouch/shotgun/large, null, VENDOR_ITEM_RECOMMENDED), + list("Insulated Gloves", 3, /obj/item/clothing/gloves/yellow, null, VENDOR_ITEM_REGULAR), list("RADIO KEYS", 0, null, null, null), list("Engineering Radio Encryption Key", 5, /obj/item/device/encryptionkey/engi, null, VENDOR_ITEM_REGULAR), @@ -57,36 +55,36 @@ GLOBAL_LIST_INIT(cm_vending_gear_rto, list( list("Supply Radio Encryption Key", 5, /obj/item/device/encryptionkey/req, null, VENDOR_ITEM_REGULAR), )) -/obj/structure/machinery/cm_vending/gear/rto - name = "ColMarTech Radio Telephone Operator Gear Rack" - desc = "An automated gear rack for RTOs." +/obj/structure/machinery/cm_vending/gear/tl + name = "ColMarTech Fireteam Leader Gear Rack" + desc = "An automated gear rack for fireteam leaders." icon_state = "intel_gear" show_points = TRUE - req_access = list(ACCESS_MARINE_RTO_PREP) - vendor_role = list(JOB_SQUAD_RTO) + req_access = list(ACCESS_MARINE_TL_PREP) + vendor_role = list(JOB_SQUAD_TEAM_LEADER) -/obj/structure/machinery/cm_vending/gear/rto/get_listed_products(mob/user) - return GLOB.cm_vending_gear_rto +/obj/structure/machinery/cm_vending/gear/tl/get_listed_products(mob/user) + return GLOB.cm_vending_gear_tl //------------CLOTHING VENDOR--------------- -GLOBAL_LIST_INIT(cm_vending_clothing_rto, list( +GLOBAL_LIST_INIT(cm_vending_clothing_tl, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine/rto, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine/insulated, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Armor", 0, /obj/item/clothing/suit/storage/marine/rto, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), + list("Uniform", 0, /obj/item/clothing/under/marine, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), + list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), + list("M4 Pattern Armor", 0, /obj/item/clothing/suit/storage/marine/rto, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Helmet", 0, /obj/item/clothing/head/helmet/marine/rto, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), - list("Radio Telephone Pack", 0, /obj/item/storage/backpack/marine/satchel/rto, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), - list("Essential RTO Utilities", 0, /obj/effect/essentials_set/rto/utilities, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), + list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), + list("Essential Fireteam Leader Utilities", 0, /obj/effect/essentials_set/tl, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), list("BELT (CHOOSE 1)", 0, null, null, null), list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), list("M276 General Pistol Holster Rig", 0, /obj/item/storage/belt/gun/m4a3, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 0, /obj/item/storage/large_holster/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 0, /obj/item/storage/belt/gun/m44, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), @@ -94,21 +92,21 @@ GLOBAL_LIST_INIT(cm_vending_clothing_rto, list( list("M276 M40 Grenade Rig", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, (MARINE_CAN_BUY_R_POUCH|MARINE_CAN_BUY_L_POUCH), VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Magazine Pouch", 0, /obj/item/storage/pouch/magazine, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medkit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sidearm Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), @@ -123,68 +121,41 @@ GLOBAL_LIST_INIT(cm_vending_clothing_rto, list( )) //MARINE_CAN_BUY_SHOES MARINE_CAN_BUY_UNIFORM currently not used -/obj/structure/machinery/cm_vending/clothing/rto - name = "ColMarTech Radio Telephone Operator Equipment Rack" - desc = "An automated rack hooked up to a colossal storage of RTO standard-issue equipment." - req_access = list(ACCESS_MARINE_RTO_PREP) - vendor_role = list(JOB_SQUAD_RTO) +/obj/structure/machinery/cm_vending/clothing/tl + name = "ColMarTech Fireteam Leader Equipment Rack" + desc = "An automated rack hooked up to a colossal storage of fireteam leader standard-issue equipment." + req_access = list(ACCESS_MARINE_TL_PREP) + vendor_role = list(JOB_SQUAD_TEAM_LEADER) -/obj/structure/machinery/cm_vending/clothing/rto/get_listed_products(mob/user) - return GLOB.cm_vending_clothing_rto +/obj/structure/machinery/cm_vending/clothing/tl/get_listed_products(mob/user) + return GLOB.cm_vending_clothing_tl -/obj/structure/machinery/cm_vending/clothing/rto/alpha +/obj/structure/machinery/cm_vending/clothing/tl/alpha squad_tag = SQUAD_MARINE_1 - req_access = list(ACCESS_MARINE_RTO_PREP, ACCESS_MARINE_ALPHA) + req_access = list(ACCESS_MARINE_TL_PREP, ACCESS_MARINE_ALPHA) gloves_type = /obj/item/clothing/gloves/marine/insulated - headset_type = /obj/item/device/radio/headset/almayer/marine/alpha/rto + headset_type = /obj/item/device/radio/headset/almayer/marine/alpha/tl -/obj/structure/machinery/cm_vending/clothing/rto/bravo +/obj/structure/machinery/cm_vending/clothing/tl/bravo squad_tag = SQUAD_MARINE_2 - req_access = list(ACCESS_MARINE_RTO_PREP, ACCESS_MARINE_BRAVO) + req_access = list(ACCESS_MARINE_TL_PREP, ACCESS_MARINE_BRAVO) gloves_type = /obj/item/clothing/gloves/marine/insulated - headset_type = /obj/item/device/radio/headset/almayer/marine/bravo/rto + headset_type = /obj/item/device/radio/headset/almayer/marine/bravo/tl -/obj/structure/machinery/cm_vending/clothing/rto/charlie +/obj/structure/machinery/cm_vending/clothing/tl/charlie squad_tag = SQUAD_MARINE_3 - req_access = list(ACCESS_MARINE_RTO_PREP, ACCESS_MARINE_CHARLIE) + req_access = list(ACCESS_MARINE_TL_PREP, ACCESS_MARINE_CHARLIE) gloves_type = /obj/item/clothing/gloves/marine/insulated - headset_type = /obj/item/device/radio/headset/almayer/marine/charlie/rto + headset_type = /obj/item/device/radio/headset/almayer/marine/charlie/tl -/obj/structure/machinery/cm_vending/clothing/rto/delta +/obj/structure/machinery/cm_vending/clothing/tl/delta squad_tag = SQUAD_MARINE_4 - req_access = list(ACCESS_MARINE_RTO_PREP, ACCESS_MARINE_DELTA) + req_access = list(ACCESS_MARINE_TL_PREP, ACCESS_MARINE_DELTA) gloves_type = /obj/item/clothing/gloves/marine/insulated - headset_type = /obj/item/device/radio/headset/almayer/marine/delta/rto + headset_type = /obj/item/device/radio/headset/almayer/marine/delta/tl //------------ESSENTIAL SETS--------------- - -/obj/effect/essentials_set/rto/vp78 - spawned_gear_list = list( - /obj/item/weapon/gun/pistol/vp78, - /obj/item/device/binoculars/range/designator, - /obj/item/storage/box/m94/signal, - /obj/item/storage/box/m94/signal, - /obj/item/ammo_magazine/pistol/vp78, - /obj/item/ammo_magazine/pistol/vp78, - /obj/item/ammo_magazine/pistol/vp78, - /obj/item/ammo_magazine/pistol/vp78, - /obj/item/storage/belt/gun/m4a3, - ) - -/obj/effect/essentials_set/rto/mod - spawned_gear_list = list( - /obj/item/weapon/gun/pistol/mod88, - /obj/item/device/binoculars/range/designator, - /obj/item/storage/box/m94/signal, - /obj/item/storage/box/m94/signal, - /obj/item/ammo_magazine/pistol/mod88, - /obj/item/ammo_magazine/pistol/mod88, - /obj/item/ammo_magazine/pistol/mod88, - /obj/item/ammo_magazine/pistol/mod88, - /obj/item/storage/belt/gun/m4a3, - ) - -/obj/effect/essentials_set/rto/utilities +/obj/effect/essentials_set/tl spawned_gear_list = list( /obj/item/device/binoculars/range/designator, /obj/item/storage/box/m94/signal, diff --git a/code/game/machinery/vending/vendor_types/wo_vendors.dm b/code/game/machinery/vending/vendor_types/wo_vendors.dm index 01f66fbfaf48..645640f9dc84 100644 --- a/code/game/machinery/vending/vendor_types/wo_vendors.dm +++ b/code/game/machinery/vending/vendor_types/wo_vendors.dm @@ -12,7 +12,7 @@ list("Lightweight IMP Backpack", 10, /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), list("M276 Ammo Load Rig", 10, /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), list("M276 General Pistol Holster Rig", 10, /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 10, /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 10, /obj/item/storage/belt/gun/m39, VENDOR_ITEM_REGULAR), list("M276 M44 Holster Rig", 10, /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", 10, /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), list("M276 Shotgun Shell Loading Rig", 10, /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), @@ -151,7 +151,7 @@ list("M44 Heavy Speed Loader (.44)", round(scale * 2), /obj/item/ammo_magazine/revolver/heavy, VENDOR_ITEM_REGULAR), list("M44 Marksman Speed Loader (.44)", round(scale * 2), /obj/item/ammo_magazine/revolver/marksman, VENDOR_ITEM_REGULAR), list("M4A3 HP Magazine (9mm)", round(scale * 5), /obj/item/ammo_magazine/pistol/hp, VENDOR_ITEM_REGULAR), - list("M56 Powerpack", round(scale * 5), /obj/item/smartgun_powerpack, VENDOR_ITEM_REGULAR), + list("M56 Battery", round(scale * 5), /obj/item/smartgun_battery, VENDOR_ITEM_REGULAR), list("M56 Smartgun Drum", round(scale * 2), /obj/item/ammo_magazine/smartgun, VENDOR_ITEM_REGULAR), list("SU-6 Smartpistol Magazine (.45)", round(scale * 6), /obj/item/ammo_magazine/pistol/smart, VENDOR_ITEM_REGULAR), list("VP78 Magazine", round(scale * 6), /obj/item/ammo_magazine/pistol/vp78, VENDOR_ITEM_REGULAR), @@ -236,7 +236,7 @@ list("G8-A General Utility Pouch", round(scale * 3), /obj/item/storage/backpack/general_belt, VENDOR_ITEM_REGULAR), list("M276 Pattern Ammo Load Rig", round(scale * 15), /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), list("M276 Pattern General Pistol Holster Rig", round(scale * 10), /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 Pattern M39 Holster Rig", round(scale * 5), /obj/item/storage/large_holster/m39, VENDOR_ITEM_REGULAR), + list("M276 Pattern M39 Holster Rig", round(scale * 5), /obj/item/storage/belt/gun/m39, VENDOR_ITEM_REGULAR), list("M276 Pattern M44 Holster Rig", round(scale * 5), /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), list("M276 M82F Holster Rig", round(scale * 2), /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), list("M276 Pattern Shotgun Shell Loading Rig", round(scale * 10), /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index cbe0871148da..b94ee6902321 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -291,6 +291,8 @@ var/ticks = 0 var/acid_strength = 1 //100% speed, normal var/barricade_damage = 40 + /// How much fuel the acid drains from the flare every acid tick + var/flare_damage = 500 var/barricade_damage_ticks = 10 // tick is once per 5 seconds. This tells us how many times it will try damaging barricades var/in_weather = FALSE @@ -299,13 +301,15 @@ name = "weak acid" acid_strength = 2.5 //250% normal speed barricade_damage = 20 + flare_damage = 150 icon_state = "acid_weak" //Superacid /obj/effect/xenomorph/acid/strong name = "strong acid" - acid_strength = 0.4 //20% normal speed + acid_strength = 0.4 //40% normal speed barricade_damage = 100 + flare_damage = 1875 icon_state = "acid_strong" /obj/effect/xenomorph/acid/New(loc, target) @@ -355,6 +359,12 @@ sleep(50) .() return + if(istype(acid_t, /obj/item/device/flashlight/flare)) + var/obj/item/device/flashlight/flare/flare = acid_t + if(flare.fuel > 0) //Flares that have fuel in them lose fuel instead of melting + flare.fuel -= flare_damage + sleep(rand(150,250) * (acid_strength)) + return .() if(++ticks >= strength_t) visible_message(SPAN_XENODANGER("[acid_t] collapses under its own weight into a puddle of goop and undigested debris!")) @@ -394,8 +404,6 @@ sleep(rand(200,300) * (acid_strength)) .() - - /obj/effect/xenomorph/boiler_bombard name = "???" desc = "" diff --git a/code/game/objects/effects/decals/cleanable/blood/blood.dm b/code/game/objects/effects/decals/cleanable/blood/blood.dm index a5b46b1ef49f..918797608b7b 100644 --- a/code/game/objects/effects/decals/cleanable/blood/blood.dm +++ b/code/game/objects/effects/decals/cleanable/blood/blood.dm @@ -131,7 +131,7 @@ anchored = TRUE layer = TURF_LAYER icon = 'icons/effects/blood.dmi' - icon_state = "gibbl5" + icon_state = "" random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6") cleanable_type = CLEANABLE_BLOOD_GIBS var/fleshcolor = "#830303" diff --git a/code/game/objects/effects/decals/cleanable/blood/xeno.dm b/code/game/objects/effects/decals/cleanable/blood/xeno.dm index 12f6e859493d..ade4723a1d74 100644 --- a/code/game/objects/effects/decals/cleanable/blood/xeno.dm +++ b/code/game/objects/effects/decals/cleanable/blood/xeno.dm @@ -5,7 +5,7 @@ name = "sizzling blood" desc = "It's yellow and acidic. It looks like... blood?" icon = 'icons/effects/blood.dmi' - basecolor = "#dffc00" + basecolor = BLOOD_COLOR_XENO amount = 1 /obj/effect/decal/cleanable/blood/gibs/xeno @@ -14,7 +14,7 @@ desc = "Gnarly..." icon_state = "xgib1" random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6") - basecolor = "#dffc00" + basecolor = BLOOD_COLOR_XENO /obj/effect/decal/cleanable/blood/gibs/xeno/update_icon() color = "#FFFFFF" @@ -35,4 +35,4 @@ random_icon_states = list("xgibmid1", "xgibmid2", "xgibmid3") /obj/effect/decal/cleanable/blood/xtracks - basecolor = "#dffc00" + basecolor = BLOOD_COLOR_XENO diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index 8d6a1ab87c0b..43c3500813a4 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -31,6 +31,16 @@ icon_state = "dirt" mouse_opacity = MOUSE_OPACITY_TRANSPARENT +/obj/effect/decal/cleanable/dirt/greenglow + name = "glowing goo" + acid_damage = 1 + icon_state = "greenglow" + luminosity = 1 + +/obj/effect/decal/cleanable/dirt/greenglow/Destroy() + SetLuminosity(0) + return ..() + /obj/effect/decal/cleanable/flour name = "flour" desc = "It's still good. Four second rule!" @@ -159,7 +169,7 @@ /obj/effect/decal/cleanable/blackgoo/Crossed(mob/living/carbon/human/H) if(!istype(H)) return if(H.species.name == "Human") - if(!H.shoes || prob(25)) + if(!H.shoes && prob(50)) H.contract_disease(new /datum/disease/black_goo) diff --git a/code/game/objects/effects/decals/strata_decals.dm b/code/game/objects/effects/decals/strata_decals.dm index 44f682961122..2ac13577f702 100644 --- a/code/game/objects/effects/decals/strata_decals.dm +++ b/code/game/objects/effects/decals/strata_decals.dm @@ -24,35 +24,11 @@ /obj/effect/decal/strata_decals/rocks/ice/ice1 icon_state = "icerock" -/obj/effect/decal/strata_decals/rocks/snowy1 - icon_state = "snowy1" - -/obj/effect/decal/strata_decals/rocks/snowy2 - icon_state = "snowy2" - -/obj/effect/decal/strata_decals/rocks/snowy3 - icon_state = "snowy3" - -/obj/effect/decal/strata_decals/rocks/snowy4 - icon_state = "snowy4" - /obj/effect/decal/strata_decals/grasses - icon_state = "" + icon_state = "tufts" name = "some foliage" desc = "A few brave tufts of snow grass." -/obj/effect/decal/strata_decals/grasses/tufts1 - icon_state = "tufts1" - -/obj/effect/decal/strata_decals/grasses/tufts2 - icon_state = "tufts2" - -/obj/effect/decal/strata_decals/grasses/tufts3 - icon_state = "tufts3" - -/obj/effect/decal/strata_decals/grasses/tufts4 - icon_state = "tufts4" - ////////////////INDOORS STUFF//////////////////// /obj/effect/decal/strata_decals/grime diff --git a/code/game/objects/effects/decals/warning_stripes.dm b/code/game/objects/effects/decals/warning_stripes.dm index 23d1daa1031e..ce0802d72d8e 100644 --- a/code/game/objects/effects/decals/warning_stripes.dm +++ b/code/game/objects/effects/decals/warning_stripes.dm @@ -91,14 +91,6 @@ /obj/effect/decal/sand_overlay/sand2/corner2 icon_state = "sand2_c" -/obj/effect/decal/halftile - name = "half tile" - icon_state = "halftile" - -/obj/effect/decal/halftile/warning - name = "warning stripes half tile" - icon_state = "halftile_w" - /obj/effect/decal/siding name = "siding" icon = 'icons/turf/floors/floors.dmi' diff --git a/code/game/objects/effects/effect_system/chemsmoke.dm b/code/game/objects/effects/effect_system/chemsmoke.dm index 18a05ddc2cb5..c2323c32c934 100644 --- a/code/game/objects/effects/effect_system/chemsmoke.dm +++ b/code/game/objects/effects/effect_system/chemsmoke.dm @@ -3,6 +3,7 @@ ///////////////////////////////////////////// /obj/effect/particle_effect/smoke/chem icon = 'icons/effects/chemsmoke.dmi' + icon_state = "" opacity = FALSE time_to_live = 300 anchored = TRUE @@ -39,7 +40,8 @@ // Culls the selected turfs to a (roughly) circle shape, then calls smokeFlow() to make // sure the smoke can actually path to the turfs. This culls any turfs it can't reach. //------------------------------------------ -/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, n = 10, c = 0, loca, direct) +/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, n = 10, c = 0, loca, direct, datum/cause_data/new_cause_data) + cause_data = istype(new_cause_data) ? new_cause_data : cause_data range = n * 0.3 cardinals = c carry.copy_to(chemholder, carry.total_volume) @@ -81,11 +83,7 @@ var/whereLink = "[where]" if(carry.my_atom.fingerprintslast) - var/mob/M = GLOB.directory[carry.my_atom.fingerprintslast] - var/more = "" - if(M) - more = "(?)" - message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].") + message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") else message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.") @@ -150,7 +148,7 @@ var/color = mix_color_from_reagents(chemholder.reagents.reagent_list) var/icon/I if(color) - I = icon('icons/effects/chemsmoke.dmi') + I = icon('icons/effects/chemsmoke.dmi', "smoke") I += color else I = icon('icons/effects/96x96.dmi', "smoke") diff --git a/code/game/objects/effects/effect_system/effect_system.dm b/code/game/objects/effects/effect_system/effect_system.dm index e84b33d072c9..49342af8514f 100644 --- a/code/game/objects/effects/effect_system/effect_system.dm +++ b/code/game/objects/effects/effect_system/effect_system.dm @@ -11,7 +11,12 @@ would spawn and follow the beaker, even if it is carried or thrown. var/cardinals = 0 var/turf/location var/atom/holder - var/setup = 0 + var/setup = FALSE + +/datum/effect_system/Destroy(force, ...) + holder = null + location = null + return ..() /datum/effect_system/proc/set_up(n = 3, c = 0, turf/loca) if(n > 10) @@ -19,7 +24,7 @@ would spawn and follow the beaker, even if it is carried or thrown. number = n cardinals = c location = loca - setup = 1 + setup = TRUE /datum/effect_system/proc/attach(atom/atom) holder = atom @@ -59,13 +64,13 @@ steam.start() -- spawns the effect /datum/effect_system/steam_spread/start() var/i = 0 - for(i=0, i 20) + for(i=0, i 20) return spawn(0) if(holder) - src.location = get_turf(holder) - var/obj/effect/particle_effect/sparks/sparks = new /obj/effect/particle_effect/sparks(src.location) - src.total_sparks++ + location = get_turf(holder) + var/obj/effect/particle_effect/sparks/sparks = new /obj/effect/particle_effect/sparks(location) + total_sparks++ var/direction - if(src.cardinals) + if(cardinals) direction = pick(cardinal) else direction = pick(alldirs) @@ -151,42 +156,45 @@ steam.start() -- spawns the effect /datum/effect_system/ion_trail_follow var/turf/oldposition - var/processing = 1 - var/on = 1 + var/processing = TRUE + var/on = TRUE /datum/effect_system/ion_trail_follow/set_up(atom/atom) attach(atom) oldposition = get_turf(atom) /datum/effect_system/ion_trail_follow/start() - if(!src.on) - src.on = 1 - src.processing = 1 - if(src.processing) - src.processing = 0 + if(!on) + on = TRUE + processing = TRUE + if(processing) + processing = FALSE spawn(0) - var/turf/T = get_turf(src.holder) - if(T != src.oldposition) - if(istype(T, /turf/open/space)) - var/obj/effect/particle_effect/ion_trails/I = new /obj/effect/particle_effect/ion_trails(src.oldposition) - src.oldposition = T - I.setDir(src.holder.dir) - flick("ion_fade", I) - I.icon_state = "blank" - QDEL_IN(I, 20) + var/turf/turf = get_turf(holder) + if(isnull(turf)) + qdel(src) + return + if(turf != oldposition) + if(istype(turf, /turf/open/space)) + var/obj/effect/particle_effect/ion_trails/trails = new /obj/effect/particle_effect/ion_trails(oldposition) + oldposition = turf + trails.setDir(holder.dir) + flick("ion_fade", trails) + trails.icon_state = "blank" + QDEL_IN(trails, 20) spawn(2) - if(src.on) - src.processing = 1 - src.start() + if(on) + processing = TRUE + start() else spawn(2) - if(src.on) - src.processing = 1 - src.start() + if(on) + processing = TRUE + start() /datum/effect_system/ion_trail_follow/proc/stop() - src.processing = 0 - src.on = 0 + processing = FALSE + on = FALSE @@ -198,39 +206,42 @@ steam.start() -- spawns the effect /datum/effect_system/steam_trail_follow var/turf/oldposition - var/processing = 1 - var/on = 1 + var/processing = TRUE + var/on = TRUE /datum/effect_system/steam_trail_follow/set_up(atom/atom) attach(atom) oldposition = get_turf(atom) /datum/effect_system/steam_trail_follow/start() - if(!src.on) - src.on = 1 - src.processing = 1 - if(src.processing) - src.processing = 0 + if(!on) + on = TRUE + processing = TRUE + if(processing) + processing = FALSE spawn(0) - if(src.number < 3) - var/obj/effect/particle_effect/steam/I = new /obj/effect/particle_effect/steam(src.oldposition) - src.number++ - src.oldposition = get_turf(holder) - I.setDir(src.holder.dir) + if(number < 3) + var/obj/effect/particle_effect/steam/trails = new /obj/effect/particle_effect/steam(oldposition) + number++ + oldposition = get_turf(holder) + if(isnull(oldposition)) + qdel(src) + return + trails.setDir(holder.dir) spawn(10) - qdel(I) + qdel(trails) number-- spawn(2) - if(src.on) - src.processing = 1 - src.start() + if(on) + processing = TRUE + start() else spawn(2) - if(src.on) - src.processing = 1 - src.start() + if(on) + processing = TRUE + start() /datum/effect_system/steam_trail_follow/proc/stop() - src.processing = 0 - src.on = 0 + processing = FALSE + on = FALSE diff --git a/code/game/objects/effects/effect_system/foam.dm b/code/game/objects/effects/effect_system/foam.dm index d0a1fa132b06..a7647dbd4489 100644 --- a/code/game/objects/effects/effect_system/foam.dm +++ b/code/game/objects/effects/effect_system/foam.dm @@ -28,7 +28,7 @@ metal = ismetal playsound(src, 'sound/effects/bubbles2.ogg', 25, 1, 5) addtimer(CALLBACK(src, PROC_REF(foam_react)), 3 + metal*3) - addtimer(CALLBACK(src, PROC_REF(foam_metal_final_react)), 120) + addtimer(CALLBACK(src, PROC_REF(foam_metal_final_react)), 40) /obj/effect/particle_effect/foam/proc/foam_react() process() diff --git a/code/game/objects/effects/effect_system/particle_effects.dm b/code/game/objects/effects/effect_system/particle_effects.dm index 69eab0442ab6..972d242bf359 100644 --- a/code/game/objects/effects/effect_system/particle_effects.dm +++ b/code/game/objects/effects/effect_system/particle_effects.dm @@ -13,42 +13,7 @@ if (PF) PF.flags_pass = PASS_OVER|PASS_AROUND|PASS_UNDER|PASS_THROUGH|PASS_MOB_THRU - //Fire -/obj/effect/particle_effect/fire //Fire that ignites mobs and deletes itself after some time, but doesn't mess with atmos. Good fire flamethrowers and incendiary stuff. - name = "fire" - icon = 'icons/effects/fire.dmi' - icon_state = "3" - var/life = 0.5 SECONDS - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -/obj/effect/particle_effect/fire/New() - if(!istype(loc, /turf)) - qdel(src) - addtimer(CALLBACK(src, PROC_REF(handle_extinguish)), life) - - setDir(pick(cardinal)) - SetLuminosity(3) - - for(var/mob/living/L in loc)//Mobs - L.fire_act() - for(var/obj/effect/alien/weeds/W in loc)//Weeds - W.fire_act() - for(var/obj/effect/alien/egg/E in loc)//Eggs - E.fire_act() - for(var/obj/structure/bed/nest/N in loc)//Nests - N.fire_act() - -/obj/effect/particle_effect/fire/proc/handle_extinguish() - if(istype(loc, /turf)) - SetLuminosity(0) - qdel(src) - -/obj/effect/particle_effect/fire/Crossed(mob/living/L) - ..() - if(isliving(L)) - L.fire_act() - - //End fire +//Water /obj/effect/particle_effect/water name = "water" diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm index 6113d3c6f766..2eb36930c542 100644 --- a/code/game/objects/effects/effect_system/smoke.dm +++ b/code/game/objects/effects/effect_system/smoke.dm @@ -174,23 +174,26 @@ /obj/effect/particle_effect/smoke/mustard name = "mustard gas" + icon = 'icons/effects/effects.dmi' icon_state = "mustard" smokeranking = SMOKE_RANK_HIGH /obj/effect/particle_effect/smoke/mustard/Move() . = ..() - for(var/mob/living/carbon/human/R in get_turf(src)) - affect(R) + for(var/mob/living/carbon/human/creature in get_turf(src)) + affect(creature) -/obj/effect/particle_effect/smoke/mustard/affect(mob/living/carbon/human/R) - ..() - R.burn_skin(0.75) - if(R.coughedtime != 1) - R.coughedtime = 1 - if(ishuman(R)) //Humans only to avoid issues - R.emote("gasp") - addtimer(VARSET_CALLBACK(R, coughedtime, 0), 2 SECONDS) - R.updatehealth() +/obj/effect/particle_effect/smoke/mustard/affect(mob/living/carbon/human/creature) + if(!istype(creature) || issynth(creature)) + return FALSE + + creature.burn_skin(0.75) + if(creature.coughedtime != 1) + creature.coughedtime = 1 + if(ishuman(creature)) //Humans only to avoid issues + creature.emote("gasp") + addtimer(VARSET_CALLBACK(creature, coughedtime, 0), 2 SECONDS) + creature.updatehealth() return ///////////////////////////////////////////// @@ -238,10 +241,60 @@ M.burn_skin(burn_damage) M.adjust_fire_stacks(applied_fire_stacks) + M.fire_reagent = new /datum/reagent/napalm/ut() M.IgniteMob() M.updatehealth() +///////////////////////////////////////////// +// CN20 Nerve Gas +///////////////////////////////////////////// + +/obj/effect/particle_effect/smoke/cn20 + name = "CN20 nerve gas" + smokeranking = SMOKE_RANK_HIGH + color = "#80c7e4" + +/obj/effect/particle_effect/smoke/cn20/Move() + . = ..() + for(var/mob/living/carbon/human/creature in get_turf(src)) + affect(creature) + +/obj/effect/particle_effect/smoke/cn20/affect(mob/living/carbon/human/creature) + if(!istype(creature) || issynth(creature) || creature.stat == DEAD) + return FALSE + if(isyautja(creature) && prob(75)) + return FALSE + + if (creature.wear_mask && (creature.wear_mask.flags_inventory & BLOCKGASEFFECT)) + return FALSE + + var/effect_amt = round(6 + amount*6) + + creature.apply_damage(12, OXY) + creature.SetEarDeafness(max(creature.ear_deaf, round(effect_amt*1.5))) //Paralysis of hearing system, aka deafness + if(!creature.eye_blind) //Eye exposure damage + to_chat(creature, SPAN_DANGER("Your eyes sting. You can't see!")) + creature.SetEyeBlind(round(effect_amt/3)) + if(creature.coughedtime != 1 && !creature.stat) //Coughing/gasping + creature.coughedtime = 1 + if(prob(50)) + creature.emote("cough") + else + creature.emote("gasp") + addtimer(VARSET_CALLBACK(creature, coughedtime, 0), 1.5 SECONDS) + if (prob(20)) + creature.apply_effect(1, WEAKEN) + + //Topical damage (neurotoxin on exposed skin) + to_chat(creature, SPAN_DANGER("Your body is going numb, almost as if paralyzed!")) + if(prob(60 + round(amount*15))) //Highly likely to drop items due to arms/hands seizing up + creature.drop_held_item() + if(ishuman(creature)) + creature.temporary_slowdown = max(creature.temporary_slowdown, 4) //One tick every two second + creature.recalculate_move_delay = TRUE + return TRUE + ////////////////////////////////////// // FLASHBANG SMOKE //////////////////////////////////// @@ -254,6 +307,17 @@ icon = 'icons/effects/effects.dmi' smokeranking = SMOKE_RANK_MED +///////////////////////////////////////// +// Acid Runner Smoke, Harmless Visuals only +///////////////////////////////////////// +/obj/effect/particle_effect/smoke/acid_runner_harmless + color = "#86B028" + time_to_live = 2 + opacity = FALSE + alpha = 200 + smokeranking = SMOKE_RANK_HARMLESS + amount = 0 + ///////////////////////////////////////// // BOILER SMOKES ///////////////////////////////////////// @@ -270,14 +334,14 @@ var/gas_damage = 20 /obj/effect/particle_effect/smoke/xeno_burn/Initialize(mapload, amount, datum/cause_data/cause_data) - var/mob/living/carbon/xenomorph/xeno = cause_data?.resolve_mob() - if (istype(xeno) && xeno.hivenumber) - hivenumber = xeno.hivenumber - - set_hive_data(src, hivenumber) - - . = ..() + if(istype(cause_data)) + var/datum/ui_state/hive_state/cause_data_hive_state = GLOB.hive_state[cause_data.faction] + var/new_hive_number = cause_data_hive_state?.hivenumber + if(new_hive_number) + hivenumber = new_hive_number + set_hive_data(src, new_hive_number) + return ..() /obj/effect/particle_effect/smoke/xeno_burn/apply_smoke_effect(turf/T) ..() @@ -374,7 +438,7 @@ if(!issynth(moob)) var/datum/effects/neurotoxin/neuro_effect = locate() in moob.effects_list if(!neuro_effect) - neuro_effect = new /datum/effects/neurotoxin(moob) + neuro_effect = new(moob, cause_data.resolve_mob()) neuro_effect.strength = effect_amt neuro_effect.duration += neuro_dose if(moob.coughedtime != 1 && !moob.stat) //Coughing/gasping @@ -528,6 +592,9 @@ /datum/effect_system/smoke_spread/phosphorus/weak smoke_type = /obj/effect/particle_effect/smoke/phosphorus/weak +/datum/effect_system/smoke_spread/cn20 + smoke_type = /obj/effect/particle_effect/smoke/cn20 + // XENO SMOKES /datum/effect_system/smoke_spread/xeno_acid diff --git a/code/game/objects/effects/landmarks/corpsespawner.dm b/code/game/objects/effects/landmarks/corpsespawner.dm index 8350e68d66a3..bcedcb85f47e 100644 --- a/code/game/objects/effects/landmarks/corpsespawner.dm +++ b/code/game/objects/effects/landmarks/corpsespawner.dm @@ -201,3 +201,9 @@ /obj/effect/landmark/corpsespawner/gladiator/burst name = "Burst Gladiator" equip_path = /datum/equipment_preset/corpse/gladiator/burst + +//FORECON + +/obj/effect/landmark/corpsespawner/forecon_spotter + name = "USCM Reconnaissance Spotter" + equip_path = /datum/equipment_preset/corpse/forecon_spotter diff --git a/code/game/objects/effects/landmarks/itemspawner.dm b/code/game/objects/effects/landmarks/itemspawner.dm index 2ab18b62ab97..6858ed6b055a 100644 --- a/code/game/objects/effects/landmarks/itemspawner.dm +++ b/code/game/objects/effects/landmarks/itemspawner.dm @@ -1,9 +1,9 @@ //Costume spawner landmarks /obj/effect/landmark/costume/random/Initialize() //costume spawner, selects a random subclass and disappears . = ..() - var/list/options = typesof(/obj/effect/landmark/costume) - /obj/effect/landmark/costume/random - var/PICK = options[rand(1, options.len)] - new PICK(src.loc) + var/list/options = subtypesof(/obj/effect/landmark/costume) - /obj/effect/landmark/costume/random + var/CHOICE = pick(options) + new CHOICE(src.loc) return INITIALIZE_HINT_QDEL //SUBCLASSES. Spawn a bunch of items and disappear likewise @@ -63,7 +63,7 @@ . = ..() new /obj/item/clothing/suit/storage/wcoat(src.loc) new /obj/item/clothing/glasses/monocle(src.loc) - var/CHOICE= pick( /obj/item/clothing/head/bowler, /obj/item/clothing/head/that) + var/CHOICE = pick(/obj/item/clothing/head/bowler, /obj/item/clothing/head/that) new CHOICE(src.loc) new /obj/item/clothing/shoes/black(src.loc) new /obj/item/weapon/pole/fancy_cane(src.loc) @@ -81,7 +81,7 @@ . = ..() new /obj/item/clothing/under/pirate(src.loc) new /obj/item/clothing/suit/pirate(src.loc) - var/CHOICE = pick( /obj/item/clothing/head/pirate , /obj/item/clothing/head/bandana ) + var/CHOICE = pick(/obj/item/clothing/head/pirate , /obj/item/clothing/head/bandana) new CHOICE(src.loc) new /obj/item/clothing/glasses/eyepatch(src.loc) return INITIALIZE_HINT_QDEL diff --git a/code/game/objects/effects/landmarks/landmarks.dm b/code/game/objects/effects/landmarks/landmarks.dm index 06f0c6822c60..0ec097f46ae3 100644 --- a/code/game/objects/effects/landmarks/landmarks.dm +++ b/code/game/objects/effects/landmarks/landmarks.dm @@ -8,10 +8,9 @@ var/invisibility_value = INVISIBILITY_MAXIMUM /obj/effect/landmark/New() - ..() tag = "landmark*[name]" invisibility = invisibility_value - return 1 + return ..() /obj/effect/landmark/Initialize(mapload, ...) . = ..() @@ -33,6 +32,29 @@ GLOB.newplayer_start -= src return ..() +/obj/effect/landmark/sim_target + name = "simulator_target" + +/obj/effect/landmark/sim_target/Initialize(mapload, ...) + . = ..() + GLOB.simulator_targets += src + +/obj/effect/landmark/sim_target/Destroy() + GLOB.simulator_targets -= src + return ..() + +/obj/effect/landmark/sim_camera + name = "simulator_camera" + color = "#FFFF00" + +/obj/effect/landmark/sim_camera/Initialize(mapload, ...) + . = ..() + GLOB.simulator_cameras += src + +/obj/effect/landmark/sim_camera/Destroy() + GLOB.simulator_cameras -= src + return ..() + /obj/effect/landmark/observer_start name = "Observer Landmark" icon = 'icons/mob/mob.dmi' @@ -82,6 +104,9 @@ /obj/effect/landmark/ert_spawns/distress_wo name = "distress_wo" +/obj/effect/landmark/ert_spawns/groundside_xeno + name = "distress_groundside_xeno" + /obj/effect/landmark/monkey_spawn name = "monkey_spawn" icon_state = "monkey_spawn" @@ -191,23 +216,25 @@ /obj/effect/landmark/yautja_teleport name = "yautja_teleport" + /// The index we registered as in mainship_yautja_desc or yautja_teleport_descs + var/desc_index /obj/effect/landmark/yautja_teleport/Initialize(mapload, ...) . = ..() - var/turf/T = get_turf(src) + var/turf/turf = get_turf(src) + desc_index = turf.loc.name + turf.loc_to_string() if(is_mainship_level(z)) GLOB.mainship_yautja_teleports += src - GLOB.mainship_yautja_desc[T.loc.name + T.loc_to_string()] = src + GLOB.mainship_yautja_desc[desc_index] = src else GLOB.yautja_teleports += src - GLOB.yautja_teleport_descs[T.loc.name + T.loc_to_string()] = src + GLOB.yautja_teleport_descs[desc_index] = src /obj/effect/landmark/yautja_teleport/Destroy() - var/turf/T = get_turf(src) GLOB.mainship_yautja_teleports -= src GLOB.yautja_teleports -= src - GLOB.mainship_yautja_desc -= T.loc.name + T.loc_to_string() - GLOB.yautja_teleport_descs -= T.loc.name + T.loc_to_string() + GLOB.mainship_yautja_desc -= desc_index + GLOB.yautja_teleport_descs -= desc_index return ..() @@ -251,9 +278,9 @@ icon_state = "leader_spawn" job = /datum/job/marine/leader/whiskey -/obj/effect/landmark/start/whiskey/rto - icon_state = "rto_spawn" - job = /datum/job/marine/rto //Need to create a WO variant in the future +/obj/effect/landmark/start/whiskey/tl + icon_state = "tl_spawn" + job = /datum/job/marine/tl //Need to create a WO variant in the future /obj/effect/landmark/start/whiskey/spec icon_state = "spec_spawn" @@ -351,6 +378,8 @@ name = "late join" icon_state = "x2" var/squad + /// What job should latejoin on this landmark + var/job /obj/effect/landmark/late_join/alpha name = "alpha late join" @@ -369,6 +398,10 @@ squad = SQUAD_MARINE_4 +/obj/effect/landmark/late_join/working_joe + name = "working joe late join" + job = JOB_WORKING_JOE + /obj/effect/landmark/late_join/Initialize(mapload, ...) . = ..() @@ -378,12 +411,16 @@ squad = GLOB.squad_mappings[squad] LAZYADD(GLOB.latejoin_by_squad[squad], src) + else if(job) + LAZYADD(GLOB.latejoin_by_job[job], src) else GLOB.latejoin += src /obj/effect/landmark/late_join/Destroy() if(squad) LAZYREMOVE(GLOB.latejoin_by_squad[squad], src) + else if(job) + LAZYREMOVE(GLOB.latejoin_by_job[job], src) else GLOB.latejoin -= src return ..() diff --git a/code/game/objects/effects/landmarks/survivor_spawner.dm b/code/game/objects/effects/landmarks/survivor_spawner.dm index 6fa1434cc777..d19bbbe49516 100644 --- a/code/game/objects/effects/landmarks/survivor_spawner.dm +++ b/code/game/objects/effects/landmarks/survivor_spawner.dm @@ -26,25 +26,39 @@ return FALSE return TRUE -/obj/effect/landmark/survivor_spawner/lv624_skylight - intro_text = list("

You are a survivor!

",\ - "You are a survivor of the attack on the colony. You worked or lived in the archaeology colony, and managed to avoid the alien attacks...until now.",\ - "You are fully aware of the xenomorph threat and are able to use this knowledge as you see fit.",\ - "Your primary objective is to heal up and survive until marines rescue you. If you want to assault the hive - adminhelp.") - story_text = "You with a small group made a run for the caves after an attack on the colony. Unfortunately during the escape you all got ambushed by one of the xenomorphs. Limping away, you and your friends found a shelter in the caves, in a place with a nice skylight above. You mustered a defence, ignoring wounds that creature dealt to you. It will be a good idea to heal up, before you attempt anything." +/obj/effect/landmark/survivor_spawner/lv624_crashed_clf + equipment = /datum/equipment_preset/survivor/clf + synth_equipment = /datum/equipment_preset/clf/synth + intro_text = list("

You are a survivor of a crash landing!

",\ + "You are NOT aware of the xenomorph threat.",\ + "Your primary objective is to heal up and survive. If you want to assault the hive - adminhelp.") + story_text = "You are a soldier of Colonial Liberation Front. Your ship received a distress signal from a planet bordering the CLF controlled space under USCM control. Ready and willing to save poor colonists from parasitic tyrants, you and your team boarded small ship called Marie Curie. Unfortunately, right before you came close to a landing zone, a glob of acid hit the ship, damaging one of the engines. Despite all the efforts of the pilot, the ship went straight into nearby mountain. You were hurt pretty badly in the crash. Dumbfounded, you rose up and noticed that one of your limbs is at a weird angle, broken. You looked at other survivors, also limping and trying to fix their broken bones." + roundstart_damage_min = 3 + roundstart_damage_max = 10 + roundstart_damage_times = 2 + + spawn_priority = SPAWN_PRIORITY_HIGH + +/obj/effect/landmark/survivor_spawner/lv624_crashed_clf_engineer + equipment = /datum/equipment_preset/clf/engineer + synth_equipment = /datum/equipment_preset/clf/synth + intro_text = list("

You are a survivor of a crash landing!

",\ + "You are NOT aware of the xenomorph threat.",\ + "Your primary objective is to heal up and survive. If you want to assault the hive - adminhelp.") + story_text = "You are a soldier of Colonial Liberation Front. Your ship received a distress signal from a planet bordering the CLF controlled space under USCM control. Ready and willing to save poor colonists from parasitic tyrants, you and your team boarded small ship called Marie Curie. Unfortunately, right before you came close to a landing zone, a glob of acid hit the ship, damaging one of the engines. Despite all the efforts of the pilot, the ship went straight into nearby mountain. You were hurt pretty badly in the crash. Dumbfounded, you rose up and noticed that one of your limbs is at a weird angle, broken. You looked at other survivors, also limping and trying to fix their broken bones." roundstart_damage_min = 3 roundstart_damage_max = 10 - roundstart_damage_times = 3 + roundstart_damage_times = 2 spawn_priority = SPAWN_PRIORITY_VERY_HIGH -/obj/effect/landmark/survivor_spawner/lv624_crashed_clf - equipment = /datum/equipment_preset/survivor/clf +/obj/effect/landmark/survivor_spawner/lv624_crashed_clf_medic + equipment = /datum/equipment_preset/clf/medic synth_equipment = /datum/equipment_preset/clf/synth intro_text = list("

You are a survivor of a crash landing!

",\ - "You are NOT aware of the xenomorph threat.",\ - "Your primary objective is to heal up and survive. If you want to assault the hive - adminhelp.") - story_text = "You are a soldier of Colonial Liberation Front. Your ship received a distress signal from a planet bordering the CLF controlled space under USCM control. Ready and willing to save poor colonists from parasitic tyrants, you and your team boarded small ship called Marie Curie. Unfortunately, right before you came close to a landing zone, a glob of acid hit the ship, damaging one of the engines. Despite all the efforts of the pilot, the ship went straight into nearby mountain. You were hurt pretty badly in the crash. Dumbfounded, you rose up and noticed that one of your limbs is at a weird angle, broken. You looked at other survivors, also limping and trying to fix their broken bones. \red You also notice that sentry turrets on the ramp of your ship beep angrily, it seems their logic circuits got damaged. They will identify you as a foe, but at least they will identify everything as a foe." + "You are NOT aware of the xenomorph threat.",\ + "Your primary objective is to heal up and survive. If you want to assault the hive - adminhelp.") + story_text = "You are a soldier of Colonial Liberation Front. Your ship received a distress signal from a planet bordering the CLF controlled space under USCM control. Ready and willing to save poor colonists from parasitic tyrants, you and your team boarded small ship called Marie Curie. Unfortunately, right before you came close to a landing zone, a glob of acid hit the ship, damaging one of the engines. Despite all the efforts of the pilot, the ship went straight into nearby mountain. You were hurt pretty badly in the crash. Dumbfounded, you rose up and noticed that one of your limbs is at a weird angle, broken. You looked at other survivors, also limping and trying to fix their broken bones." roundstart_damage_min = 3 roundstart_damage_max = 10 roundstart_damage_times = 2 @@ -53,7 +67,7 @@ /obj/effect/landmark/survivor_spawner/bigred_crashed_pmc equipment = /datum/equipment_preset/survivor/pmc - synth_equipment = /datum/equipment_preset/pmc/synth + synth_equipment = /datum/equipment_preset/synth/survivor/pmc intro_text = list("

You are a survivor of a crash landing!

",\ "You are NOT aware of the xenomorph threat.",\ "Your primary objective is to heal up and survive. If you want to assault the hive - adminhelp.") @@ -64,9 +78,35 @@ spawn_priority = SPAWN_PRIORITY_HIGH +/obj/effect/landmark/survivor_spawner/bigred_crashed_pmc_medic + equipment = /datum/equipment_preset/survivor/pmc/medic + synth_equipment = /datum/equipment_preset/synth/survivor/pmc + intro_text = list("

You are a survivor of a crash landing!

",\ + "You are NOT aware of the xenomorph threat.",\ + "Your primary objective is to heal up and survive. If you want to assault the hive - adminhelp.") + story_text = "You are a PMC medic from Weyland-Yutani. Your ship was enroute to Solaris Ridge to escort an Assistant Manager. On the way, your ship received a distress signal from the colony about an attack. Worried that it might be a CLF attack, your pilot set full speed for the colony. However, during atmospheric entry the engine failed and you fell unconcious from the G-Forces. You wake up wounded... and see that the ship has crashed onto the colony. Your squadmates lie dead beside you, but there's some missing. Perhaps they survived and moved elsewhere? You need to find out what happened to the colony, see if you can find any of your squadmates, and find a way to contact Weyland-Yutani." + roundstart_damage_min = 3 + roundstart_damage_max = 10 + roundstart_damage_times = 2 + + spawn_priority = SPAWN_PRIORITY_VERY_HIGH + +/obj/effect/landmark/survivor_spawner/bigred_crashed_pmc_engineer + equipment = /datum/equipment_preset/survivor/pmc/engineer + synth_equipment = /datum/equipment_preset/synth/survivor/pmc + intro_text = list("

You are a survivor of a crash landing!

",\ + "You are NOT aware of the xenomorph threat.",\ + "Your primary objective is to heal up and survive. If you want to assault the hive - adminhelp.") + story_text = "You are a PMC engineer from Weyland-Yutani. Your ship was enroute to Solaris Ridge to escort an Assistant Manager. On the way, your ship received a distress signal from the colony about an attack. Worried that it might be a CLF attack, your pilot set full speed for the colony. However, during atmospheric entry the engine failed and you fell unconcious from the G-Forces. You wake up wounded... and see that the ship has crashed onto the colony. Your squadmates lie dead beside you, but there's some missing. Perhaps they survived and moved elsewhere? You need to find out what happened to the colony, see if you can find any of your squadmates, and find a way to contact Weyland-Yutani." + roundstart_damage_min = 3 + roundstart_damage_max = 10 + roundstart_damage_times = 2 + + spawn_priority = SPAWN_PRIORITY_VERY_HIGH + /obj/effect/landmark/survivor_spawner/bigred_crashed_cl equipment = /datum/equipment_preset/survivor/wy/manager - synth_equipment = /datum/equipment_preset/pmc/synth + synth_equipment = /datum/equipment_preset/synth/survivor/pmc intro_text = list("

You are a survivor of a crash landing!

",\ "You are NOT aware of the xenomorph threat.",\ "Your primary objective is to heal up and survive. If you want to assault the hive - adminhelp.") @@ -77,12 +117,11 @@ spawn_priority = SPAWN_PRIORITY_VERY_HIGH - //Military Survivors// /obj/effect/landmark/survivor_spawner/lv522_forecon_tech equipment = /datum/equipment_preset/survivor/forecon/tech - spawn_priority = SPAWN_PRIORITY_MEDIUM + spawn_priority = SPAWN_PRIORITY_HIGH /obj/effect/landmark/survivor_spawner/lv522_forecon_marksman equipment = /datum/equipment_preset/survivor/forecon/marksman @@ -92,10 +131,36 @@ equipment = /datum/equipment_preset/survivor/forecon/smartgunner spawn_priority = SPAWN_PRIORITY_MEDIUM -/obj/effect/landmark/survivor_spawner/lv522_forecon_grenadier - equipment = /datum/equipment_preset/survivor/forecon/grenadier +/obj/effect/landmark/survivor_spawner/lv522_forecon_sniper + equipment = /datum/equipment_preset/survivor/forecon/sniper spawn_priority = SPAWN_PRIORITY_MEDIUM /obj/effect/landmark/survivor_spawner/lv522_forecon_squad_leader equipment = /datum/equipment_preset/survivor/forecon/squad_leader spawn_priority = SPAWN_PRIORITY_HIGH + +/obj/effect/landmark/survivor_spawner/upp/soldier + equipment = /datum/equipment_preset/survivor/upp/soldier + synth_equipment = /datum/equipment_preset/synth/survivor/upp + spawn_priority = SPAWN_PRIORITY_MEDIUM + +/obj/effect/landmark/survivor_spawner/upp_sapper + equipment = /datum/equipment_preset/survivor/upp/sapper + synth_equipment = /datum/equipment_preset/synth/survivor/upp + spawn_priority = SPAWN_PRIORITY_MEDIUM + +/obj/effect/landmark/survivor_spawner/upp_medic + equipment = /datum/equipment_preset/survivor/upp/medic + synth_equipment = /datum/equipment_preset/synth/survivor/upp + spawn_priority = SPAWN_PRIORITY_HIGH + +/obj/effect/landmark/survivor_spawner/upp_specialist + equipment = /datum/equipment_preset/survivor/upp/specialist + synth_equipment = /datum/equipment_preset/synth/survivor/upp + spawn_priority = SPAWN_PRIORITY_HIGH + +/obj/effect/landmark/survivor_spawner/squad_leader + equipment = /datum/equipment_preset/survivor/upp/squad_leader + synth_equipment = /datum/equipment_preset/synth/survivor/upp + spawn_priority = SPAWN_PRIORITY_VERY_HIGH + diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index 4f79b6b2ade5..4bf3da23dc13 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -31,17 +31,6 @@ if (PF) PF.flags_pass = PASS_OVER|PASS_THROUGH - -/obj/effect/begin - name = "begin" - icon = 'icons/obj/structures/props/stationobjs.dmi' - icon_state = "begin" - anchored = TRUE - unacidable = TRUE - - - - /obj/effect/list_container name = "list container" diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm index 6be176546148..382b92489baa 100644 --- a/code/game/objects/effects/spawners/gibspawner.dm +++ b/code/game/objects/effects/spawners/gibspawner.dm @@ -64,7 +64,7 @@ var/gibType = gibtypes[i] gib = new gibType(loc) - // Apply human species colouration to masks. + // Apply human species coloration to masks. if(fleshcolor) gib.fleshcolor = fleshcolor if(bloodcolor) diff --git a/code/game/objects/effects/spawners/random.dm b/code/game/objects/effects/spawners/random.dm index 626fd2d7a39c..4d5bf88b9e6c 100644 --- a/code/game/objects/effects/spawners/random.dm +++ b/code/game/objects/effects/spawners/random.dm @@ -174,6 +174,13 @@ icon_state = "random_kit" /obj/effect/spawner/random/supply_kit/item_to_spawn() + return pick(prob(3);/obj/item/storage/box/kit/pursuit,\ + prob(3);/obj/item/storage/box/kit/self_defense,\ + prob(3);/obj/item/storage/box/kit/mini_medic,\ + prob(2);/obj/item/storage/box/kit/mou53_sapper,\ + prob(1);/obj/item/storage/box/kit/heavy_support) + +/obj/effect/spawner/random/supply_kit/market/item_to_spawn() return pick(prob(3);/obj/item/storage/box/kit/pursuit,\ prob(3);/obj/item/storage/box/kit/mini_intel,\ prob(3);/obj/item/storage/box/kit/mini_jtac,\ @@ -460,7 +467,6 @@ /obj/item/weapon/gun/lever_action/r4t = /obj/item/ammo_magazine/lever_action, /obj/item/weapon/gun/shotgun/merc = null, /obj/item/weapon/gun/shotgun/pump/dual_tube/cmb/m3717 = null, - /obj/item/weapon/gun/shotgun/double = null ) //no ammotypes needed as it spawns random 12g boxes. Apart from the r4t. why is the r4t in the shotgun pool? fuck you, that's why. /obj/effect/spawner/random/gun/shotgun/lowchance @@ -514,7 +520,6 @@ icon_state = "loot_special" guns = list( /obj/item/weapon/gun/rifle/mar40/lmg = /obj/item/ammo_magazine/rifle/mar40/lmg, - /obj/item/weapon/gun/m60 = /obj/item/ammo_magazine/m60, /obj/item/weapon/gun/shotgun/merc = null, /obj/item/weapon/gun/launcher/rocket/anti_tank/disposable = /obj/item/prop/folded_anti_tank_sadar, /obj/item/weapon/gun/rifle/m41a = /obj/item/ammo_magazine/rifle, diff --git a/code/game/objects/effects/spawners/wo_spawners/players.dm b/code/game/objects/effects/spawners/wo_spawners/players.dm index 4fc17806a8bc..23a75adea45d 100644 --- a/code/game/objects/effects/spawners/wo_spawners/players.dm +++ b/code/game/objects/effects/spawners/wo_spawners/players.dm @@ -31,7 +31,7 @@ new Landmark(O) num ++ sleep(5) - message_admins("[num] [src]\s were spawned in at [loc.loc.name] ([loc.x],[loc.y],[loc.z]). (JMP)") + message_admins("[num] [src]\s were spawned in at [loc.loc.name] ([loc.x],[loc.y],[loc.z]). [ADMIN_JMP(loc)]") qdel(src) /obj/effect/landmark/wo_spawners/supplydrops diff --git a/code/game/objects/effects/spawners/wo_spawners/supplies.dm b/code/game/objects/effects/spawners/wo_spawners/supplies.dm index 2552e296fc6a..28f9936b972f 100644 --- a/code/game/objects/effects/spawners/wo_spawners/supplies.dm +++ b/code/game/objects/effects/spawners/wo_spawners/supplies.dm @@ -64,6 +64,7 @@ /obj/effect/landmark/wo_supplies/guns icon = 'icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi' + icon_state = "" /obj/effect/landmark/wo_supplies/guns/common amount = list(5,10) @@ -81,7 +82,7 @@ stuff = list(/obj/item/weapon/gun/smg/m39) /obj/effect/landmark/wo_supplies/guns/common/m44 - icon_state = "m44" + icon_state = "m44r" stuff = list(/obj/item/weapon/gun/revolver/m44) /obj/effect/landmark/wo_supplies/guns/common/m4a3 @@ -174,7 +175,7 @@ /obj/effect/landmark/wo_supplies/storage/belts/m39holster icon_state = "m39_holster" amount = list(1,5) - stuff = list(/obj/item/storage/large_holster/m39) + stuff = list(/obj/item/storage/belt/gun/m39) @@ -187,38 +188,41 @@ /obj/effect/landmark/wo_supplies/ammo icon = 'icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi' + icon_state = "" amount = list(1,5) /obj/effect/landmark/wo_supplies/ammo/powerpack - icon = 'icons/obj/items/storage.dmi' + icon = 'icons/obj/items/clothing/backpacks.dmi' icon_state = "powerpack" - stuff = list(/obj/item/smartgun_powerpack) + stuff = list(/obj/item/smartgun_battery) /obj/effect/landmark/wo_supplies/ammo/box + icon = 'icons/obj/items/weapons/guns/ammo_boxes/boxes_and_lids.dmi' + icon_state = "" amount = list(1,2) /obj/effect/landmark/wo_supplies/ammo/box/m41a - icon_state = "big_ammo_box" + icon_state = "base_m41" stuff = list(/obj/item/ammo_box/rounds) /obj/effect/landmark/wo_supplies/ammo/box/smg - icon_state = "big_ammo_box_m39" + icon_state = "base_m39" stuff = list(/obj/item/ammo_box/rounds/smg) /obj/effect/landmark/wo_supplies/ammo/box/m41amag - icon_state = "mag_box_m41" + icon_state = "base_m41" stuff = list(/obj/item/ammo_box/magazine) /obj/effect/landmark/wo_supplies/ammo/box/slug - icon_state = "shell_box" + icon_state = "base_slug" stuff = list(/obj/item/ammo_box/magazine/shotgun) /obj/effect/landmark/wo_supplies/ammo/box/buck - icon_state = "shell_box_buck" + icon_state = "base_buck" stuff = list(/obj/item/ammo_box/magazine/shotgun/buckshot) /obj/effect/landmark/wo_supplies/ammo/box/smgmag - icon_state = "mag_box_m39" + icon_state = "base_m39" stuff = list(/obj/item/ammo_box/magazine/m39) @@ -227,25 +231,25 @@ amount = list(0,1) /obj/effect/landmark/wo_supplies/ammo/box/rare/m41aap - icon_state = "big_ammo_box_ap" + icon_state = "base_m41" stuff = list(/obj/item/ammo_box/rounds/ap) /obj/effect/landmark/wo_supplies/ammo/box/rare/m41aapmag - icon_state = "mag_box_m41_ap" + icon_state = "base_m41" stuff = list(/obj/item/ammo_box/magazine/ap) /obj/effect/landmark/wo_supplies/ammo/box/rare/m41aincend - icon_state = "mag_box_m41_incen" + icon_state = "base_inc" stuff = list(/obj/item/ammo_box/magazine/incen) /obj/effect/landmark/wo_supplies/ammo/box/rare/m41aextend - icon_state = "mag_box_m41_ext" + icon_state = "base_m41" stuff = list(/obj/item/ammo_box/magazine/ext) /obj/effect/landmark/wo_supplies/ammo/box/rare/smgap - icon_state = "mag_box_m39_ap" + icon_state = "base_m39" stuff = list(/obj/item/ammo_box/magazine/m39/ap) /obj/effect/landmark/wo_supplies/ammo/box/rare/smgextend - icon_state = "mag_box_m39_ext" + icon_state = "base_m39" stuff = list(/obj/item/ammo_box/magazine/m39/ext) diff --git a/code/game/objects/effects/temporary_visuals.dm b/code/game/objects/effects/temporary_visuals.dm index c1c4a558fa66..4dc07b76f3cb 100644 --- a/code/game/objects/effects/temporary_visuals.dm +++ b/code/game/objects/effects/temporary_visuals.dm @@ -40,7 +40,9 @@ layer = ABOVE_XENO_LAYER var/splatter_type = "splatter" -/obj/effect/temp_visual/dir_setting/bloodsplatter/Initialize(mapload, set_dir, fx_duration) +/obj/effect/temp_visual/dir_setting/bloodsplatter/Initialize(mapload, set_dir, fx_duration, color_override) + if(color_override) + color = color_override if(IS_DIAGONAL_DIR(set_dir)) icon_state = "[splatter_type][pick(1, 2, 6)]" else @@ -76,21 +78,21 @@ /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter splatter_type = "csplatter" - color = "#77b013" + color = BLOOD_COLOR_XENO /obj/effect/temp_visual/dir_setting/bloodsplatter/human splatter_type = "csplatter" - color = "#a8180d" + color = BLOOD_COLOR_HUMAN /obj/effect/temp_visual/dir_setting/bloodsplatter/hellhound splatter_type = "csplatter" - color = "#a80d3b" + color = BLOOD_COLOR_YAUTJA /obj/effect/temp_visual/dir_setting/bloodsplatter/yautjasplatter splatter_type = "csplatter" - color = "#5A934A" + color = BLOOD_COLOR_YAUTJA_DARK /obj/effect/temp_visual/dir_setting/bloodsplatter/synthsplatter splatter_type = "csplatter" - color = "#e0e0e0" + color = BLOOD_COLOR_SYNTHETIC diff --git a/code/game/objects/explosion_recursive.dm b/code/game/objects/explosion_recursive.dm index fc9741f50ea2..1f52901c21a6 100644 --- a/code/game/objects/explosion_recursive.dm +++ b/code/game/objects/explosion_recursive.dm @@ -266,7 +266,7 @@ explosion resistance exactly as much as their health else if(ishuman(firingMob) && ishuman(M) && M.faction == firingMob.faction && !thearea?.statistic_exempt) //One human blew up another, be worried about it but do everything basically the same //special_role should be null or an empty string if done correctly M.attack_log += "\[[time_stamp()]\] [firingMob]/[firingMob.ckey] blew up [M]/[M.ckey] with \a [explosion_source] in [get_area(firingMob)]." firingMob:attack_log += "\[[time_stamp()]\] [firingMob]/[firingMob.ckey] blew up [M]/[M.ckey] with \a [explosion_source] in [get_area(firingMob)]." - var/ff_msg = "[firingMob] ([firingMob.ckey]) blew up [M] ([M.ckey]) with \a [explosion_source] in [get_area(firingMob)] (JMP) ([firingMob.client ? "PM" : "NO CLIENT"])" + var/ff_msg = "[firingMob] ([firingMob.ckey]) blew up [M] ([M.ckey]) with \a [explosion_source] in [get_area(firingMob)] [ADMIN_JMP(location_of_mob)] [ADMIN_PM(firingMob)])" var/ff_living = TRUE if(M.stat == DEAD) ff_living = FALSE diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 559a73a13a82..a98a9c25d1aa 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -781,7 +781,9 @@ cases. Override_icon_state should be a list.*/ /obj/item/proc/showoff(mob/user) - for (var/mob/M in view(user)) + var/list/viewers = get_mobs_in_view(world_view_size, user) + user.langchat_speech("holds up [src].", viewers, GLOB.all_languages, skip_language_check = TRUE, animation_style = LANGCHAT_FAST_POP, additional_styles = list("langchat_small", "emote")) + for (var/mob/M in viewers) M.show_message("[user] holds up [src]. Take a closer look.", SHOW_MESSAGE_VISIBLE) /mob/living/carbon/verb/showoff() @@ -827,6 +829,7 @@ cases. Override_icon_state should be a list.*/ UnregisterSignal(src, list( COMSIG_ITEM_DROPPED, COMSIG_ITEM_UNWIELD, + COMSIG_PARENT_QDELETING, )) UnregisterSignal(user, COMSIG_MOB_MOVE_OR_LOOK) //General reset in case anything goes wrong, the view will always reset to default unless zooming in. @@ -859,6 +862,7 @@ cases. Override_icon_state should be a list.*/ RegisterSignal(src, list( COMSIG_ITEM_DROPPED, COMSIG_ITEM_UNWIELD, + COMSIG_PARENT_QDELETING, ), PROC_REF(unzoom_dropped_callback)) RegisterSignal(user, COMSIG_MOB_MOVE_OR_LOOK, PROC_REF(zoom_handle_mob_move_or_look)) @@ -1062,3 +1066,7 @@ cases. Override_icon_state should be a list.*/ animate(attack_image, alpha = 175, transform = copy_transform.Scale(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) + +///Called by /mob/living/carbon/swap_hand() when hands are swapped +/obj/item/proc/hands_swapped(mob/living/carbon/swapper_of_hands) + return diff --git a/code/game/objects/items/artifacts.dm b/code/game/objects/items/artifacts.dm deleted file mode 100644 index a5845eaf4a97..000000000000 --- a/code/game/objects/items/artifacts.dm +++ /dev/null @@ -1,34 +0,0 @@ -/obj/item/changestone - name = "\proper an uncut ruby" - desc = "The ruby shines and catches the light, despite being uncut." - icon = 'icons/obj/items/misc.dmi' - icon_state = "changerock" - -/obj/item/changestone/proc/change(mob/target) - if(!ishuman(target)) - return FALSE - var/mob/living/carbon/human/humantarget = target - if(humantarget.flags_human_misc & HUMAN_FLAG_CHANGED) - return - if(humantarget.gender == FEMALE) - humantarget.gender = MALE - else - humantarget.gender = FEMALE - humantarget.visible_message(SPAN_NOTICE("[humantarget] changes in a way you can't quite pinpoint."), SPAN_NOTICE("You feel different.")) - humantarget.flags_human_misc |= HUMAN_FLAG_CHANGED - return TRUE - -/obj/item/changestone/attack_hand(mob/user as mob) - change(user) - . = ..() - -/obj/item/changestone/attack(mob/living/M, mob/living/user) - if(change(user)) - return - . = ..() - -/obj/item/changestone/mob_launch_collision(mob/living/L) - . = ..() - change(L) - - diff --git a/code/game/objects/items/backpack_sprayers.dm b/code/game/objects/items/backpack_sprayers.dm index 09f620c345d5..427a1dd597c7 100644 --- a/code/game/objects/items/backpack_sprayers.dm +++ b/code/game/objects/items/backpack_sprayers.dm @@ -8,6 +8,7 @@ w_class = SIZE_LARGE flags_equip_slot = SLOT_BACK flags_atom = OPENCONTAINER + possible_transfer_amounts = null//no point giving it possibility when mister can't it just confuse people volume = 500 var/fill_reagent = "water" var/spawn_empty = FALSE @@ -83,8 +84,10 @@ /obj/item/reagent_container/glass/watertank/verb/toggle_mister_verb() set name = "Toggle Mister" set category = "Object" + set src in usr toggle_mister(usr) + /obj/item/reagent_container/glass/watertank/MouseDrop(obj/over_object as obj) if(!CAN_PICKUP(usr, src)) return ..() @@ -132,7 +135,7 @@ item_state = "nozzle" w_class = SIZE_LARGE flags_equip_slot = null - amount_per_transfer_from_this = 50 + amount_per_transfer_from_this = 5 possible_transfer_amounts = null spray_size = 5 volume = 500 diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm index 55f3c32cebba..3b84d2433e88 100644 --- a/code/game/objects/items/bodybag.dm +++ b/code/game/objects/items/bodybag.dm @@ -122,25 +122,27 @@ /obj/structure/closet/bodybag/store_mobs(stored_units) // overriding this var/list/dead_mobs = list() - for(var/mob/living/M in loc) - if(M.buckled) + for(var/mob/living/mob in loc) + if(mob.buckled) continue - if(M.stat != DEAD) // covers alive mobs + if(mob.stat != DEAD) // covers alive mobs continue - if(!ishuman(M)) // all the dead other shit - dead_mobs += M + if(!ishuman(mob)) // all the dead other shit + dead_mobs += mob continue - var/mob/living/carbon/human/H = M - if(H.check_tod() || issynth(H) || H.is_revivable() && H.get_ghost()) // revivable + var/mob/living/carbon/human/human = mob + if(issynth(human)) continue - dead_mobs += M + if(human.check_tod() && human.is_revivable()) // revivable + continue + dead_mobs += mob var/mob/living/mob_to_store if(dead_mobs.len) mob_to_store = pick(dead_mobs) mob_to_store.forceMove(src) stored_units += mob_size - for(var/obj/item/limb/L in loc) - L.forceMove(src) + for(var/obj/item/limb/limb in loc) + limb.forceMove(src) return stored_units /obj/structure/closet/bodybag/attack_hand(mob/living/user) diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 04308492752c..a5e0eafe2f91 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -210,7 +210,7 @@ assignment = "Corporate Mercenary" /obj/item/card/id/pmc/New() - access = get_all_centcom_access() + access = get_access(ACCESS_LIST_WY_ALL) ..() /obj/item/card/id/pmc/ds @@ -236,7 +236,7 @@ assignment = "General" /obj/item/card/id/general/New() - access = get_all_centcom_access() + access = get_access(ACCESS_LIST_MARINE_ALL) /obj/item/card/id/provost name = "provost holo-badge" @@ -246,7 +246,7 @@ assignment = "Provost" /obj/item/card/id/provost/New() - access = get_all_centcom_access() + access = get_access(ACCESS_LIST_MARINE_ALL) /obj/item/card/id/syndicate name = "agent card" @@ -331,7 +331,7 @@ assignment = "Captain" /obj/item/card/id/captains_spare/New() - access = get_all_marine_access() + access = get_access(ACCESS_LIST_MARINE_ALL) ..() /obj/item/card/id/centcom @@ -342,7 +342,7 @@ assignment = "General" /obj/item/card/id/centcom/New() - access = get_all_centcom_access() + access = get_access(ACCESS_LIST_WY_ALL) ..() diff --git a/code/game/objects/items/circuitboards/airlock.dm b/code/game/objects/items/circuitboards/airlock.dm index 6fa986e9d17c..4de97a8e20f3 100644 --- a/code/game/objects/items/circuitboards/airlock.dm +++ b/code/game/objects/items/circuitboards/airlock.dm @@ -44,7 +44,7 @@ t1 += "
" - var/list/accesses = get_all_accesses() + var/list/accesses = get_access(ACCESS_LIST_MARINE_ALL) for (var/acc in accesses) var/aname = get_access_desc(acc) diff --git a/code/game/objects/items/circuitboards/robot_modules.dm b/code/game/objects/items/circuitboards/robot_modules.dm index 90d0b54807bb..2e5185353852 100644 --- a/code/game/objects/items/circuitboards/robot_modules.dm +++ b/code/game/objects/items/circuitboards/robot_modules.dm @@ -27,6 +27,11 @@ // src.jetpack = new /obj/item/toy/sword(src) // src.jetpack.name = "Placeholder Upgrade Item" +/obj/item/circuitboard/robot_module/Destroy() + . = ..() + QDEL_NULL(emag) + QDEL_NULL(jetpack) + QDEL_NULL_LIST(modules) /obj/item/circuitboard/robot_module/proc/respawn_consumable(mob/living/silicon/robot/R) @@ -283,11 +288,6 @@ src.modules += L src.modules += new /obj/item/reagent_container/food/drinks/shaker(src) - src.emag = new /obj/item/reagent_container/food/drinks/cans/beer(src) - - emag.create_reagents(50) - emag.reagents.add_reagent("beer2", 50) - src.emag.name = "Mickey Finn's Special Brew" /obj/item/circuitboard/robot_module/butler/add_languages(mob/living/silicon/robot/R) //full set of languages @@ -308,7 +308,6 @@ src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/energy/sword(src) -// src.modules += new /obj/item/weapon/gun/energy/pulse_rifle/destroyer(src) /obj/item/circuitboard/robot_module/drone name = "drone module" diff --git a/code/game/objects/items/devices/RCD.dm b/code/game/objects/items/devices/RCD.dm index 28d462ad1048..55965533c48b 100644 --- a/code/game/objects/items/devices/RCD.dm +++ b/code/game/objects/items/devices/RCD.dm @@ -35,7 +35,7 @@ RCD spark_system.attach(src) return -/obj/item/device/rcd/Initialize() +/obj/item/device/rcd/Destroy() QDEL_NULL(spark_system) return ..() diff --git a/code/game/objects/items/devices/binoculars.dm b/code/game/objects/items/devices/binoculars.dm index 1b14c802d239..a4589fb1dd78 100644 --- a/code/game/objects/items/devices/binoculars.dm +++ b/code/game/objects/items/devices/binoculars.dm @@ -32,6 +32,10 @@ zoom(user, 11, 12) +/obj/item/device/binoculars/dropped(/obj/item/item, mob/user) + . = ..() + on_unset_interaction(user) + /obj/item/device/binoculars/on_set_interaction(mob/user) flags_atom |= RELAY_CLICK @@ -97,27 +101,30 @@ return TRUE return ..() -/obj/item/device/binoculars/range/handle_click(mob/living/carbon/human/user, atom/A, list/mods) +/obj/item/device/binoculars/range/handle_click(mob/living/carbon/human/user, atom/targeted_atom, list/mods) if(!istype(user)) return if(mods["ctrl"]) + if(user.stat != CONSCIOUS) + to_chat(user, SPAN_WARNING("You cannot use [src] while incapacitated.")) + return FALSE if(SEND_SIGNAL(user, COMSIG_BINOCULAR_HANDLE_CLICK, src)) return FALSE if(mods["click_catcher"]) return FALSE - if(user.z != A.z) + if(user.z != targeted_atom.z && !coord) to_chat(user, SPAN_WARNING("You cannot get a direct laser from where you are.")) return FALSE - if(!(is_ground_level(A.z))) + if(!(is_ground_level(targeted_atom.z))) to_chat(user, SPAN_WARNING("INVALID TARGET: target must be on the surface.")) return FALSE if(user.sight & SEE_TURFS) - var/list/turf/path = getline2(user, A, include_from_atom = FALSE) + var/list/turf/path = getline2(user, targeted_atom, include_from_atom = FALSE) for(var/turf/T in path) if(T.opacity) to_chat(user, SPAN_WARNING("There is something in the way of the laser!")) return FALSE - acquire_target(A, user) + acquire_target(targeted_atom, user) return TRUE return FALSE @@ -126,7 +133,7 @@ QDEL_NULL(coord) to_chat(user, SPAN_WARNING("You stop lasing.")) -/obj/item/device/binoculars/range/proc/acquire_target(atom/A, mob/living/carbon/human/user) +/obj/item/device/binoculars/range/proc/acquire_target(atom/targeted_atom, mob/living/carbon/human/user) set waitfor = 0 if(coord) @@ -147,10 +154,10 @@ las_name = S.name // Safety check - prevent targeting items in containers (notably your equipment/inventory) - if(A.z == 0) + if(targeted_atom.z == 0) return - var/turf/TU = get_turf(A) + var/turf/TU = get_turf(targeted_atom) if(!istype(TU) || user.action_busy) return playsound(src, 'sound/effects/nightvision.ogg', 35) @@ -250,7 +257,7 @@ return range_mode = !range_mode - to_chat(user, SPAN_NOTICE("You switch [src] to [range_mode? "range finder" : "CAS marking"] range_mode.")) + to_chat(user, SPAN_NOTICE("You switch [src] to [range_mode? "range finder" : "CAS marking"] mode.")) update_icon() playsound(usr, 'sound/machines/click.ogg', 15, 1) @@ -263,7 +270,7 @@ if(coord) qdel(coord) -/obj/item/device/binoculars/range/designator/acquire_target(atom/A, mob/living/carbon/human/user) +/obj/item/device/binoculars/range/designator/acquire_target(atom/targeted_atom, mob/living/carbon/human/user) set waitfor = 0 if(laser || coord) @@ -288,11 +295,11 @@ las_name = las_name + "-[tracking_id]" // Safety check - prevent targeting atoms in containers (notably your equipment/inventory) - if(A.z == 0) + if(targeted_atom.z == 0) return - var/turf/TU = get_turf(A) - var/area/targ_area = get_area(A) + var/turf/TU = get_turf(targeted_atom) + var/area/targ_area = get_area(targeted_atom) if(!istype(TU)) return var/is_outside = FALSE switch(targ_area.ceiling) @@ -330,7 +337,7 @@ laser = LT var/turf/userloc = get_turf(user) - msg_admin_niche("Laser target [las_name] has been designated by [key_name(user, 1)] at ([TU.x], [TU.y], [TU.z]). (JMP SRC) (JMP LOC)") + msg_admin_niche("Laser target [las_name] has been designated by [key_name(user, 1)] at ([TU.x], [TU.y], [TU.z]). [ADMIN_JMP(userloc)]") log_game("Laser target [las_name] has been designated by [key_name(user, 1)] at ([TU.x], [TU.y], [TU.z]).") playsound(src, 'sound/effects/binoctarget.ogg', 35) @@ -414,12 +421,12 @@ if(istype(human) && !human.is_mob_incapacitated() && !human.lying && (holder_item == human.r_hand || holder_item || human.l_hand)) return TRUE -/datum/action/item_action/specialist/spotter_target/proc/use_ability(atom/targetted_atom) +/datum/action/item_action/specialist/spotter_target/proc/use_ability(atom/targeted_atom) var/mob/living/carbon/human/human = owner - if(!istype(targetted_atom, /mob/living)) + if(!istype(targeted_atom, /mob/living)) return - var/mob/living/target = targetted_atom + var/mob/living/target = targeted_atom if(target.stat == DEAD || target == human) return @@ -431,7 +438,6 @@ if(!check_can_use(target)) return - COOLDOWN_START(designator, spotting_cooldown, designator.spotting_cooldown_delay) human.face_atom(target) ///Add a decisecond to the default 1.5 seconds for each two tiles to hit. @@ -466,6 +472,7 @@ qdel(laser_beam) REMOVE_TRAIT(target, TRAIT_SPOTTER_LAZED, TRAIT_SOURCE_EQUIPMENT(designator.tracking_id)) return + target.overlays -= I designator.is_spotting = FALSE designator.update_icon() @@ -487,6 +494,7 @@ to_chat(human, SPAN_WARNING("\The [target] is too close to laze!")) return FALSE + COOLDOWN_START(designator, spotting_cooldown, designator.spotting_cooldown_delay) return TRUE //ADVANCED LASER DESIGNATER, was used for WO. @@ -566,8 +574,8 @@ return return -/obj/item/device/binoculars/designator/proc/lasering(mob/living/carbon/human/user, atom/A, params) - if(istype(A,/atom/movable/screen)) +/obj/item/device/binoculars/designator/proc/lasering(mob/living/carbon/human/user, atom/targeted_atom, params) + if(istype(targeted_atom,/atom/movable/screen)) return FALSE if(user.stat) zoom(user) @@ -575,7 +583,7 @@ return FALSE if(lasing) return FALSE - target = A + target = targeted_atom if(!istype(target)) return FALSE if(target.z != user.z) @@ -586,7 +594,7 @@ return FALSE var/turf/SS = get_turf(src) //Stand Still, not what you're thinking. - var/turf/T = get_turf(A) + var/turf/T = get_turf(targeted_atom) if(!las_mode) to_chat(user, SPAN_WARNING("The Laser Designator is currently off!")) @@ -597,7 +605,7 @@ return 0 to_chat(user, SPAN_BOLDNOTICE(" You start lasing the target area.")) - message_admins("ALERT: [user] ([user.key]) IS CURRENTLY LASING A TARGET: CURRENT MODE [las_mode], at ([T.x],[T.y],[T.z]) (JMP).") // Alert all the admins to this asshole. Added the jmp command from the explosion code. + message_admins("ALERT: [user] ([user.key]) IS CURRENTLY LASING A TARGET: CURRENT MODE [las_mode], at ([T.x],[T.y],[T.z]) [ADMIN_JMP(T)].") // Alert all the admins to this asshole. Added the jmp command from the explosion code. var/obj/effect/las_target/lasertarget = new(T.loc) if(las_mode == 1 && !las_r) // Heres our IR bomb code. lasing = TRUE @@ -638,7 +646,7 @@ return else if(las_mode == 2 && !las_b) //Give them the option for mortar fire. lasing = TRUE - lasertarget.icon_state = "laz_b" + lasertarget.icon_state = "las_b" las_b = 2 playsound(src, 'sound/effects/nightvision.ogg', 35) sleep(50) @@ -646,7 +654,7 @@ lasing = FALSE las_b = 0 return 0 - lasertarget.icon_state = "lazlock_b" + lasertarget.icon_state = "laslock_b" var/HE_power = 0 var/con_power = 0 if(!plane_toggle) @@ -671,8 +679,8 @@ addtimer(VARSET_CALLBACK(src, las_b, FALSE), 5 MINUTES) return -/obj/item/device/binoculars/designator/afterattack(atom/A as mob|obj|turf, mob/user as mob, params) // This is actually WAY better, espically since its fucken already in the code. - lasering(user, A, params) +/obj/item/device/binoculars/designator/afterattack(atom/targeted_atom as mob|obj|turf, mob/user as mob, params) // This is actually WAY better, espically since its fucken already in the code. + lasering(user, targeted_atom, params) return /obj/effect/las_target diff --git a/code/game/objects/items/devices/cictablet.dm b/code/game/objects/items/devices/cictablet.dm index a25528dcccbf..b2707a20aa90 100644 --- a/code/game/objects/items/devices/cictablet.dm +++ b/code/game/objects/items/devices/cictablet.dm @@ -53,6 +53,7 @@ data["faction"] = announcement_faction data["cooldown_message"] = cooldown_between_messages + data["distresstimelock"] = DISTRESS_TIME_LOCK return data @@ -63,7 +64,6 @@ data["evac_status"] = EvacuationAuthority.evac_status data["endtime"] = announcement_cooldown data["distresstime"] = distress_cooldown - data["distresstimelock"] = DISTRESS_TIME_LOCK data["worldtime"] = world.time return data @@ -145,6 +145,8 @@ log_game("[key_name(usr)] has called for an emergency evacuation.") message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") . = TRUE if("distress") @@ -158,7 +160,7 @@ for(var/client/C in GLOB.admins) if((R_ADMIN|R_MOD) & C.admin_holder.rights) playsound_client(C,'sound/effects/sos-morse-code.ogg',10) - message_admins("[key_name(usr)] has requested a Distress Beacon! (Mark) (SEND) (DENY) (JMP) (RPLY)") + message_admins("[key_name(usr)] has requested a Distress Beacon! [CC_MARK(usr)] (SEND) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM Central Command.")) COOLDOWN_START(src, distress_cooldown, COOLDOWN_COMM_REQUEST) return TRUE diff --git a/code/game/objects/items/devices/cloaking.dm b/code/game/objects/items/devices/cloaking.dm index 64ea7189cd68..05e7786744e2 100644 --- a/code/game/objects/items/devices/cloaking.dm +++ b/code/game/objects/items/devices/cloaking.dm @@ -23,10 +23,8 @@ spark_system.attach(src) /obj/item/device/chameleon/Destroy() - if(spark_system) - qdel(spark_system) - spark_system = null - . = ..() + QDEL_NULL(spark_system) + return ..() /obj/item/device/chameleon/dropped(mob/user) disrupt(user) diff --git a/code/game/objects/items/devices/coins.dm b/code/game/objects/items/devices/coins.dm index 9af5f855b0fa..6ab79e3216d4 100644 --- a/code/game/objects/items/devices/coins.dm +++ b/code/game/objects/items/devices/coins.dm @@ -30,7 +30,7 @@ black_market_value = 25 /obj/item/coin/copper - name = "gold coin" + name = "copper coin" desc = "A familiar, but cheap form of currency." icon_state = "coin_copper" black_market_value = 30 @@ -43,7 +43,7 @@ /obj/item/coin/iron name = "iron coin" - desc = "You fear this might get rusty." + desc = "A coin made of sturdy iron. You fear this might become rusty." icon_state = "coin_iron" black_market_value = 15 @@ -55,13 +55,13 @@ /obj/item/coin/uranium name = "uranium coin" - desc = "Don't touch it!" + desc = "A radioactive coin. Don't touch it!" icon_state = "coin_uranium" black_market_value = 35 /obj/item/coin/platinum name = "platinum coin" - desc = "This is quite valuable." + desc = "A coin made of shiny platinum. It is quite valuable." icon_state = "coin_platinum" black_market_value = 35 @@ -73,7 +73,7 @@ /obj/item/coin/chitin name = "chitin coin" - desc = "Durable chitin pressed into a coin. Why would anyone make this?" + desc = "Durable alien chitin pressed into a coin. There are much better uses for chitin..." icon_state = "coin_chitin" black_market_value = 35 diff --git a/code/game/objects/items/devices/data_detector.dm b/code/game/objects/items/devices/data_detector.dm index ad1b9c3bb05f..6a358ec09bd8 100644 --- a/code/game/objects/items/devices/data_detector.dm +++ b/code/game/objects/items/devices/data_detector.dm @@ -17,6 +17,7 @@ /obj/structure/machinery/computer/objective, /obj/item/limb/head/synth, ) + var/detect_empty_vial_boxes = FALSE /obj/item/device/motiondetector/intel/get_help_text() . = "Green indicators on your HUD will show the location of intelligence objects detected by the scanner. Has two modes: slow long-range [SPAN_HELPFUL("(14 tiles)")] and fast short-range [SPAN_HELPFUL("(7 tiles)")]." @@ -42,10 +43,16 @@ var/detected for(var/DT in objects_to_detect) if(istype(I, DT)) + if(!detect_empty_vial_boxes && istype(I, /obj/item/storage/fancy/vials/random)) + if(!I.contents) + continue detected = TRUE if(I.contents) for(var/obj/item/CI in I.contents) if(istype(CI, DT)) + if(!detect_empty_vial_boxes && istype(I, /obj/item/storage/fancy/vials/random)) + if(!I.contents) + continue detected = TRUE break if(human_user && detected) @@ -69,6 +76,9 @@ for(var/obj/I in M.contents_twice()) for(var/DT in objects_to_detect) if(istype(I, DT)) + if(!detect_empty_vial_boxes && istype(I, /obj/item/storage/fancy/vials/random)) + if(!I.contents) + continue detected = TRUE break if(detected) diff --git a/code/game/objects/items/devices/defibrillator.dm b/code/game/objects/items/devices/defibrillator.dm index e873fa893d62..30d0467a9b76 100644 --- a/code/game/objects/items/devices/defibrillator.dm +++ b/code/game/objects/items/devices/defibrillator.dm @@ -11,7 +11,10 @@ w_class = SIZE_MEDIUM var/blocked_by_suit = TRUE - var/heart_damage_to_deal = 5 + /// Min damage defib deals to victims' heart + var/min_heart_damage_dealt = 3 + /// Max damage defib deals to victims' heart + var/max_heart_damage_dealt = 5 var/ready = 0 var/damage_heal_threshold = 12 //This is the maximum non-oxy damage the defibrillator will heal to get a patient above -100, in all categories var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread @@ -191,8 +194,11 @@ shock_cooldown = world.time + 10 //1 second cooldown before you can shock again var/datum/internal_organ/heart/heart = H.internal_organs_by_name["heart"] + /// Has the defib already caused the chance of heart damage, to not potentially double up later + var/heart_already_damaged = FALSE if(heart && prob(25)) - heart.take_damage(heart_damage_to_deal, TRUE) //Allow the defibrillator to possibly worsen heart damage. Still rare enough to just be the "clone damage" of the defib + heart.take_damage(rand(min_heart_damage_dealt, max_heart_damage_dealt), TRUE) // Make death and revival leave lasting consequences + heart_already_damaged = TRUE if(!H.is_revivable()) playsound(get_turf(src), 'sound/items/defib_failed.ogg', 25, 0) @@ -228,7 +234,11 @@ user.visible_message(SPAN_NOTICE("[icon2html(src, viewers(src))] \The [src] beeps: Defibrillation successful.")) playsound(get_turf(src), 'sound/items/defib_success.ogg', 25, 0) user.track_life_saved(user.job) + user.life_revives_total++ H.handle_revive() + if(heart && !heart_already_damaged) + heart.take_damage(rand(min_heart_damage_dealt, max_heart_damage_dealt), TRUE) // Make death and revival leave lasting consequences + to_chat(H, SPAN_NOTICE("You suddenly feel a spark and your consciousness returns, dragging you back to the mortal plane.")) if(H.client?.prefs.toggles_flashing & FLASH_CORPSEREVIVE) window_flash(H.client) @@ -238,13 +248,14 @@ /obj/item/device/defibrillator/compact_adv name = "advanced compact defibrillator" - desc = "An advanced compact defibrillator that trades capacity for strong immediate power. Ignores armor and heals strongly and quickly, at the cost of very low charge." + desc = "An advanced compact defibrillator that trades capacity for strong immediate power. Ignores armor and heals strongly and quickly, at the cost of very low charge. It does not damage the heart." icon = 'icons/obj/items/experimental_tools.dmi' icon_state = "compact_defib" item_state = "defib" w_class = SIZE_MEDIUM blocked_by_suit = FALSE - heart_damage_to_deal = 0 + min_heart_damage_dealt = 0 + max_heart_damage_dealt = 0 damage_heal_threshold = 40 charge_cost = 198 diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index a4ddaf71449b..9bcda4a82bbb 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -58,8 +58,9 @@ if(!toggleable) to_chat(user, SPAN_WARNING("You cannot toggle \the [src.name] on or off.")) return FALSE + if(!isturf(user.loc)) - to_chat(user, "You cannot turn the light on while in [user.loc].") //To prevent some lighting anomalities. + to_chat(user, SPAN_WARNING("You cannot turn the light [on ? "off" : "on"] while in [user.loc].")) //To prevent some lighting anomalies. return FALSE on = !on @@ -285,7 +286,7 @@ /obj/item/device/flashlight/flare/Initialize() . = ..() - fuel = rand(1600 SECONDS, 2000 SECONDS) + fuel = rand(9.5 MINUTES, 10.5 MINUTES) /obj/item/device/flashlight/flare/update_icon() overlays?.Cut() @@ -415,7 +416,7 @@ /obj/item/device/flashlight/flare/on/illumination/Initialize() . = ..() - fuel = rand(800 SECONDS, 1000 SECONDS) // Half the duration of a flare, but justified since it's invincible + fuel = rand(4.5 MINUTES, 5.5 MINUTES) // Half the duration of a flare, but justified since it's invincible /obj/item/device/flashlight/flare/on/illumination/update_icon() return @@ -429,7 +430,7 @@ /obj/item/device/flashlight/flare/on/starshell_ash name = "burning star shell ash" - desc = "Bright burning ash from a Star Shell 40mm. Don't touch, oh it'll burn ya'." + desc = "Bright burning ash from a Star Shell 40mm. Don't touch, or it'll burn ya'." icon_state = "starshell_ash" brightness_on = 7 anchored = TRUE//can't be picked up @@ -440,7 +441,7 @@ if(mapload) return INITIALIZE_HINT_QDEL . = ..() - fuel = rand(5 SECONDS, 60 SECONDS) + fuel = rand(30 SECONDS, 60 SECONDS) /obj/item/device/flashlight/flare/on/illumination/chemical name = "chemical light" @@ -524,8 +525,9 @@ anchored = TRUE if(activate_message) visible_message(SPAN_DANGER("[src]'s flame reaches full strength. It's fully active now."), null, 5) - msg_admin_niche("Flare target [src] has been activated by [key_name(user, 1)] at ([x], [y], [z]). (JMP LOC)") - log_game("Flare target [src] has been activated by [key_name(user, 1)] at ([x], [y], [z]).") + var/turf/target_turf = get_turf(src) + msg_admin_niche("Flare target [src] has been activated by [key_name(user, 1)] at ([target_turf.x], [target_turf.y], [target_turf.z]). (JMP LOC)") + log_game("Flare target [src] has been activated by [key_name(user, 1)] at ([target_turf.x], [target_turf.y], [target_turf.z]).") return TRUE /obj/item/device/flashlight/flare/signal/attack_hand(mob/user) @@ -540,7 +542,7 @@ STOP_PROCESSING(SSobj, src) if(signal) cas_groups[faction].remove_signal(signal) - qdel(signal) + QDEL_NULL(signal) return ..() /obj/item/device/flashlight/flare/signal/turn_off() diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm index 6a01dfdba9da..c6da7d354054 100644 --- a/code/game/objects/items/devices/megaphone.dm +++ b/code/game/objects/items/devices/megaphone.dm @@ -28,6 +28,11 @@ var/message = tgui_input_text(user, "Shout a message?", "Megaphone", multiline = TRUE) if(!message) return + // we know user is a human now, so adjust user for this check + var/mob/living/carbon/human/humanoid = user + if(humanoid.speech_problem_flag) + var/list/new_message = humanoid.handle_speech_problems(message) + message = new_message[1] message = capitalize(message) log_admin("[key_name(user)] used a megaphone to say: >[message]<") diff --git a/code/game/objects/items/devices/motion_detector.dm b/code/game/objects/items/devices/motion_detector.dm index d2e018268e08..dd0c5d45eda4 100644 --- a/code/game/objects/items/devices/motion_detector.dm +++ b/code/game/objects/items/devices/motion_detector.dm @@ -22,6 +22,7 @@ item_state = "motion_detector" flags_atom = FPRINT| CONDUCT flags_equip_slot = SLOT_WAIST + inherent_traits = list(TRAIT_ITEM_NOT_IMPLANTABLE) var/list/blip_pool = list() var/detector_range = 14 var/detector_mode = MOTION_DETECTOR_LONG @@ -228,11 +229,14 @@ if(human_user) show_blip(human_user, M) - for(var/mob/hologram/queen/Q in GLOB.hologram_list) - if(Q.z != cur_turf.z || !(range_bounds.contains_atom(Q))) continue + for(var/mob/hologram/holo as anything in GLOB.hologram_list) + if(!holo.motion_sensed) + continue + if(holo.z != cur_turf.z || !(range_bounds.contains_atom(holo))) + continue ping_count++ if(human_user) - show_blip(human_user, Q, "queen_eye") + show_blip(human_user, holo, "queen_eye") if(ping_count > 0) playsound(loc, pick('sound/items/detector_ping_1.ogg', 'sound/items/detector_ping_2.ogg', 'sound/items/detector_ping_3.ogg', 'sound/items/detector_ping_4.ogg'), 60, 0, 7, 2) @@ -310,6 +314,16 @@ desc = "A device that usually picks up non-USCM signals, but this one's been hacked to detect all non-freelancer movement instead. Fight fire with fire!" iff_signal = FACTION_MERCENARY +/obj/item/device/motiondetector/hacked/pmc + name = "corporate motion detector" + desc = "A device that usually picks up non-USCM signals, but this one's been reprogrammed to detect all non-PMC movement instead. Very corporate." + iff_signal = FACTION_PMC + +/obj/item/device/motiondetector/hacked/dutch + name = "hacked motion detector" + desc = "A device that usually picks up non-USCM signals, but this one's been hacked to detect all non-Dutch's Dozen movement instead. Fight fire with fire!" + iff_signal = FACTION_DUTCH + /obj/item/device/motiondetector/hacked/contractor name = "modified motion detector" desc = "A device that usually picks up non-USCM signals, but this one's been modified with after-market IFF sensors to detect all non-Vanguard's Arrow Incorporated movement instead. Fight fire with fire!" diff --git a/code/game/objects/items/devices/portable_vendor.dm b/code/game/objects/items/devices/portable_vendor.dm index a9e587c43dfb..65e2128a02c0 100644 --- a/code/game/objects/items/devices/portable_vendor.dm +++ b/code/game/objects/items/devices/portable_vendor.dm @@ -14,18 +14,22 @@ throw_range = 4 w_class = SIZE_LARGE - var/req_role = "" //to be compared with assigned_role to only allow those to use that machine. + /// to be compared with assigned_role to only allow those to use that machine. + var/req_role = "" var/points = 40 var/max_points = 50 var/use_points = TRUE - var/fabricating = 0 - var/broken = 0 + var/fabricating = FALSE + var/broken = FALSE + var/list/purchase_log = list() var/list/listed_products = list() - var/special_prod_time_lock //needs to be a time define - var/list/special_prods //list of typepaths + /// needs to be a time define + var/special_prod_time_lock + /// list of typepaths + var/list/special_prods /obj/item/device/portable_vendor/attack_hand(mob/user) if(loc == user) @@ -67,119 +71,108 @@ user.set_interaction(src) - ui_interact(user) - - -/obj/item/device/portable_vendor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0) - - if(!ishuman(user)) return + tgui_interact(user) - var/list/display_list = list() - - - for(var/i in 1 to listed_products.len) - var/list/myprod = listed_products[i] - var/p_name = myprod[1] - var/p_cost = myprod[2] - if(p_cost > 0) - p_name += " ([p_cost] points)" +/obj/item/device/portable_vendor/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortableVendor", "[src]") + ui.open() - var/prod_available = FALSE - //var/avail_flag = myprod[4] - if(points >= p_cost || !use_points) - prod_available = TRUE +/obj/item/device/portable_vendor/ui_data(mob/user) + . = ..() - //place in main list, name, cost, available or not, color. - display_list += list(list("prod_index" = i, "prod_name" = p_name, "prod_available" = prod_available, "prod_color" = myprod[4], "prod_desc" = myprod[5])) + var/list/available_items = list() + for(var/index in 1 to length(listed_products)) + var/product = listed_products[index] + var/name = product[1] + var/cost = product[2] + var/color = product[4] + var/description = product[5] - var/list/data = list( - "vendor_name" = name, - "show_points" = use_points, - "current_points" = round(points), - "max_points" = max_points, - "displayed_records" = display_list, - ) + if(cost > 0) + name += " ([cost] points)" - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + var/available = points >= product[2] || !use_points + available_items += list(list("index" = index, "name" = name, "cost" = cost, "available" = available, "color" = color, "description" = description)) - if (!ui) - ui = new(user, src, ui_key, "portable_vendor.tmpl", name , 600, 700) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(0) + .["vendor_name"] = name + .["show_points"] = use_points + .["current_points"] = round(points) + .["max_points"] = max_points + .["displayed_records"] = available_items -/obj/item/device/portable_vendor/Topic(href, href_list) +/obj/item/device/portable_vendor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return + + switch(action) + if("vend") + vend(text2num(params["choice"]), ui.user) + +/obj/item/device/portable_vendor/proc/vend(choice, mob/user) if(broken) return - if(usr.is_mob_incapacitated()) + + if(user.is_mob_incapacitated()) return - if (in_range(src, usr) && ishuman(usr)) - usr.set_interaction(src) - if (href_list["vend"]) + if(!(in_range(src, user) || ishuman(user))) + return - if(!allowed(usr)) - to_chat(usr, SPAN_WARNING("Access denied.")) - return + user.set_interaction(src) - var/mob/living/carbon/human/H = usr - var/obj/item/card/id/I = H.wear_id - if(!istype(I)) //not wearing an ID - to_chat(H, SPAN_WARNING("Access denied. No ID card detected")) - return + if(!allowed(user)) + to_chat(user, SPAN_WARNING("Access denied.")) + return - if(I.registered_name != H.real_name) - to_chat(H, SPAN_WARNING("Wrong ID card owner detected.")) - return + var/mob/living/carbon/human/human_user = user + var/obj/item/card/id/id = human_user.get_idcard() - if(req_role && I.rank != req_role) - to_chat(H, SPAN_WARNING("This device isn't for you.")) - return + if(!istype(id)) + to_chat(human_user, SPAN_WARNING("Access denied. No ID card detected.")) + return - var/idx=text2num(href_list["vend"]) + if(req_role && req_role != id.rank) + to_chat(human_user, SPAN_WARNING("This device isn't for you.")) - var/list/L = listed_products[idx] - var/cost = L[2] + var/list/product = listed_products[choice] - if(use_points && points < cost) - to_chat(H, SPAN_WARNING("Not enough points.")) - return + var/cost = product[2] + if(use_points && points < cost) + to_chat(human_user, SPAN_WARNING("Not enough points.")) + return - var/turf/T = get_turf(loc) - if(length(T.contents) > 25) - to_chat(H, SPAN_WARNING("The floor is too cluttered, make some space.")) - return + var/turf/current_turf = get_turf(src) + if(length(current_turf.contents) > 25) + to_chat(human_user, SPAN_WARNING("The floor is too cluttered, make some space.")) + return - if(special_prod_time_lock) - if(L[3] in special_prods) - if(world.time < SSticker.mode.round_time_lobby + special_prod_time_lock) - to_chat(usr, SPAN_WARNING("\The [src] is still fabricating \the [L[1]]. Please wait another [round((SSticker.mode.round_time_lobby + special_prod_time_lock-world.time)/600)] minutes before trying again.")) - return + if(special_prod_time_lock && (product[3] in special_prods)) + if(ROUND_TIME < special_prod_time_lock) + to_chat(usr, SPAN_WARNING("[src] is still fabricating [product[1]]. Please wait another [round((SSticker.mode.round_time_lobby + special_prod_time_lock-world.time)/600)] minutes before trying again.")) + return - if(use_points) - points -= cost + if(use_points) + points -= cost - purchase_log += "[key_name(usr)] bought [L[1]]." + purchase_log += "[key_name(usr)] bought [product[1]]." - playsound(src, "sound/machines/fax.ogg", 5) - fabricating = 1 - update_overlays() - spawn(30) - var/type_p = L[3] - var/obj/IT = new type_p(get_turf(src)) - H.put_in_any_hand_if_possible(IT) - fabricating = 0 - update_overlays() + playsound(src, "sound/machines/fax.ogg", 5) + fabricating = TRUE + update_overlays() - src.add_fingerprint(usr) - ui_interact(usr) //updates the nanoUI window + addtimer(CALLBACK(src, PROC_REF(spawn_product), product[3], user), 3 SECONDS) +/obj/item/device/portable_vendor/proc/spawn_product(typepath, mob/user) + var/obj/new_item = new typepath(get_turf(src)) + user.put_in_any_hand_if_possible(new_item) + fabricating = FALSE + update_overlays() /obj/item/device/portable_vendor/proc/update_overlays() if(overlays) overlays.Cut() @@ -194,8 +187,7 @@ /obj/item/device/portable_vendor/process() points = min(max_points, points+0.05) - -/obj/item/device/portable_vendor/New() +/obj/item/device/portable_vendor/Initialize() . = ..() START_PROCESSING(SSobj, src) update_overlays() @@ -246,7 +238,7 @@ special_prod_time_lock = CL_BRIEFCASE_TIME_LOCK special_prods = list(/obj/item/implanter/neurostim, /obj/item/reagent_container/hypospray/autoinjector/ultrazine/liaison) - req_access = list(ACCESS_WY_CORPORATE) + req_access = list(ACCESS_WY_EXEC) req_role = JOB_CORPORATE_LIAISON listed_products = list( list("INCENTIVES", 0, null, null, null), @@ -278,4 +270,7 @@ list("MISC", 0, null, null, null), list("Hollow Cane", 15, /obj/item/weapon/pole/fancy_cane/this_is_a_knife, "white", "A hollow cane that can store any commonplace sharp weaponry. Said weapon not included."), + + list("AMMO", 0, null, null, null), + list("ES-4 stun magazine", 10, /obj/item/ammo_magazine/pistol/es4, "white", "Holds 19 rounds of specialized Conductive 9mm."), ) diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index 77b1fee9ec78..d724e1cec10f 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -15,8 +15,6 @@ icon_state = "binary_key" translate_apollo = TRUE - - /obj/item/device/encryptionkey/public name = "Public Radio Encryption Key" icon_state = "stripped_key" @@ -28,11 +26,30 @@ icon_state = "stripped_key" channels = list(RADIO_CHANNEL_COLONY= TRUE) +// MARINE ONE CHANNEL + +/obj/item/device/encryptionkey/command + name = "Command Encryption Key" + icon_state = "cap_key" + channels = list(RADIO_CHANNEL_COMMAND = TRUE) + +/obj/item/device/encryptionkey/jtac + name = "\improper JTAC Radio Encryption Key" + icon_state = "jtac_key" + channels = list(RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_REQ = TRUE) + +/obj/item/device/encryptionkey/intel + name = "\improper Intel Radio Encryption Key" + icon_state = "jtac_key" + channels = list(RADIO_CHANNEL_INTEL = TRUE) + +//MARINE ENCRYPTION KEYS + /obj/item/device/encryptionkey/ai_integrated name = "AI Integrated Encryption Key" desc = "Integrated encryption key" icon_state = "cap_key" - channels = list(RADIO_CHANNEL_ALMAYER = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_ALMAYER = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/sentry_laptop name = "Sentry Network Status Encryption Key" @@ -40,80 +57,93 @@ icon_state = "eng_key" channels = list(RADIO_CHANNEL_SENTRY = TRUE) +// MARINE COMMAND + +/obj/item/device/encryptionkey/cmpcom/cdrcom + name = "\improper Marine Senior Command Radio Encryption Key" + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + +/obj/item/device/encryptionkey/mcom + name = "\improper Marine Command Radio Encryption Key" + icon_state = "cap_key" + channels = list(RADIO_CHANNEL_COMMAND = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + +/obj/item/device/encryptionkey/mcom/alt + channels = list(RADIO_CHANNEL_COMMAND = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + +// MARINE ENGINEERING + +/obj/item/device/encryptionkey/ce + name = "Chief Engineer's Encryption Key" + icon_state = "ce_key" + channels = list(RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE) + /obj/item/device/encryptionkey/engi name = "Engineering Radio Encryption Key" icon_state = "eng_key" channels = list(RADIO_CHANNEL_ENGI = TRUE) -/obj/item/device/encryptionkey/sec - name = "Security Radio Encryption Key" - icon_state = "sec_key" - channels = list(RADIO_CHANNEL_MP = TRUE) +// MARINE MEDICAL + +/obj/item/device/encryptionkey/cmo + name = "Chief Medical Officer's Encryption Key" + icon_state = "cmo_key" + channels = list(RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/med name = "Medical Radio Encryption Key" icon_state = "med_key" channels = list(RADIO_CHANNEL_MEDSCI = TRUE) -/obj/item/device/encryptionkey/ce - name = "Chief Engineer's Encryption Key" - icon_state = "ce_key" - channels = list(RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE) +/obj/item/device/encryptionkey/medres + name = "Research Radio Encryption Key" + icon_state = "med_key" + channels = list(RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_INTEL = TRUE) -/obj/item/device/encryptionkey/cmo - name = "Chief Medical Officer's Encryption Key" - icon_state = "cmo_key" - channels = list(RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_COMMAND = TRUE) +// MARINE MILITARY POLICE -/obj/item/device/encryptionkey/command - name = "Command Encryption Key" - icon_state = "cap_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE) +/obj/item/device/encryptionkey/cmpcom + name = "\improper Marine Chief MP Radio Encryption Key" + icon_state = "cmp_key" + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE) + +/obj/item/device/encryptionkey/mmpo + name = "\improper Military Police Radio Encryption Key" + icon_state = "sec_key" + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE,) + +/obj/item/device/encryptionkey/sec + name = "Security Radio Encryption Key" + icon_state = "sec_key" + channels = list(RADIO_CHANNEL_MP = TRUE) + +// MARINE REQUISTIONS -/obj/item/device/encryptionkey/ro +/obj/item/device/encryptionkey/qm name = "Requisition Officer's Encryption Key" icon_state = "ce_key" channels = list(RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_ENGI = FALSE, RADIO_CHANNEL_MEDSCI = FALSE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE) -/obj/item/device/encryptionkey/req +/obj/item/device/encryptionkey/req/ct name = "Supply Radio Encryption Key" icon_state = "req_key" - channels = list(RADIO_CHANNEL_REQ = TRUE) + channels = list(RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_COMMAND = FALSE, RADIO_CHANNEL_ENGI = FALSE) -/obj/item/device/encryptionkey/req/ct +/obj/item/device/encryptionkey/req name = "Supply Radio Encryption Key" icon_state = "req_key" - channels = list(RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_COMMAND = FALSE, RADIO_CHANNEL_ENGI = FALSE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE) - -/obj/item/device/encryptionkey/mmpo - name = "\improper Military Police Radio Encryption Key" - icon_state = "sec_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE,) - -//MARINE ENCRYPTION KEYS - -/obj/item/device/encryptionkey/cmpcom - name = "\improper Marine Chief MP Radio Encryption Key" - icon_state = "cmp_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE) + channels = list(RADIO_CHANNEL_REQ = TRUE) -/obj/item/device/encryptionkey/cmpcom/cdrcom - name = "\improper Marine Senior Command Radio Encryption Key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) +// MARINE SUPPORT /obj/item/device/encryptionkey/cmpcom/synth name = "\improper Marine Synth Radio Encryption Key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) - -/obj/item/device/encryptionkey/mcom - name = "\improper Marine Command Radio Encryption Key" - icon_state = "cap_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/mcom/cl name = "\improper Corporate Liaison radio encryption key" icon_state = "cap_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE, RADIO_CHANNEL_WY = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE, RADIO_CHANNEL_WY = TRUE) /obj/item/device/encryptionkey/mcom/rep name = "\improper Representative radio encryption key" @@ -123,25 +153,27 @@ /obj/item/device/encryptionkey/po name = "\improper Marine Pilot Officer Radio Encryption Key" icon_state = "cap_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/io name = "\improper Marine Intelligence Officer Radio Encryption Key" icon_state = "cap_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_INTEL = TRUE) -/obj/item/device/encryptionkey/mcom/ai //AI only. - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) +/obj/item/device/encryptionkey/vc + name = "\improper Marine Vehicle Crewman Radio Encryption Key" + icon_state = "cap_key" + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE) -/obj/item/device/encryptionkey/jtac - name = "\improper JTAC Radio Encryption Key" - icon_state = "jtac_key" - channels = list(RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_REQ = TRUE) +/obj/item/device/encryptionkey/req/mst + name = "Supply Radio Encryption Key" + icon_state = "req_key" + channels = list(RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_COMMAND = FALSE) -/obj/item/device/encryptionkey/intel - name = "\improper Intel Radio Encryption Key" - icon_state = "jtac_key" - channels = list(RADIO_CHANNEL_INTEL = TRUE) +/obj/item/device/encryptionkey/mcom/ai //AI only. + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + +// MARINE SQUADS /obj/item/device/encryptionkey/squadlead name = "\improper Squad Leader Radio Encryption Key" @@ -186,6 +218,11 @@ icon_state = "binary_key" channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_INTEL = TRUE, RADIO_CHANNEL_JTAC = TRUE, SQUAD_MARINE_1 = FALSE, SQUAD_MARINE_2 = FALSE, SQUAD_MARINE_3 = FALSE, SQUAD_MARINE_4 = FALSE, SQUAD_MARINE_5 = FALSE, SQUAD_MARINE_CRYO = FALSE) +/obj/item/device/encryptionkey/soc/forecon + name = "\improper SOF Radio Encryption Key" + icon_state = "binary_key" + channels = list(RADIO_CHANNEL_COLONY= TRUE) + //ERT, PMC /obj/item/device/encryptionkey/dutch @@ -272,7 +309,7 @@ /obj/item/device/encryptionkey/highcom name = "\improper USCM High Command Radio Encryption Key" icon_state = "binary_key" - channels = list(RADIO_CHANNEL_HIGHCOM = TRUE, SQUAD_SOF = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_HIGHCOM = TRUE, SQUAD_SOF = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/contractor name = "\improper Vanguard's Arrow Incorporated Radio Encryption Key" @@ -282,7 +319,7 @@ /obj/item/device/encryptionkey/cmb name = "\improper Colonial Marshal Bureau Radio Encryption Key" icon_state = "cmb_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_INTEL = TRUE, RADIO_CHANNEL_ALMAYER = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_INTEL = TRUE, RADIO_CHANNEL_ALMAYER = TRUE, RADIO_CHANNEL_COLONY = TRUE) /// Used by the Mortar Crew in WO game mode - intently has no squad radio access /obj/item/device/encryptionkey/mortar name = "\improper Mortar Crew Radio Encryption Key" diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 7d5412806848..7e6b0db056d0 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -65,6 +65,7 @@ /obj/item/device/radio/headset/Destroy() wearer = null + QDEL_NULL_LIST(keys) return ..() /obj/item/device/radio/headset/proc/set_volume_setting() @@ -428,9 +429,9 @@ /obj/item/device/radio/headset/almayer/chef name = "kitchen radio headset" - desc = "Used by the onboard kitchen staff, filled with background noise of sizzling pots. Can coordinate with the supply channel, using :u." + desc = "Used by the onboard kitchen staff, filled with background noise of sizzling pots. Can coordinate with the supply channel, using :u and inform command of delivery service using :v." icon_state = "req_headset" - initial_keys = list(/obj/item/device/encryptionkey/req/ct) + initial_keys = list(/obj/item/device/encryptionkey/req/mst) /obj/item/device/radio/headset/almayer/doc name = "medical radio headset" @@ -438,17 +439,23 @@ icon_state = "med_headset" initial_keys = list(/obj/item/device/encryptionkey/med) +/obj/item/device/radio/headset/almayer/research + name = "researcher radio headset" + desc = "A headset used by medbay's skilled researchers. Channels are as follows: :m - medical, :t - intel." + icon_state = "med_headset" + initial_keys = list(/obj/item/device/encryptionkey/medres) + /obj/item/device/radio/headset/almayer/ct name = "supply radio headset" desc = "Used by the lowly Cargo Technicians of the USCM, light weight and portable. To access the supply channel, use :u." icon_state = "req_headset" initial_keys = list(/obj/item/device/encryptionkey/req/ct) -/obj/item/device/radio/headset/almayer/ro - desc = "A headset used by the RO for controlling their slave(s). Channels are as follows: :u - requisitions, :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad." +/obj/item/device/radio/headset/almayer/qm + desc = "A headset used by the quartermaster for controlling their slave(s). Channels are as follows: :u - requisitions, :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad." name = "requisition officer radio headset" icon_state = "ro_headset" - initial_keys = list(/obj/item/device/encryptionkey/ro) + initial_keys = list(/obj/item/device/encryptionkey/qm) volume = RADIO_VOLUME_CRITICAL multibroadcast_cooldown = LOW_MULTIBROADCAST_COOLDOWN @@ -487,6 +494,9 @@ volume = RADIO_VOLUME_CRITICAL multibroadcast_cooldown = LOW_MULTIBROADCAST_COOLDOWN +/obj/item/device/radio/headset/almayer/mcom/alt + initial_keys = list(/obj/item/device/encryptionkey/mcom/alt) + /obj/item/device/radio/headset/almayer/marine/mp_honor/com name = "marine honor guard command radio headset" desc = "Given to highly trusted marine honor guard only. It features a non-standard brace. Channels are as follows: :v - marine command, :p - military police, :n - engineering, :m - medbay, :u - requisitions, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad." @@ -495,15 +505,15 @@ /obj/item/device/radio/headset/almayer/po name = "marine pilot radio headset" - desc = "Used by Pilot Officers. Channels are as follows: :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad, :j - JTAC, :t - intel." + desc = "Used by Pilot Officers. Channels are as follows: :v - marine command, :n - engineering, :m - medical, :j - JTAC, :t - intel." initial_keys = list(/obj/item/device/encryptionkey/po) volume = RADIO_VOLUME_CRITICAL multibroadcast_cooldown = LOW_MULTIBROADCAST_COOLDOWN /obj/item/device/radio/headset/almayer/intel name = "marine intel radio headset" - desc = "Used by Intelligence Officers. Channels are as follows: :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad, :j - JTAC, :t - intel." - initial_keys = list(/obj/item/device/encryptionkey/po) + desc = "Used by Intelligence Officers. Channels are as follows: :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad, :n - engineering, :m - medical, :j - JTAC, :t - intel." + initial_keys = list(/obj/item/device/encryptionkey/io) /obj/item/device/radio/headset/almayer/mcl name = "corporate liaison radio headset" @@ -546,7 +556,8 @@ "Bravo SL" = TRACKER_BSL, "Charlie SL" = TRACKER_CSL, "Delta SL" = TRACKER_DSL, - "Echo SL" = TRACKER_ESL + "Echo SL" = TRACKER_ESL, + "Foxtrot SL" = TRACKER_FSL ) /obj/item/device/radio/headset/almayer/mcom/ai @@ -569,9 +580,9 @@ initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/squadlead) volume = RADIO_VOLUME_CRITICAL -/obj/item/device/radio/headset/almayer/marine/alpha/rto - name = "marine alpha RTO radio headset" - desc = "This is used by the marine Alpha RTO. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." +/obj/item/device/radio/headset/almayer/marine/alpha/tl + name = "marine alpha team leader radio headset" + desc = "This is used by the marine Alpha team leader. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/jtac) volume = RADIO_VOLUME_RAISED @@ -598,9 +609,9 @@ initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/squadlead) volume = RADIO_VOLUME_CRITICAL -/obj/item/device/radio/headset/almayer/marine/bravo/rto - name = "marine bravo RTO radio headset" - desc = "This is used by the marine Bravo RTO. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." +/obj/item/device/radio/headset/almayer/marine/bravo/tl + name = "marine bravo team leader radio headset" + desc = "This is used by the marine Bravo team leader. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/jtac) volume = RADIO_VOLUME_RAISED @@ -627,9 +638,9 @@ initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/squadlead) volume = RADIO_VOLUME_CRITICAL -/obj/item/device/radio/headset/almayer/marine/charlie/rto - name = "marine charlie RTO radio headset" - desc = "This is used by the marine Charlie RTO. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." +/obj/item/device/radio/headset/almayer/marine/charlie/tl + name = "marine charlie team leader radio headset" + desc = "This is used by the marine Charlie team leader. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/jtac) volume = RADIO_VOLUME_RAISED @@ -656,9 +667,9 @@ initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/squadlead) volume = RADIO_VOLUME_CRITICAL -/obj/item/device/radio/headset/almayer/marine/delta/rto - name = "marine delta RTO radio headset" - desc = "This is used by the marine Delta RTO. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." +/obj/item/device/radio/headset/almayer/marine/delta/tl + name = "marine delta team leader radio headset" + desc = "This is used by the marine Delta team leader. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/jtac) volume = RADIO_VOLUME_RAISED @@ -685,9 +696,9 @@ initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/squadlead) volume = RADIO_VOLUME_CRITICAL -/obj/item/device/radio/headset/almayer/marine/echo/rto - name = "marine echo RTO radio headset" - desc = "This is used by the marine Echo RTO. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." +/obj/item/device/radio/headset/almayer/marine/echo/tl + name = "marine echo team leader radio headset" + desc = "This is used by the marine Echo team leader. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/jtac) volume = RADIO_VOLUME_RAISED @@ -715,9 +726,9 @@ initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/squadlead) volume = RADIO_VOLUME_CRITICAL -/obj/item/device/radio/headset/almayer/marine/cryo/rto - name = "marine foxtrot RTO radio headset" - desc = "This is used by the marine Foxtrot RTO. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." +/obj/item/device/radio/headset/almayer/marine/cryo/tl + name = "marine foxtrot team leader radio headset" + desc = "This is used by the marine Foxtrot team leader. Channels are as follows: :u - requisitions, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/jtac) volume = RADIO_VOLUME_RAISED @@ -788,8 +799,8 @@ if(JOB_SQUAD_ENGI) name = "marine combat technician " + name keys += new /obj/item/device/encryptionkey/engi(src) - if(JOB_SQUAD_RTO) - name = "marine RTO " + name + if(JOB_SQUAD_TEAM_LEADER) + name = "marine fireteam leader " + name keys += new /obj/item/device/encryptionkey/jtac(src) else name = "marine " + name @@ -959,20 +970,23 @@ //CMB Headsets /obj/item/device/radio/headset/distress/CMB name = "\improper CMB Earpiece" - desc = "A sleek headset used by The Colonial Marshal Bureau, crafted in Sol. Low profile and comfortable. No one is above the law. Featured channels include: ; - CMB, :g - public, :v - marine command, :m - medbay, :t - intel." + desc = "A sleek headset used by The Colonial Marshal Bureau, crafted in Sol. Low profile and comfortable. No one is above the law. Featured channels include: ; - CMB, :o - Colony, :g - public, :v - marine command, :m - medbay, :t - intel." frequency = CMB_FREQ icon_state = "cmb_headset" initial_keys = list(/obj/item/device/encryptionkey/cmb) has_hud = TRUE hud_type = MOB_HUD_FACTION_USCM +/obj/item/device/radio/headset/distress/CMB/limited + name = "\improper Damaged CMB Earpiece" + desc = "A sleek headset used by The Colonial Marshal Bureau, crafted in Sol. Low profile and comfortable. No one is above the law. This one is damaged, so the channels are: ; - CMB, :o - Colony." + initial_keys = list(/obj/item/device/encryptionkey/colony) + /obj/item/device/radio/headset/distress/CMB/ICC name = "\improper ICC Liaison Headset" - desc = "An expensive headset used by The Interstellar Commerce Commission. This one in particular has a liaison chip with the CMB. Featured channels include: ; - CMB, :g - public, :v - marine command, :m - medbay, :t - intel, :y - Weyland-Yutani." - frequency = CMB_FREQ + desc = "An expensive headset used by The Interstellar Commerce Commission. This one in particular has a liaison chip with the CMB. Featured channels include: ; - CMB, :o - Colony, :g - public, :v - marine command, :m - medbay, :t - intel, :y - Weyland-Yutani." icon_state = "wy_headset" initial_keys = list(/obj/item/device/encryptionkey/WY, /obj/item/device/encryptionkey/cmb) - has_hud = TRUE /obj/item/device/radio/headset/almayer/highcom name = "USCM High Command headset" @@ -991,8 +1005,20 @@ volume = RADIO_VOLUME_IMPORTANT ignore_z = TRUE +/obj/item/device/radio/headset/almayer/sof/survivor_forecon + name = "USCM SOF headset" + desc = "Issued exclusively to Marine Raiders and members of the USCM's Force Reconnaissance." + icon_state = "soc_headset" + frequency = SOF_FREQ + initial_keys = list(/obj/item/device/encryptionkey/soc/forecon) + volume = RADIO_VOLUME_QUIET + ignore_z = FALSE + has_hud = TRUE + hud_type = MOB_HUD_FACTION_USCM + /obj/item/device/radio/headset/almayer/mcom/vc name = "marine vehicle crew radio headset" - desc = "Used by USCM vehicle crew, features a non-standard brace. Channels are as follows: :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad, :n - engineering, :m - medbay, :u - requisitions, :j - JTAC, :t - intel." + desc = "Used by USCM vehicle crew, features a non-standard brace. Channels are as follows: :v - marine command, :n - engineering, :m - medbay, :u - requisitions" + initial_keys = list(/obj/item/device/encryptionkey/vc) volume = RADIO_VOLUME_RAISED multibroadcast_cooldown = HIGH_MULTIBROADCAST_COOLDOWN diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index dd0ceed3f144..2092ffa108c6 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -216,8 +216,6 @@ if(!(src.wires & WIRE_TRANSMIT)) // The device has to have all its wires and shit intact return - M.last_target_click = world.time - /* 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 diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 7026f2a3e7d0..3e2c1445f8e5 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -446,6 +446,8 @@ FORENSIC SCANNER /obj/item/device/black_market_scanner/afterattack(atom/hit_atom, mob/user, proximity) if(!proximity) return + if(!ismovable(hit_atom)) + return ..() var/market_value = get_black_market_value(hit_atom) if(isnull(market_value)) return ..() diff --git a/code/game/objects/items/explosives/explosive.dm b/code/game/objects/items/explosives/explosive.dm index 42b33bdc7ea8..0c482e8db9e7 100644 --- a/code/game/objects/items/explosives/explosive.dm +++ b/code/game/objects/items/explosives/explosive.dm @@ -205,7 +205,7 @@ var/mob/cause_mob = cause_data?.resolve_mob() if(cause_mob) //so we don't message for simulations reagents.source_mob = WEAKREF(cause_mob) - msg_admin_niche("[key_name(cause_mob)] detonated custom explosive by [key_name(creator)]: [name] (REAGENTS: [reagent_list_text]) in [get_area(src)] (JMP)", loc.x, loc.y, loc.z) + msg_admin_niche("[key_name(cause_mob)] detonated custom explosive by [key_name(creator)]: [name] (REAGENTS: [reagent_list_text]) in [get_area(src)] [ADMIN_JMP(loc)]", loc.x, loc.y, loc.z) if(containers.len < 2) reagents.trigger_volatiles = TRUE //Explode on the first transfer diff --git a/code/game/objects/items/explosives/grenades/flashbang.dm b/code/game/objects/items/explosives/grenades/flashbang.dm index e97d50c059ee..365dfe26df89 100644 --- a/code/game/objects/items/explosives/grenades/flashbang.dm +++ b/code/game/objects/items/explosives/grenades/flashbang.dm @@ -162,7 +162,7 @@ //Created by Polymorph, fixed by Sieve /obj/item/explosive/grenade/flashbang/cluster name = "cluster flashbang" - desc = "Use of this weapon may be considered a war crime in your area, consult your local captain." + desc = "Use of this weapon may be considered a war crime in your area, consult your local commanding officer." icon_state = "cluster" no_damage = TRUE diff --git a/code/game/objects/items/explosives/grenades/grenade.dm b/code/game/objects/items/explosives/grenades/grenade.dm index e8c019c6cffc..7e98e9819931 100644 --- a/code/game/objects/items/explosives/grenades/grenade.dm +++ b/code/game/objects/items/explosives/grenades/grenade.dm @@ -63,7 +63,7 @@ if(antigrief_protection && user.faction == FACTION_MARINE && explosive_antigrief_check(src, user)) to_chat(user, SPAN_WARNING("\The [name]'s safe-area accident inhibitor prevents you from priming the grenade!")) // Let staff know, in case someone's actually about to try to grief - msg_admin_niche("[key_name(user)] attempted to prime \a [name] in [get_area(src)] (JMP)") + msg_admin_niche("[key_name(user)] attempted to prime \a [name] in [get_area(src)] [ADMIN_JMP(src.loc)]") return if(SEND_SIGNAL(user, COMSIG_GRENADE_PRE_PRIME) & COMPONENT_GRENADE_PRIME_CANCEL) diff --git a/code/game/objects/items/explosives/grenades/marines.dm b/code/game/objects/items/explosives/grenades/marines.dm index 76ab1db703e0..a8e0e1803a33 100644 --- a/code/game/objects/items/explosives/grenades/marines.dm +++ b/code/game/objects/items/explosives/grenades/marines.dm @@ -195,6 +195,88 @@ direct_hit_shrapnel = 5 dispersion_angle = 360 //beeg circle +/* +//================================================ + M203 Grenades +//================================================ +*/ + +/obj/item/explosive/grenade/incendiary/impact + name = "\improper 40mm incendiary grenade" + desc = "This is a 40mm grenade, designed to be launched by a grenade launcher and detonate on impact. This one is marked as a incendiary grenade, watch your fire." + icon_state = "grenade_40mm_inc" + det_time = 0 + item_state = "grenade_fire" + hand_throwable = FALSE + dangerous = TRUE + underslug_launchable = TRUE + flame_level = BURN_TIME_TIER_2 + burn_level = BURN_LEVEL_TIER_3 + flameshape = FLAMESHAPE_DEFAULT + radius = 2 + fire_type = FIRE_VARIANT_DEFAULT + +/obj/item/explosive/grenade/incendiary/impact/prime() + return + +/obj/item/explosive/grenade/incendiary/impact/launch_impact(atom/hit_atom) + ..() + var/detonate = TRUE + var/turf/hit_turf = null + if(isobj(hit_atom) && !rebounding) + detonate = FALSE + if(isturf(hit_atom)) + hit_turf = hit_atom + if(hit_turf.density && !rebounding) + detonate = FALSE + if(active && detonate) // Active, and we reached our destination. + var/angle = dir2angle(last_move_dir) + var/turf/target = locate(x + sin(angle)*radius, y + cos(angle)*radius, z) + if(target) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flame_radius), cause_data, radius, get_turf(src), flame_level, burn_level, flameshape, target) + else + //Not stellar, but if we can't find a direction, fall back to HIDP behaviour. + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flame_radius), cause_data, radius, get_turf(src), flame_level, burn_level, FLAMESHAPE_DEFAULT, target) + playsound(src, 'sound/weapons/gun_flamethrower2.ogg', 35, 1, 4) + qdel(src) + +/obj/item/explosive/grenade/high_explosive/impact //omega hell killer grenade of doom from hell + name = "\improper 40mm HE grenade" + desc = "This is a 40mm grenade, designed to be launched by a grenade launcher and detonate on impact. This one is marked as a High-Explosive grenade, watch your fire." + icon_state = "grenade_40mm_he" + item_state = "grenade_hedp" + det_time = 0 + hand_throwable = FALSE + dangerous = TRUE + underslug_launchable = TRUE + explosion_power = 100 //hedp + falloff_mode = EXPLOSION_FALLOFF_SHAPE_LINEAR + +/obj/item/explosive/grenade/high_explosive/impact/prime() +// We don't prime, we use launch_impact. + +/obj/item/explosive/grenade/high_explosive/impact/launch_impact(atom/hit_atom) + ..() + var/detonate = TRUE + if(isobj(hit_atom) && !rebounding) + detonate = FALSE + if(isturf(hit_atom) && hit_atom.density && !rebounding) + detonate = FALSE + if(active && detonate) // Active, and we reached our destination. + if(explosion_power) + cell_explosion(loc, explosion_power, explosion_falloff, falloff_mode, last_move_dir, cause_data) + qdel(src) + +/obj/item/explosive/grenade/high_explosive/airburst/buckshot + name = "\improper 40mm Buckshot Shell" + desc = "A classic of grenade launchers everywhere, this is a 40mm shell loaded with buckshot; very dangerous, watch your fire." + icon_state = "grenade_40mm_buckshot" + item_state = "grenade_hornet_active" + shrapnel_count = 10 + shrapnel_type = /datum/ammo/bullet/shotgun/spread + direct_hit_shrapnel = 5 + dispersion_angle = 35//big + /* //================================================ Incendiary Grenades @@ -465,31 +547,32 @@ ram_distance -- //for max pinballing. icon_state = inactive_icon -/obj/item/explosive/grenade/slug/proc/impact_mob(mob/living/M) - var/direction = Get_Angle(src,M) - var/target_turf = get_angle_target_turf(src,direction,throw_max) - var/fling = rand(throw_min,throw_max) //WEEEEEEEEEEEEEEEEEEEE What is going to be put into throw_atom +/obj/item/explosive/grenade/slug/proc/impact_mob(mob/living/smacked) + var/direction = Get_Angle(src, smacked) + var/target_turf = get_angle_target_turf(src,direction, throw_max) + var/fling = rand(throw_min, throw_max) //WEEEEEEEEEEEEEEEEEEEE What is going to be put into throw_atom var/random_tile = 0 //random tile for bounce - playsound(M.loc, impact_sound, 75, 1) - M.apply_damage(impact_damage, BRUTE) + playsound(smacked.loc, impact_sound, 75, 1) + smacked.apply_damage(impact_damage, BRUTE) + smacked.attack_log += "\[[time_stamp()]\] [src], fired by [fingerprintslast], struck [key_name(smacked)]." random_tile = get_random_turf_in_range(src,ram_distance,ram_distance) //getting random tile for bounce src.throw_atom(random_tile,ram_distance,SPEED_FAST,src,TRUE,NORMAL_LAUNCH,NO_FLAGS) //time for a little trolling - if(isyautja(M)|| issynth(M)) - M.apply_effect(slowdown_time * 0.5, SLOW) - M.apply_effect(dazed_time * 0.5, DAZE) + if(isyautja(smacked)|| issynth(smacked)) + smacked.apply_effect(slowdown_time * 0.5, SLOW) + smacked.apply_effect(dazed_time * 0.5, DAZE) - if(M.mob_size >= MOB_SIZE_BIG)//big xenos not KO'ed - M.apply_effect(slowdown_time * 1.2, SLOW)//They are slowed more :trol: - M.apply_effect(dazed_time * 1.2, DAZE) + if(smacked.mob_size >= MOB_SIZE_BIG)//big xenos not KO'ed + smacked.apply_effect(slowdown_time * 1.2, SLOW)//They are slowed more :trol: + smacked.apply_effect(dazed_time * 1.2, DAZE) return - M.apply_effect(knockout_time, WEAKEN)//but little xenos and humans are - M.throw_atom(target_turf,fling,SPEED_AVERAGE,M,TRUE) - M.apply_effect(slowdown_time, SLOW) - M.apply_effect(dazed_time, DAZE) + smacked.apply_effect(knockout_time, WEAKEN)//but little xenos and humans are + smacked.throw_atom(target_turf, fling, SPEED_AVERAGE, smacked, TRUE) + smacked.apply_effect(slowdown_time, SLOW) + smacked.apply_effect(dazed_time, DAZE) return /obj/item/explosive/grenade/slug/baton diff --git a/code/game/objects/items/explosives/mine.dm b/code/game/objects/items/explosives/mine.dm index 6b8c9bccd299..742a5f314c4a 100644 --- a/code/game/objects/items/explosives/mine.dm +++ b/code/game/objects/items/explosives/mine.dm @@ -198,6 +198,8 @@ return if(L.get_target_lock(iff_signal) || isrobot(L)) return + if(HAS_TRAIT(L, TRAIT_ABILITY_BURROWED)) + return L.visible_message(SPAN_DANGER("[icon2html(src, viewers(src))] The [name] clicks as [L] moves in front of it."), \ SPAN_DANGER("[icon2html(src, L)] The [name] clicks as you move in front of it."), \ SPAN_DANGER("You hear a click.")) diff --git a/code/game/objects/items/explosives/plastic.dm b/code/game/objects/items/explosives/plastic.dm index f5d78c0d7f01..830df9659070 100644 --- a/code/game/objects/items/explosives/plastic.dm +++ b/code/game/objects/items/explosives/plastic.dm @@ -62,10 +62,6 @@ /obj/item/explosive/plastic/afterattack(atom/target, mob/user, flag) setDir(get_dir(user, target)) - if(antigrief_protection && user.faction == FACTION_MARINE && explosive_antigrief_check(src, user)) - to_chat(user, SPAN_WARNING("\The [name]'s safe-area accident inhibitor prevents you from planting it!")) - msg_admin_niche("[key_name(user)] attempted to prime \a [name] in [get_area(src)] (JMP)") - return if(user.action_busy || !flag) return @@ -75,6 +71,11 @@ if(!can_place(user, target)) return + if(antigrief_protection && user.faction == FACTION_MARINE && explosive_antigrief_check(src, user)) + to_chat(user, SPAN_WARNING("[name]'s safe-area accident inhibitor prevents you from planting it!")) + msg_admin_niche("[key_name(user)] attempted to prime \a [name] in [get_area(src)] [ADMIN_JMP(src.loc)]") + return + user.visible_message(SPAN_WARNING("[user] is trying to plant [name] on [target]!"), SPAN_WARNING("You are trying to plant [name] on [target]!")) if(ismob(target)) @@ -105,10 +106,10 @@ var/mob/M = target to_chat(M, FONT_SIZE_HUGE(SPAN_DANGER("[user] plants [name] on you!"))) user.attack_log += "\[[time_stamp()]\] [key_name(user)] successfully planted [name] on [key_name(target)]" - msg_admin_niche("[key_name(user, user.client)](?) planted [src.name] on [key_name(target)](?) with [timer] second fuse") + msg_admin_niche("[key_name(user, user.client)] planted [src.name] on [key_name(target)] with [timer] second fuse") log_game("[key_name(user)] planted [src.name] on [key_name(target)] with [timer] second fuse") else - msg_admin_niche("[key_name(user, user.client)](?) planted [src.name] on [target.name] at ([target.x],[target.y],[target.z] - JMP) with [timer] second fuse") + msg_admin_niche("[key_name(user, user.client)] planted [src.name] on [target.name] at ([target.x],[target.y],[target.z] [ADMIN_JMP(target)] with [timer] second fuse") log_game("[key_name(user)] planted [src.name] on [target.name] at ([target.x],[target.y],[target.z]) with [timer] second fuse") if(customizable) @@ -212,23 +213,6 @@ return TRUE -/obj/item/explosive/plastic/breaching_charge/can_place(mob/user, atom/target) - if(!is_type_in_list(target, breachable))//only items on the list are allowed - to_chat(user, SPAN_WARNING("You cannot plant \the [name] on \the [target]!")) - return FALSE - - if(SSinterior.in_interior(target))// vehicle checks again JUST IN CASE - to_chat(user, SPAN_WARNING("It's too cramped in here to deploy \the [src].")) - return FALSE - - if(istype(target, /obj/structure/window))//no breaching charges on the briefing windows / brig / CIC e.e - var/obj/structure/window/W = target - if(W.not_damageable) - to_chat(user, SPAN_WARNING("[W] is much too tough for you to do anything to it with [src].")) //On purpose to mimic wall message - return FALSE - - return TRUE - /obj/item/explosive/plastic/proc/calculate_pixel_offset(mob/user, atom/target) switch(get_dir(user, target)) if(NORTH) @@ -311,13 +295,6 @@ cell_explosion(target_turf, 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) qdel(src) -/obj/item/explosive/plastic/breaching_charge/handle_explosion(turf/target_turf, dir, cause_data) - var/explosion_target = get_step(target_turf, dir) - create_shrapnel(explosion_target, 40, dir, angle,/datum/ammo/bullet/shrapnel/metal, cause_data) - sleep(1)// prevents explosion from eating shrapnel - cell_explosion(target_turf, 60, 60, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, dir, cause_data) - qdel(src) - /obj/item/explosive/plastic/proc/delayed_prime(turf/target_turf) prime(TRUE) @@ -341,3 +318,65 @@ min_timer = 3 penetration = 0.60 deploying_time = 10 + var/shrapnel_volume = 40 + +/obj/item/explosive/plastic/breaching_charge/can_place(mob/user, atom/target) + if(!is_type_in_list(target, breachable))//only items on the list are allowed + to_chat(user, SPAN_WARNING("You cannot plant [name] on [target]!")) + return FALSE + + if(SSinterior.in_interior(target))// vehicle checks again JUST IN CASE + to_chat(user, SPAN_WARNING("It's too cramped in here to deploy [src].")) + return FALSE + + if(istype(target, /obj/structure/window))//no breaching charges on the briefing windows / brig / CIC e.e + var/obj/structure/window/window = target + if(window.not_damageable) + to_chat(user, SPAN_WARNING("[window] is much too tough for you to do anything to it with [src].")) //On purpose to mimic wall message + return FALSE + + if(istype(target, /turf/closed/wall)) + var/turf/closed/wall/targeted_wall = target + if(targeted_wall.hull) + to_chat(user, SPAN_WARNING("You are unable to stick [src] to [targeted_wall]!")) + return FALSE + + return TRUE + +/obj/item/explosive/plastic/breaching_charge/handle_explosion(turf/target_turf, dir, cause_data) + var/explosion_target = get_step(target_turf, dir) + create_shrapnel(explosion_target, shrapnel_volume, dir, angle,/datum/ammo/bullet/shrapnel/metal, cause_data) + addtimer(CALLBACK(src, PROC_REF(trigger_explosion), target_turf, dir, cause_data), 1) + +/obj/item/explosive/plastic/breaching_charge/proc/trigger_explosion(turf/target_turf, dir, cause_data) + cell_explosion(target_turf, 60, 60, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, dir, cause_data) + qdel(src) + +/obj/item/explosive/plastic/breaching_charge/plasma + name = "plasma charge" + desc = "An alien explosive device. Who knows what it might do." + icon_state = "plasma-charge" + overlay_image = "plasma-active" + w_class = SIZE_SMALL + angle = 55 + timer = 5 + min_timer = 5 + penetration = 0.60 + deploying_time = 10 + flags_item = NOBLUDGEON|ITEM_PREDATOR + shrapnel_volume = 10 + +/obj/item/explosive/plastic/breaching_charge/plasma/can_place(mob/user, atom/target) + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + to_chat(user, SPAN_WARNING("You don't quite understand how the device works...")) + return FALSE + . = ..() + +/obj/item/explosive/plastic/breaching_charge/plasma/handle_explosion(turf/target_turf, dir, cause_data) + var/explosion_target = get_step(target_turf, dir) + create_shrapnel(explosion_target, shrapnel_volume, dir, angle,/datum/ammo/bullet/shrapnel/plasma, cause_data) + addtimer(CALLBACK(src, PROC_REF(trigger_explosion), target_turf, dir, cause_data), 1) + +/obj/item/explosive/plastic/breaching_charge/plasma/trigger_explosion(turf/target_turf, dir, cause_data) + cell_explosion(target_turf, 90, 90, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, dir, cause_data) + qdel(src) diff --git a/code/game/objects/items/fulton.dm b/code/game/objects/items/fulton.dm index 70d653927a72..98987d1cd2b3 100644 --- a/code/game/objects/items/fulton.dm +++ b/code/game/objects/items/fulton.dm @@ -22,6 +22,7 @@ var/global/list/deployed_fultons = list() var/atom/movable/attached_atom = null var/turf/original_location = null var/attachable_atoms = list(/obj/structure/closet/crate) + var/datum/turf_reservation/reservation /obj/item/stack/fulton/New(loc, amount, atom_to_attach) ..() @@ -139,7 +140,10 @@ var/global/list/deployed_fultons = list() sleep(30) original_location = get_turf(attached_atom) playsound(loc, 'sound/items/fulton.ogg', 50, 1) - var/turf/space_tile = pick(get_area_turfs(/area/space/highalt)) + reservation = SSmapping.RequestBlockReservation(3, 3, turf_type_override = /turf/open/space) + var/middle_x = reservation.bottom_left_coords[1] + FLOOR((reservation.top_right_coords[1] - reservation.bottom_left_coords[1]) / 2, 1) + var/middle_y = reservation.bottom_left_coords[2] + FLOOR((reservation.top_right_coords[2] - reservation.bottom_left_coords[2]) / 2, 1) + var/turf/space_tile = locate(middle_x, middle_y, reservation.bottom_left_coords[3]) if(!space_tile) visible_message(SPAN_WARNING("[src] begins beeping like crazy. Something is wrong!")) return @@ -157,8 +161,8 @@ var/global/list/deployed_fultons = list() /obj/item/stack/fulton/proc/return_fulton(turf/return_turf) - // Fulton is not in space, it must have been collected. - if(!istype(get_area(attached_atom), /area/space/highalt)) + // Fulton is not in reservation, it must have been collected. + if(!(get_turf(src) in reservation.reserved_turfs)) return attached_atom.forceMove(return_turf) @@ -170,5 +174,7 @@ var/global/list/deployed_fultons = list() //Giving marines an objective to retrieve that fulton (so they'd know what they lost and where) var/datum/cm_objective/retrieve_item/fulton/objective = new /datum/cm_objective/retrieve_item/fulton(attached_atom) intel_system.store_single_objective(objective) + + qdel(reservation) qdel(src) return diff --git a/code/game/objects/items/handheld_distress_beacon.dm b/code/game/objects/items/handheld_distress_beacon.dm new file mode 100644 index 000000000000..d3f99134cd23 --- /dev/null +++ b/code/game/objects/items/handheld_distress_beacon.dm @@ -0,0 +1,40 @@ + +///handheld distress beacons used by goon chem retrieval team to call for PMC back up +/obj/item/handheld_distress_beacon + name = "handheld distress beacon" + desc = "A standard handheld distress beacon. Generally used by teams who may be out of regular communications range but must signal for assistance. This one is branded with a Weyland Yutani symbol and sold en masse to colonies across the Neroid Sector." + icon = 'icons/obj/items/handheld_distress_beacon.dmi' + icon_state = "beacon_inactive" + w_class = SIZE_SMALL + + var/active = FALSE + +/obj/item/handheld_distress_beacon/get_examine_text(mob/user) + . = ..() + + if(active) + . += "The beacon has been activated!" + +/obj/item/handheld_distress_beacon/update_icon() + . = ..() + + if(active) + icon_state = "beacon_active" + else + icon_state = initial(icon_state) + +/obj/item/handheld_distress_beacon/attack_self(mob/user) + . = ..() + + if(active) + to_chat(user, "[src] is already active!") + return + + for(var/client/C in GLOB.admins) + if((R_ADMIN|R_MOD) & C.admin_holder.rights) + playsound_client(C,'sound/effects/sos-morse-code.ogg',10) + message_admins("[key_name(user)] has requested a PMC Distress Beacon! [CC_MARK(user)] (SEND) (DENY) [ADMIN_JMP_USER(user)] [CC_REPLY(user)]") + to_chat(user, SPAN_NOTICE("A distress beacon request has been sent to the USCSS Royce.")) + + active = TRUE + update_icon() diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm index f88ac1c1f17f..d39b7e675452 100644 --- a/code/game/objects/items/implants/implant.dm +++ b/code/game/objects/items/implants/implant.dm @@ -171,7 +171,7 @@ Implant Specifics:
"} var/need_gib = null if(istype(imp_in, /mob/)) var/mob/T = imp_in - message_admins("Explosive implant triggered in [T] ([T.key]). (JMP) ") + message_admins("Explosive implant triggered in [T] ([T.key]). [ADMIN_JMP(T)] ") log_game("Explosive implant triggered in [T] ([T.key]).") need_gib = 1 diff --git a/code/game/objects/items/paint.dm b/code/game/objects/items/paint.dm index b4b2c02623e1..9089dd228ed0 100644 --- a/code/game/objects/items/paint.dm +++ b/code/game/objects/items/paint.dm @@ -35,7 +35,7 @@ var/global/list/cached_icons = list() . = ..() reagents.add_reagent("paint_[paint_type]", volume) -/obj/item/reagent_container/glass/paint/on_reagent_change() //Until we have a generic "paint", this will give new colours to all paints in the can +/obj/item/reagent_container/glass/paint/on_reagent_change() //Until we have a generic "paint", this will give new colors to all paints in the can var/mixedcolor = mix_color_from_reagents(reagents.reagent_list) for(var/datum/reagent/paint/P in reagents.reagent_list) P.color = mixedcolor diff --git a/code/game/objects/items/pamphlets.dm b/code/game/objects/items/pamphlets.dm index 683fbb2540f4..dd96f275ef17 100644 --- a/code/game/objects/items/pamphlets.dm +++ b/code/game/objects/items/pamphlets.dm @@ -96,8 +96,8 @@ user.hud_set_squad() var/obj/item/card/id/ID = user.wear_id - ID.set_assignment((user.assigned_squad ? (user.assigned_squad.name + " ") : "") + "Squad Spotter") - GLOB.data_core.manifest_modify(user.real_name, WEAKREF(user), "Squad Spotter") + ID.set_assignment((user.assigned_squad ? (user.assigned_squad.name + " ") : "") + "Spotter") + GLOB.data_core.manifest_modify(user.real_name, WEAKREF(user), "Spotter") /obj/item/pamphlet/skill/machinegunner name = "heavy machinegunner instructional pamphlet" diff --git a/code/game/objects/items/reagent_containers/autoinjectors.dm b/code/game/objects/items/reagent_containers/autoinjectors.dm index 660d98568cc9..4c1e8af88ee5 100644 --- a/code/game/objects/items/reagent_containers/autoinjectors.dm +++ b/code/game/objects/items/reagent_containers/autoinjectors.dm @@ -90,15 +90,6 @@ item_state = "emptyskill" skilllock = SKILL_MEDICAL_DEFAULT -/obj/item/reagent_container/hypospray/autoinjector/quickclot - name = "quick clot autoinjector" - chemname = "quickclot" - desc = "An autoinjector loaded with 3 uses of Quick Clot, a chemical designed to pause all bleeding. Renew doses as needed." - amount_per_transfer_from_this = LOWH_REAGENTS_OVERDOSE * INJECTOR_PERCENTAGE_OF_OD - volume = (LOWH_REAGENTS_OVERDOSE * INJECTOR_PERCENTAGE_OF_OD) * INJECTOR_USES - display_maptext = TRUE - maptext_label = "Qc" - /obj/item/reagent_container/hypospray/autoinjector/adrenaline name = "epinephrine autoinjector" chemname = "adrenaline" diff --git a/code/game/objects/items/reagent_containers/blood_pack.dm b/code/game/objects/items/reagent_containers/blood_pack.dm index ea1a8576e7da..0879dcffdc68 100644 --- a/code/game/objects/items/reagent_containers/blood_pack.dm +++ b/code/game/objects/items/reagent_containers/blood_pack.dm @@ -1,20 +1,27 @@ +#define BLOOD_BAG_INJECTING 1 +#define BLOOD_BAG_TAKING 0 + /obj/item/reagent_container/blood - name = "BloodPack" - desc = "Contains blood used for transfusion." + name = "blood pack" + desc = "A blood pack. Contains fluids, typically used for transfusions." icon = 'icons/obj/items/bloodpack.dmi' - icon_state = "empty" - volume = 200 + icon_state = "bloodpack" + volume = 300 matter = list("plastic" = 500) flags_atom = CAN_BE_SYRINGED transparent = TRUE + var/mode = BLOOD_BAG_INJECTING + var/mob/living/carbon/human/connected_to + var/mob/living/carbon/human/connected_from var/blood_type = null + var/datum/beam/current_beam /obj/item/reagent_container/blood/Initialize() . = ..() if(blood_type != null) - name = "BloodPack [blood_type]" - reagents.add_reagent("blood", 200, list("viruses"=null,"blood_type"=blood_type,"resistances"=null)) + name = "[blood_type] blood pack" + reagents.add_reagent("blood", initial(volume), list("viruses" = null, "blood_type" = blood_type, "resistances" = null)) update_icon() /obj/item/reagent_container/blood/on_reagent_change() @@ -22,10 +29,146 @@ /obj/item/reagent_container/blood/update_icon() var/percent = round((reagents.total_volume / volume) * 100) - switch(percent) - if(0 to 9) icon_state = "empty" - if(10 to 50) icon_state = "half" - if(51 to INFINITY) icon_state = "full" + overlays = null + underlays = null + + if(blood_type) + overlays += image('icons/obj/items/bloodpack.dmi', src, blood_type) + + if(reagents && reagents.total_volume) + var/image/filling = image('icons/obj/items/reagentfillings.dmi', src, "[icon_state]10") + + switch(percent) + if(1 to 9) filling.icon_state = "[icon_state]5" + if(10 to 19) filling.icon_state = "[icon_state]10" + if(20 to 39) filling.icon_state = "[icon_state]25" + if(40 to 64) filling.icon_state = "[icon_state]50" + if(65 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 = mix_color_from_reagents(reagents.reagent_list) + underlays += filling + +/obj/item/reagent_container/blood/proc/update_beam() + if(current_beam) + QDEL_NULL(current_beam) + else if(connected_from && connected_to) + current_beam = connected_from.beam(connected_to, "iv_tube") + +/obj/item/reagent_container/blood/attack(mob/attacked_mob, mob/user) + . = ..() + + if(attacked_mob == user) + to_chat(user, SPAN_WARNING("You cannot connect this to yourself!")) + return + + if(connected_to == attacked_mob) + STOP_PROCESSING(SSobj, src) + user.visible_message("[user] detaches [src] from [connected_to].", \ + "You detach [src] from [connected_to].") + connected_to.active_transfusions -= src + connected_to.base_pixel_x = 0 + connected_to = null + connected_from = null + update_beam() + return + + if(!skillcheck(user, SKILL_SURGERY, SKILL_SURGERY_NOVICE)) + to_chat(user, SPAN_WARNING("You don't know how to connect this!")) + return + + if(user.action_busy) + return + + if(!do_after(user, (1 SECONDS) * user.get_skill_duration_multiplier(SKILL_SURGERY), INTERRUPT_ALL, BUSY_ICON_FRIENDLY, attacked_mob, INTERRUPT_MOVED, BUSY_ICON_MEDICAL)) + to_chat(user, SPAN_WARNING("You were interrupted before you could finish!")) + return + + if(istype(attacked_mob, /mob/living/carbon/human)) + connected_to = attacked_mob + connected_from = user + connected_to.active_transfusions += src + connected_to.base_pixel_x = 5 + START_PROCESSING(SSobj, src) + user.visible_message("[user] attaches \the [src] to [connected_to].", \ + "You attach \the [src] to [connected_to].") + update_beam() + +/obj/item/reagent_container/blood/process() + //if we're not connected to anything stop doing stuff + if(!connected_to) + return PROCESS_KILL + + //if we're not on a human stop doing stuff + if(!ishuman(loc)) + bad_disconnect() + return PROCESS_KILL + + //if we're not being held in a hand stop doing stuff + var/mob/living/carbon/human/current_human = loc + if(!(current_human.l_hand == src || current_human.r_hand == src)) + bad_disconnect() + return PROCESS_KILL + + //if we're further than 1 tile away or we're not on a turf stop doing stuff + if(!(get_dist(src, connected_to) <= 1 && isturf(connected_to.loc))) + bad_disconnect() + return PROCESS_KILL + + //give blood + if(mode == BLOOD_BAG_INJECTING) + if(volume > 0) + var/transfer_amount = REAGENTS_METABOLISM * 30 + connected_to.inject_blood(src, transfer_amount) + return + + // Take blood + var/amount = reagents.maximum_volume - reagents.total_volume + amount = min(amount, 4) + if(!amount) + return + + if(!istype(connected_to)) + return + if(connected_to.species && connected_to.species.flags & NO_BLOOD) + return + + connected_to.take_blood(src, amount) + +/obj/item/reagent_container/blood/dropped() + ..() + bad_disconnect() + +///Used to standardize effects of a blood bag disconnecting improperly +/obj/item/reagent_container/blood/proc/bad_disconnect() + if(!connected_to) + return + + connected_to.visible_message("[src] breaks free of [connected_to]!", "[src] is pulled out of you!") + connected_to.apply_damage(3, BRUTE, pick("r_arm", "l_arm")) + if(connected_to.pain.feels_pain) + connected_to.emote("pain") + connected_to.active_transfusions -= src + connected_to.base_pixel_x = 0 + connected_to = null + connected_from = null + update_beam() + +/obj/item/reagent_container/blood/verb/toggle_mode() + set category = "Object" + set name = "Toggle Mode" + set src in view(1) + + if(!istype(usr, /mob/living)) + return + + if(usr.stat || usr.lying) + return + + mode = !mode + to_chat(usr, "The blood bag is now [mode ? "giving blood" : "taking blood"].") + /obj/item/reagent_container/blood/APlus blood_type = "A+" @@ -46,6 +189,8 @@ blood_type = "O-" /obj/item/reagent_container/blood/empty - name = "Empty BloodPack" - desc = "Seems pretty useless... Maybe if there were a way to fill it?" - icon_state = "empty" + name = "empty blood pack" + desc = "An empty blood pack. Sorry, vampires, no luck here." + +#undef BLOOD_BAG_INJECTING +#undef BLOOD_BAG_TAKING diff --git a/code/game/objects/items/reagent_containers/borghydro.dm b/code/game/objects/items/reagent_containers/borghydro.dm index 3ef49002b211..30a9bdbd3c65 100644 --- a/code/game/objects/items/reagent_containers/borghydro.dm +++ b/code/game/objects/items/reagent_containers/borghydro.dm @@ -13,7 +13,7 @@ var/charge_tick = 0 var/recharge_time = 2 SECONDS //Time it takes for shots to recharge - var/list/reagent_ids = list("tricordrazine", "bicaridine", "kelotane", "dexalinp", "anti_toxin", "inaprovaline", "tramadol", "imidazoline", "spaceacillin", "quickclot") + var/list/reagent_ids = list("tricordrazine", "bicaridine", "kelotane", "dexalinp", "anti_toxin", "inaprovaline", "tramadol", "imidazoline", "spaceacillin") var/list/reagent_volumes = list() var/list/reagent_names = list() diff --git a/code/game/objects/items/reagent_containers/food.dm b/code/game/objects/items/reagent_containers/food.dm index 13dfcac84ff8..ded1b90b106f 100644 --- a/code/game/objects/items/reagent_containers/food.dm +++ b/code/game/objects/items/reagent_containers/food.dm @@ -2,6 +2,10 @@ /// Food. //////////////////////////////////////////////////////////////////////////////// /obj/item/reagent_container/food + item_icons = list( + WEAR_L_HAND = 'icons/mob/humans/onmob/items_lefthand_1.dmi', + WEAR_R_HAND = 'icons/mob/humans/onmob/items_righthand_1.dmi' + ) possible_transfer_amounts = null volume = 50 //Sets the default container amount for all food items. flags_atom = CAN_BE_SYRINGED diff --git a/code/game/objects/items/reagent_containers/food/cans.dm b/code/game/objects/items/reagent_containers/food/cans.dm index 2ecce5323924..aab2ee066e12 100644 --- a/code/game/objects/items/reagent_containers/food/cans.dm +++ b/code/game/objects/items/reagent_containers/food/cans.dm @@ -175,7 +175,8 @@ /obj/item/reagent_container/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, drunkenness, or even death. Please Drink Responsibly." + desc = "Consumption of Thirteen Loko may result in seizures, blindness, drunkenness, or even death. Please Drink Responsibly." + desc_lore = "A rarity among modern markets, Thirteen Loko is an all-Earth original. With a name coined by the general consensus that only the mildly insane willing to imbibe it, this energy drink has garnered a notorious reputation for itself and a sizeable cult following to match it. After a series of legal proceedings by Weyland-Yutani, denatured cobra venom was removed from the recipe, much to the disappointment of the drink's consumers." icon_state = "thirteen_loko" center_of_mass = "x=16;y=8" @@ -224,13 +225,13 @@ . = ..() reagents.add_reagent("lemon_lime", 30) -/obj/item/reagent_container/food/drinks/cans/lemon_lime +/obj/item/reagent_container/food/drinks/cans/iced_tea name = "iced tea can" desc = "Just like the squad redneck's grandmother used to buy." icon_state = "ice_tea_can" center_of_mass = "x=16;y=10" -/obj/item/reagent_container/food/drinks/cans/lemon_lime/Initialize() +/obj/item/reagent_container/food/drinks/cans/iced_tea/Initialize() . = ..() reagents.add_reagent("icetea", 30) @@ -269,6 +270,7 @@ /obj/item/reagent_container/food/drinks/cans/boda name = "\improper Boda" desc = "State regulated soda beverage. Enjoy comrades." + desc_lore = "Designed back in 2159, the advertising campaign for BODA started out as an attempt by the UPP to win the hearts and minds of colonists and settlers across the galaxy. Soon after, the ubiquitous cyan vendors and large supplies of the drink began to crop up in UA warehouses with seemingly no clear origin. Despite some concerns, after initial testing determined that the stored products were safe for consumption and surprisingly popular when blind-tested with focus groups, the strange surplus of BODA was authorized for usage within the UA-associated colonies. Subsequently, it enjoyed a relative popularity before falling into obscurity in the coming decades as supplies dwindled." icon_state = "boda" center_of_mass = "x=16;y=10" diff --git a/code/game/objects/items/reagent_containers/food/condiment.dm b/code/game/objects/items/reagent_containers/food/condiment.dm index 7318a7b0165d..a13489f0af1e 100644 --- a/code/game/objects/items/reagent_containers/food/condiment.dm +++ b/code/game/objects/items/reagent_containers/food/condiment.dm @@ -202,6 +202,7 @@ /obj/item/reagent_container/food/condiment/hotsauce/franks name = "\improper Frank's Red Hot bottle" desc = "A bottle of Weyland-Yutani brand Frank's Red Hot hot sauce." + desc_lore = "Supposedly designed as a middle-ground flavor between ketchup and cayenne, this brand of spicy goodness achieved critical acclaim throughout UA space within both colonies and vessels alike. The sudden and widespread adoption was curiously timed with the near-simultaneous shelving of the original Frank's 'ULTRA' hot sauce." icon_state = "hotsauce_franks" item_state = "hotsauce_franks" diff --git a/code/game/objects/items/reagent_containers/food/fish_snacks.dm b/code/game/objects/items/reagent_containers/food/fish_snacks.dm index 9e9dcb1b8017..ba4a3c05fb0f 100644 --- a/code/game/objects/items/reagent_containers/food/fish_snacks.dm +++ b/code/game/objects/items/reagent_containers/food/fish_snacks.dm @@ -13,7 +13,7 @@ var/gut_icon_state = null var/gut_time = 3 var/initial_desc = "" - var/list/guttable_atoms = list(/obj/item/reagent_container/food/snacks/meat, /obj/item/reagent_container/food/snacks/meat/syntiflesh)//placeholders, for now + var/list/guttable_atoms = list(/obj/item/reagent_container/food/snacks/meat, /obj/item/reagent_container/food/snacks/meat/synthmeat)//placeholders, for now var/base_gut_meat = /obj/item/reagent_container/food/snacks/meat //slice_path = null// //slices_num diff --git a/code/game/objects/items/reagent_containers/food/snacks.dm b/code/game/objects/items/reagent_containers/food/snacks.dm index 80af9cf47b8d..06a4d785e677 100644 --- a/code/game/objects/items/reagent_containers/food/snacks.dm +++ b/code/game/objects/items/reagent_containers/food/snacks.dm @@ -60,28 +60,32 @@ if(istype(M, /mob/living/carbon)) var/mob/living/carbon/C = M var/fullness = M.nutrition + (M.reagents.get_reagent_amount("nutriment") * 25) - if(fullness > 540 && world.time < C.overeat_cooldown) + if(fullness > NUTRITION_HIGH && world.time < C.overeat_cooldown) to_chat(user, SPAN_WARNING("[user == M ? "You" : "They"] don't feel like eating more right now.")) return if(issynth(C)) fullness = 200 //Synths never get full - if(fullness > 540) + if(HAS_TRAIT(M, TRAIT_CANNOT_EAT)) //Do not feed the Working Joes + to_chat(user, SPAN_DANGER("[user == M ? "You are" : "[M] is"] unable to eat!")) + return + + if(fullness > NUTRITION_HIGH) C.overeat_cooldown = world.time + OVEREAT_TIME if(M == user)//If you're eating it yourself - if (fullness <= 50) + if (fullness <= NUTRITION_VERYLOW) to_chat(M, SPAN_WARNING("You hungrily chew out a piece of [src] and gobble it!")) - if (fullness > 50 && fullness <= 150) + if (fullness > NUTRITION_VERYLOW && fullness <= NUTRITION_LOW) to_chat(M, SPAN_NOTICE(" You hungrily begin to eat [src].")) - if (fullness > 150 && fullness <= 350) + if (fullness > NUTRITION_LOW && fullness <= NUTRITION_NORMAL) to_chat(M, SPAN_NOTICE(" You take a bite of [src].")) - if (fullness > 350 && fullness <= 540) + if (fullness > NUTRITION_NORMAL && fullness <= NUTRITION_HIGH) to_chat(M, SPAN_NOTICE(" You unwillingly chew a bit of [src].")) - if (fullness > 540) + if (fullness > NUTRITION_HIGH) to_chat(M, SPAN_WARNING("You reluctantly force more of [src] to go down your throat.")) else - if (fullness <= 540) + if (fullness <= NUTRITION_HIGH) user.affected_message(M, SPAN_HELPFUL("You start feeding [user == M ? "yourself" : "[M]"] [src]."), SPAN_HELPFUL("[user] starts feeding you [src]."), @@ -942,7 +946,7 @@ /obj/item/reagent_container/food/snacks/waffles name = "waffles" - desc = "Mmm, waffles" + desc = "Mmm, waffles." icon_state = "waffles" trash = /obj/item/trash/waffles filling_color = "#E6DEB5" @@ -953,6 +957,19 @@ reagents.add_reagent("sugar", 3) bitesize = 2 +/obj/item/reagent_container/food/snacks/pancakes + name = "pancakes" + desc = "Golden brown creamy pancakes fresh from the griddle. Drizzled with maple syrup and topped with a slice of butter." + icon_state = "pancakes" + filling_color = "#bb9857" + bitesize = 2 + +/obj/item/reagent_container/food/snacks/pancakes/Initialize() + . = ..() + reagents.add_reagent("bread", 6) + reagents.add_reagent("sugar", 4) + reagents.add_reagent("milk", 5) + /obj/item/reagent_container/food/snacks/eggplantparm name = "Eggplant Parmigiana" desc = "The only good recipe for eggplant." @@ -3230,6 +3247,19 @@ reagents.add_reagent("bread", 4) reagents.add_reagent("sodiumchloride", 12) +/obj/item/reagent_container/food/snacks/kepler_crisps/flamehot + name = "Kepler Flamehot" + desc = "'They're disturbingly good!' Due to an exceptionally well-timed ad campaign with the release of Kepler Flamehot in 2165, the Kepler brand was able to overtake other confectionary Weyland products by quarter three of that year. Contains 0% trans fat." + icon_state = "flamehotkepler" + bitesize = 2 + trash = /obj/item/trash/kepler/flamehot + +/obj/item/reagent_container/food/snacks/kepler_crisps/flamehot/Initialize() + . = ..() + reagents.add_reagent("bread", 4) + reagents.add_reagent("sodiumchloride", 4) + reagents.add_reagent("hotsauce", 8) + //Wrapped candy bars /obj/item/reagent_container/food/snacks/wrapped diff --git a/code/game/objects/items/reagent_containers/food/snacks/meat.dm b/code/game/objects/items/reagent_containers/food/snacks/meat.dm index 0174af8520d2..f459d1b169ae 100644 --- a/code/game/objects/items/reagent_containers/food/snacks/meat.dm +++ b/code/game/objects/items/reagent_containers/food/snacks/meat.dm @@ -24,10 +24,20 @@ else ..() -/obj/item/reagent_container/food/snacks/meat/syntiflesh +/obj/item/reagent_container/food/snacks/meat/synthmeat name = "synthetic meat" desc = "A synthetic slab of flesh." +/obj/item/reagent_container/food/snacks/meat/synthmeat/synthflesh //meat made from synthetics. Slightly toxic + name = "synthetic flesh" + desc = "A slab of artificial, inorganic 'flesh' that resembles human meat. Probably came from a synth." + icon_state = "synthmeat" + filling_color = "#ffffff" + +/obj/item/reagent_container/food/snacks/meat/synthmeat/synthetic/Initialize() + . = ..() + reagents.add_reagent("pacid", 1.5) + /obj/item/reagent_container/food/snacks/meat/human name = "human meat" desc = "A slab of flesh for cannibals." diff --git a/code/game/objects/items/reagent_containers/glass.dm b/code/game/objects/items/reagent_containers/glass.dm index fe4ef0a0c2bd..240809b7851f 100644 --- a/code/game/objects/items/reagent_containers/glass.dm +++ b/code/game/objects/items/reagent_containers/glass.dm @@ -677,9 +677,3 @@ if(do_after(user,30, INTERRUPT_ALL, BUSY_ICON_GENERIC)) user.visible_message("[user] finishes wiping off the [AM]!") AM.clean_blood() - - -/obj/item/reagent_container/glass/rag/get_examine_text(mob/user) - . = ..() - . += "That's \a [src]." - . += desc diff --git a/code/game/objects/items/reagent_containers/pill.dm b/code/game/objects/items/reagent_containers/pill.dm index dcc4ec1e42d8..de86ad07f53a 100644 --- a/code/game/objects/items/reagent_containers/pill.dm +++ b/code/game/objects/items/reagent_containers/pill.dm @@ -166,10 +166,6 @@ pill_initial_reagents = list("cyanide" = 50) pill_icon_class = "tox" -/obj/item/reagent_container/pill/adminordrazine - pill_desc = "An Adminordrazine pill. It's magic. We don't have to explain it." - pill_initial_reagents = list("adminordrazine" = 50) - /obj/item/reagent_container/pill/stox pill_desc = "A sleeping pill commonly used to treat insomnia." pill_initial_reagents = list("stoxin" = 15) @@ -255,11 +251,6 @@ pill_initial_reagents = list("bicaridine" = 15) pill_icon_class = "bica" -/obj/item/reagent_container/pill/quickclot - pill_desc = "A Quickclot pill. Stabilizes internal bleeding temporarily." - pill_initial_reagents = list("quickclot" = 7) - pill_icon_class = "qc" - /obj/item/reagent_container/pill/ultrazine pill_desc = "An Ultrazine pill. A highly-potent, long-lasting combination CNS and muscle stimulant. Extremely addictive." pill_initial_reagents = list("ultrazine" = 5) diff --git a/code/game/objects/items/stacks/flags.dm b/code/game/objects/items/stacks/flags.dm index 3894ed2afbe0..bc55096211d4 100644 --- a/code/game/objects/items/stacks/flags.dm +++ b/code/game/objects/items/stacks/flags.dm @@ -2,7 +2,7 @@ /obj/item/stack/flag name = "flags" - desc = "Some colourful flags." + desc = "Some colorful flags." singular_name = "flag" amount = 10 max_amount = 10 diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 4c71c2a87e8d..f96903cfb687 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -101,7 +101,7 @@ gender = PLURAL singular_name = "ointment" icon_state = "ointment" - heal_burn = 1 + heal_burn = 5 stack_id = "ointment" @@ -120,7 +120,7 @@ return 1 if(affecting.get_incision_depth()) - to_chat(user, SPAN_NOTICE("[M]'s [affecting.display_name] is cut open, you'll need more than a bandage!")) + to_chat(user, SPAN_NOTICE("[M]'s [affecting.display_name] is cut open, you'll need more than an ointment!")) return TRUE var/possessive = "[user == M ? "your" : "\the [M]'s"]" @@ -131,6 +131,7 @@ SPAN_HELPFUL("You salve the burns on [possessive] [affecting.display_name]."), SPAN_HELPFUL("[user] salves the burns on your [affecting.display_name]."), SPAN_NOTICE("[user] salves the burns on [possessive_their] [affecting.display_name].")) + affecting.heal_damage(burn = heal_burn) use(1) playsound(user, 'sound/handling/ointment_spreading.ogg', 25, 1, 2) if(WOUNDS_ALREADY_TREATED) @@ -141,9 +142,9 @@ return TRUE /obj/item/stack/medical/advanced/bruise_pack - name = "advanced trauma kit" - singular_name = "advanced trauma kit" - desc = "An advanced trauma kit for severe injuries." + name = "trauma kit" + singular_name = "trauma kit" + desc = "A trauma kit for severe injuries." icon_state = "traumakit" heal_brute = 12 @@ -166,7 +167,7 @@ heal_amt = 3 //non optimal application means less healing if(affecting.get_incision_depth()) - to_chat(user, SPAN_NOTICE("[M]'s [affecting.display_name] is cut open, you'll need more than a bandage!")) + to_chat(user, SPAN_NOTICE("[M]'s [affecting.display_name] is cut open, you'll need more than a trauma kit!")) return TRUE var/possessive = "[user == M ? "your" : "\the [M]'s"]" @@ -208,13 +209,13 @@ stack_id = "soothing herbs" alien = TRUE /obj/item/stack/medical/advanced/ointment - name = "advanced burn kit" - singular_name = "advanced burn kit" - desc = "An advanced treatment kit for severe burns." + name = "burn kit" + singular_name = "burn kit" + desc = "A treatment kit for severe burns." icon_state = "burnkit" heal_burn = 12 - stack_id = "advanced burn kit" + stack_id = "burn kit" /obj/item/stack/medical/advanced/ointment/attack(mob/living/carbon/M as mob, mob/user as mob) if(..()) @@ -233,7 +234,7 @@ heal_amt = 3 //non optimal application means less healing if(affecting.get_incision_depth()) - to_chat(user, SPAN_NOTICE("[M]'s [affecting.display_name] is cut open, you'll need more than a bandage!")) + to_chat(user, SPAN_NOTICE("[M]'s [affecting.display_name] is cut open, you'll need more than a burn kit!")) return TRUE var/possessive = "[user == M ? "your" : "\the [M]'s"]" diff --git a/code/game/objects/items/stacks/predator.dm b/code/game/objects/items/stacks/predator.dm index 1397088cb3c2..42874b907e02 100644 --- a/code/game/objects/items/stacks/predator.dm +++ b/code/game/objects/items/stacks/predator.dm @@ -15,41 +15,49 @@ max_amount = 8 /obj/item/stack/yautja_rope/attack(mob/living/mob_victim, mob/living/carbon/human/user) - . = ..() - if(!.) - return + if(mob_victim.stat != DEAD) + return ..() + + if(mob_victim.mob_size != MOB_SIZE_HUMAN) + to_chat(user, SPAN_WARNING("[mob_victim] has the wrong body plan to hang up.")) + return TRUE if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) to_chat(user, SPAN_WARNING("You're not strong enough to lift [mob_victim] up with a rope. Also, that's kind of fucked up.")) - return - - if(mob_victim.mob_size != MOB_SIZE_HUMAN) - return + return TRUE var/mob/living/carbon/human/victim = mob_victim - if(victim.stat != DEAD) - return if(!do_after(user, 1 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, victim)) - return + return TRUE + + user.visible_message(SPAN_NOTICE("[user] starts to secure \his rope to the ceiling..."), + SPAN_NOTICE("You start securing the rope to the ceiling...")) - to_chat(user, SPAN_NOTICE("You start securing the rope to the ceiling...")) if(do_after(user, 4 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, victim)) var/turf/rturf = get_turf(victim) var/area/rarea = get_area(victim) if(rturf.density) to_chat(user, SPAN_WARNING("They're in a wall!")) - return + return TRUE if(rarea.ceiling == CEILING_NONE) - to_chat(user, SPAN_WARNING("There's no ceiling!")) + to_chat(user, SPAN_WARNING("There's no ceiling to hang them from!")) + return TRUE + user.visible_message(SPAN_NOTICE("[user] secures the rope."), + SPAN_NOTICE("You secure the rope.")) + if(!do_after(user, 1 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, victim)) + return + user.visible_message(SPAN_WARNING("[user] begins hanging [victim] up by the rope..."), + SPAN_NOTICE("You start hanging [victim] up by the rope...")) + if(!do_after(user, 3 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, victim)) return - to_chat(user, SPAN_NOTICE("You secure the rope.")) - to_chat(user, SPAN_NOTICE("You start hanging [victim] by the rope...")) - if(do_after(user, 4 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, victim)) - to_chat(user, SPAN_NOTICE("You finish the hanging of [victim].")) - user.stop_pulling() - victim.get_hung() - use(1) + if(victim.anchored) + return // Just in case weed_food took them during this time + user.visible_message(SPAN_WARNING("[user] hangs [victim] from the ceiling!"), SPAN_NOTICE("You finish hanging [victim].")) + user.stop_pulling() + victim.get_hung() + use(1) + return TRUE /mob/living/carbon/human/proc/get_hung() animate(src, pixel_y = 9, time = 0.5 SECONDS, easing = SINE_EASING|EASE_OUT) @@ -100,4 +108,5 @@ apply_transform(A) pixel_x = 0 pixel_y = 0 + Moved(loc, NONE, TRUE) // Trigger any movement signals return COMPONENT_CANCEL_ATTACK diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 34719747bd02..98a7ab036f06 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -144,6 +144,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \ /* new/datum/stack_recipe("table parts", /obj/item/frame/table/wood, 2), \ */ + new/datum/stack_recipe("campfire", /obj/structure/prop/brazier/frame/full/campfire, 5, time = 15, one_per_turf = ONE_TYPE_PER_TURF, on_floor = TRUE), \ new/datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood/normal, 1, time = 10, one_per_turf = ONE_TYPE_PER_TURF, on_floor = 1), \ new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 20, one_per_turf = ONE_TYPE_PER_BORDER, on_floor = 1), \ new/datum/stack_recipe("wooden crate", /obj/structure/closet/coffin/woodencrate, 5, time = 15, one_per_turf = ONE_TYPE_PER_TURF, on_floor = 1), \ diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index cd9bbf3cd946..3bf3656f4bd2 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -53,7 +53,7 @@ user.visible_message(SPAN_NOTICE("\The [user] starts strapping \the [src] onto [target_mob]."), \ SPAN_NOTICE("You start strapping \the [src] onto [target_mob]."), null, 5, CHAT_TYPE_FLUFF_ACTION) - if(!do_after(user, HUMAN_STRIP_DELAY * user.get_skill_duration_multiplier(), INTERRUPT_ALL, BUSY_ICON_GENERIC, target_mob, INTERRUPT_MOVED, BUSY_ICON_GENERIC)) + if(!do_after(user, HUMAN_STRIP_DELAY * user.get_skill_duration_multiplier(SKILL_CQC), INTERRUPT_ALL, BUSY_ICON_GENERIC, target_mob, INTERRUPT_MOVED, BUSY_ICON_GENERIC)) to_chat(user, SPAN_WARNING("You were interrupted!")) return FALSE @@ -210,8 +210,8 @@ to_chat(user, SPAN_DANGER("The Bluespace portal resists your attempt to add another item.")) //light failure else to_chat(user, SPAN_DANGER("The Bluespace generator malfunctions!")) - for (var/obj/O in src.contents) //it broke, delete what was in it - qdel(O) + for (var/obj/thing in contents) //it broke, delete what was in it + qdel(thing) crit_fail = 1 icon_state = "brokenpack" @@ -359,17 +359,17 @@ /obj/item/storage/backpack/satchel/vir name = "virologist satchel" - desc = "A sterile satchel with virologist colours." + desc = "A sterile satchel with virologist colors." icon_state = "satchel-vir" /obj/item/storage/backpack/satchel/chem name = "chemist satchel" - desc = "A sterile satchel with chemist colours." + desc = "A sterile satchel with chemist colors." icon_state = "satchel-chem" /obj/item/storage/backpack/satchel/gen name = "geneticist satchel" - desc = "A sterile satchel with geneticist colours." + desc = "A sterile satchel with geneticist colors." icon_state = "satchel-gen" /obj/item/storage/backpack/satchel/tox @@ -399,6 +399,36 @@ xeno_icon_state = "marinepack" xeno_types = list(/mob/living/carbon/xenomorph/runner, /mob/living/carbon/xenomorph/praetorian, /mob/living/carbon/xenomorph/drone, /mob/living/carbon/xenomorph/warrior, /mob/living/carbon/xenomorph/defender, /mob/living/carbon/xenomorph/sentinel, /mob/living/carbon/xenomorph/spitter) +/obj/item/storage/backpack/marine/ammo_rack + name = "\improper IMP ammo rack" + desc = "A bare IMP frame with buckles designed to hold multiple ammo cans, but can fit any cumbersome box thanks to Marine ingenuity. Helps you lug around extra rounds or supplies." + has_gamemode_skin = FALSE + storage_slots = 3 + icon_state = "ammo_pack_0" + can_hold = list(/obj/item/ammo_box) + max_w_class = SIZE_MASSIVE + throw_range = 0 + xeno_types = null + var/base_icon_state = "ammo_pack" + var/move_delay_mult = 0.4 + +/obj/item/storage/backpack/marine/ammo_rack/update_icon() + . = ..() + icon_state = "[base_icon_state]_[length(contents)]" + +/obj/item/storage/backpack/marine/ammo_rack/pickup(mob/user, silent) + . = ..() + RegisterSignal(user, COMSIG_HUMAN_POST_MOVE_DELAY, PROC_REF(handle_movedelay)) + +/obj/item/storage/backpack/marine/ammo_rack/proc/handle_movedelay(mob/user, list/movedata) + SIGNAL_HANDLER + if(locate(/obj/item/storage/backpack/marine/ammo_rack) in user.contents) + movedata["move_delay"] += move_delay_mult + +/obj/item/storage/backpack/marine/ammo_rack/dropped(mob/user, silent) + . = ..() + UnregisterSignal(user, COMSIG_HUMAN_POST_MOVE_DELAY) + /obj/item/storage/backpack/marine/medic name = "\improper USCM corpsman backpack" desc = "A standard-issue backpack worn by USCM medics." @@ -407,6 +437,10 @@ xeno_icon_state = "medicpack" xeno_types = list(/mob/living/carbon/xenomorph/runner, /mob/living/carbon/xenomorph/praetorian, /mob/living/carbon/xenomorph/drone, /mob/living/carbon/xenomorph/warrior, /mob/living/carbon/xenomorph/defender, /mob/living/carbon/xenomorph/sentinel, /mob/living/carbon/xenomorph/spitter) +/obj/item/storage/backpack/marine/medic/upp + name = "\improper UPP corpsman backpack" + desc = "Uncommon issue backpack worn by UPP medics from isolated sectors. You can swear you can see a faded USCM symbol." + /obj/item/storage/backpack/marine/tech name = "\improper USCM technician backpack" desc = "A standard-issue backpack worn by USCM technicians." @@ -460,10 +494,9 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r flags_item = ITEM_OVERRIDE_NORTHFACE - uniform_restricted = list(/obj/item/clothing/under/marine/rto) var/obj/structure/transmitter/internal/internal_transmitter - var/phone_category = PHONE_RTO + var/phone_category = PHONE_MARINE var/network_receive = FACTION_MARINE var/list/networks_transmit = list(FACTION_MARINE) var/base_icon @@ -477,12 +510,9 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r button.overlays += IMG /datum/action/item_action/rto_pack/use_phone/action_activate() - if(!istype(owner, /mob/living/carbon/human)) + for(var/obj/item/storage/backpack/marine/satchel/rto/radio_backpack in owner) + radio_backpack.use_phone(owner) return - var/mob/living/carbon/human/user = owner - if(istype(user.back, /obj/item/storage/backpack/marine/satchel/rto)) - var/obj/item/storage/backpack/marine/satchel/rto/R = user.back - R.use_phone(user) /obj/item/storage/backpack/marine/satchel/rto/post_skin_selection() base_icon = icon_state @@ -517,11 +547,6 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r else icon_state = base_icon -/obj/item/storage/backpack/marine/satchel/rto/item_action_slot_check(mob/user, slot) - if(slot == WEAR_BACK) - return TRUE - return FALSE - /obj/item/storage/backpack/marine/satchel/rto/forceMove(atom/dest) . = ..() if(isturf(dest)) @@ -558,10 +583,7 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r internal_transmitter.enabled = FALSE /obj/item/storage/backpack/marine/satchel/rto/proc/use_phone(mob/user) - if(user.back == src) - internal_transmitter.attack_hand(user) - else if(internal_transmitter.get_calling_phone()) - internal_transmitter.attack_hand(user) + internal_transmitter.attack_hand(user) /obj/item/storage/backpack/marine/satchel/rto/attackby(obj/item/W, mob/user) @@ -578,9 +600,6 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r name = "\improper USCM Small Radio Telephone Pack" max_storage_space = 10 - uniform_restricted = null - phone_category = PHONE_MARINE - /obj/item/storage/backpack/marine/satchel/rto/small/upp_net network_receive = FACTION_UPP @@ -657,7 +676,7 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r /obj/item/storage/backpack/general_belt/equipped(mob/user, slot) switch(slot) - if(WEAR_WAIST, WEAR_J_STORE) //The G8 can be worn on several armours. + if(WEAR_WAIST, WEAR_J_STORE) //The G8 can be worn on several armors. mouse_opacity = MOUSE_OPACITY_OPAQUE //so it's easier to click when properly equipped. ..() @@ -868,17 +887,21 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r return . = ..() -/obj/item/storage/backpack/marine/engineerpack/afterattack(obj/O as obj, mob/user as mob, 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(src, max_fuel) - to_chat(user, SPAN_NOTICE(" You crack the cap off the top of the pack and fill it back up again from the tank.")) - playsound(loc, 'sound/effects/refill.ogg', 25, TRUE, 3) - return - else if (istype(O, /obj/structure/reagent_dispensers/fueltank) && src.reagents.total_volume == max_fuel) - to_chat(user, SPAN_NOTICE(" The pack is already full!")) +/obj/item/storage/backpack/marine/engineerpack/afterattack(obj/target, mob/user, proximity) + if(!proximity) return + if(istype(target, /obj/structure/reagent_dispensers)) + if(!(istypestrict(target, /obj/structure/reagent_dispensers/fueltank))) + to_chat(user, SPAN_NOTICE("This must be filled with a fuel tank.")) + return + if(reagents.total_volume < max_fuel) + target.reagents.trans_to(src, max_fuel) + to_chat(user, SPAN_NOTICE("You crack the cap off the top of the pack and fill it back up again from the tank.")) + playsound(loc, 'sound/effects/refill.ogg', 25, TRUE, 3) + return + if(reagents.total_volume == max_fuel) + to_chat(user, SPAN_NOTICE("The pack is already full!")) + return ..() /obj/item/storage/backpack/marine/engineerpack/get_examine_text(mob/user) @@ -895,6 +918,16 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r max_fuel = 100 worn_accessible = TRUE +/obj/item/storage/backpack/marine/engineerpack/welder_chestrig + name = "\improper Technician Welder Chestrig" + desc = "A specialized Chestrig worn by technicians and engineers. It carries one medium fuel tank for quick welder refueling and use." + icon_state = "welder_chestrig" + item_state = "welder_chestrig" + max_storage_space = 12 + has_gamemode_skin = FALSE + max_fuel = 100 + worn_accessible = TRUE + // Pyrotechnician Spec backpack fuel tank /obj/item/storage/backpack/marine/engineerpack/flamethrower name = "\improper USCM Pyrotechnician G6-2 fueltank" @@ -904,6 +937,42 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r fuel_type = "utnapthal" has_gamemode_skin = TRUE +/obj/item/storage/backpack/marine/engineerpack/flamethrower/verb/remove_reagents() + set name = "Empty canister" + set category = "Object" + + set src in usr + + if(usr.get_active_hand() != src) + return + + if(alert(usr, "Do you really want to empty out [src]?", "Empty canister", "Yes", "No") != "Yes") + return + + reagents.clear_reagents() + + playsound(loc, 'sound/effects/refill.ogg', 25, 1, 3) + to_chat(usr, SPAN_NOTICE("You empty out [src]")) + update_icon() + +//this is to revert change for the backpack that are for flametrower usage. +// so that they can use custom mix to refill those backpack +/obj/item/storage/backpack/marine/engineerpack/flamethrower/afterattack(obj/target, mob/user, proximity) + if(!proximity) + return + if (!(istype(target, /obj/structure/reagent_dispensers/fueltank))) + return + + if (reagents.total_volume >= max_fuel) + to_chat(user, SPAN_NOTICE("The pack is already full!")) + return + + if(reagents.total_volume < max_fuel) + target.reagents.trans_to(src, max_fuel) + to_chat(user, SPAN_NOTICE("You crack the cap off the top of the pack and fill it back up again from the tank.")) + playsound(loc, 'sound/effects/refill.ogg', 25, TRUE, 3) + return + /obj/item/storage/backpack/marine/engineerpack/flamethrower/attackby(obj/item/W, mob/living/user) if (istype(W, /obj/item/ammo_magazine/flamer_tank)) var/obj/item/ammo_magazine/flamer_tank/FTL = W diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index f0a235b2301f..c86003b251da 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -30,24 +30,28 @@ item_state = "trashbag" w_class = SIZE_LARGE - max_w_class = SIZE_SMALL - storage_slots = 21 + max_w_class = SIZE_MEDIUM + storage_slots = null + max_storage_space = 21 //equivalent to an IMP backpack can_hold = list() // any cant_hold = list(/obj/item/disk/nuclear, /obj/item/weapon/throwing_knife) storage_flags = STORAGE_GATHER_SIMULTAENOUSLY|STORAGE_QUICK_GATHER|STORAGE_CLICK_GATHER + flags_equip_slot = NONE /obj/item/storage/bag/trash/update_icon() - if(contents.len == 0) + var/sum_storage_cost = 0 + for(var/obj/item/item in contents) + sum_storage_cost += item.get_storage_cost() + + if(!sum_storage_cost) icon_state = "trashbag0" - else if(contents.len < 12) + else if(sum_storage_cost < round(max_storage_space * 0.35)) icon_state = "trashbag1" - else if(contents.len < 21) + else if(sum_storage_cost < round(max_storage_space * 0.7)) icon_state = "trashbag2" - else icon_state = "trashbag3" - -/obj/item/storage/bag/trash/open(mob/user) - return + else + icon_state = "trashbag3" // ----------------------------- // Plastic Bag @@ -183,7 +187,7 @@ //Turned numbered display on. Appears to work as intended, despite above comment -- Vanagandr. /obj/item/storage/bag/sheetsnatcher/orient2hud() - var/adjusted_contents = contents.len + var/adjusted_contents = length(contents) //Numbered contents display var/list/datum/numbered_display/numbered_contents diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index bc7b1c9695ad..7721a9643fb5 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -3,6 +3,10 @@ desc = "Can hold various things." icon = 'icons/obj/items/clothing/belts.dmi' icon_state = "utilitybelt" + item_icons = list( + WEAR_L_HAND = 'icons/mob/humans/onmob/items_lefthand_1.dmi', + WEAR_R_HAND = 'icons/mob/humans/onmob/items_righthand_1.dmi' + ) item_state = "utility" flags_equip_slot = SLOT_WAIST attack_verb = list("whipped", "lashed", "disciplined") @@ -12,6 +16,26 @@ ///TRUE Means that it closes a flap over its contents, and therefore update_icon should lift that flap when opened. If it doesn't have _half and _full iconstates, this doesn't matter either way. var/flap = TRUE +/obj/item/storage/belt/gun/flaregun/dump_into(obj/item/storage/origin_storage, mob/user) + + if(length(holstered_guns) < 1 && length(contents) >= (storage_slots-1)) + + to_chat(user, SPAN_WARNING("[src] is full.")) + return FALSE + return ..() + +/obj/item/storage/belt/gun/flaregun/handle_item_insertion(obj/item/new_item, prevent_warning = FALSE, mob/user) + + if(istype(new_item, /obj/item/device/flashlight/flare) && length(holstered_guns) < 1 && length(contents) >= (storage_slots-1)) + return FALSE + return ..() + +/obj/item/storage/belt/gun/flaregun/has_room(obj/item/new_item, W_class_override = null) + + if(istype(new_item, /obj/item/device/flashlight/flare) && length(holstered_guns) < 1 && length(contents) >= (storage_slots-1)) + return FALSE //No slot open because gun in holster. + return ..() + /obj/item/storage/belt/equipped(mob/user, slot) switch(slot) if(WEAR_WAIST, WEAR_J_STORE, WEAR_BACK) @@ -106,6 +130,13 @@ new /obj/item/tool/wirecutters(src) new /obj/item/device/t_scanner(src) +/obj/item/storage/belt/utility/full/pred + name = "\improper Yautja toolbelt" + desc = "A modular belt with various clips. This version lacks any hunting functionality, and is commonly used by engineers to transport important tools." + icon = 'icons/obj/items/hunter/pred_gear.dmi' + icon_state = "utilitybelt_pred" + item_state = "utility" + /obj/item/storage/belt/medical name = "\improper M276 pattern medical storage rig" desc = "The M276 is the standard load-bearing equipment of the USCM. It consists of a modular belt with various clips. This version is a less common configuration, designed to transport medical supplies and pistol ammunition. \nRight click its sprite and click \"toggle belt mode\" to take pills out of bottles by simply clicking them." @@ -144,6 +175,8 @@ /obj/item/roller, /obj/item/tool/surgery/synthgraft, /obj/item/reagent_container/glass/minitank, + /obj/item/storage/surgical_case, + /obj/item/reagent_container/blood, ) /obj/item/storage/belt/medical/full/fill_preset_inventory() @@ -154,7 +187,6 @@ new /obj/item/storage/pill_bottle/inaprovaline(src) new /obj/item/storage/pill_bottle/tramadol(src) new /obj/item/storage/pill_bottle/peridaxon(src) - new /obj/item/storage/pill_bottle/quickclot(src) new /obj/item/stack/medical/splint(src) new /obj/item/stack/medical/advanced/bruise_pack(src) new /obj/item/stack/medical/advanced/ointment(src) @@ -220,7 +252,6 @@ new /obj/item/storage/pill_bottle/inaprovaline(src) new /obj/item/storage/pill_bottle/tramadol(src) new /obj/item/storage/pill_bottle/peridaxon(src) - new /obj/item/storage/pill_bottle/quickclot(src) new /obj/item/stack/medical/splint(src) /obj/item/storage/belt/medical/lifesaver/full/dutch/fill_preset_inventory() @@ -238,7 +269,6 @@ new /obj/item/storage/pill_bottle/inaprovaline(src) new /obj/item/storage/pill_bottle/tramadol(src) new /obj/item/storage/pill_bottle/peridaxon(src) - new /obj/item/storage/pill_bottle/quickclot(src) new /obj/item/stack/medical/splint(src) new /obj/item/device/healthanalyzer(src) new /obj/item/storage/pill_bottle/imidazoline(src) @@ -272,7 +302,19 @@ new /obj/item/storage/pill_bottle/inaprovaline(src) new /obj/item/storage/pill_bottle/tramadol(src) new /obj/item/storage/pill_bottle/peridaxon(src) - new /obj/item/storage/pill_bottle/quickclot(src) + +/obj/item/storage/belt/medical/lifesaver/upp/partial/fill_preset_inventory() + new /obj/item/stack/medical/advanced/bruise_pack(src) + new /obj/item/stack/medical/advanced/bruise_pack(src) + new /obj/item/stack/medical/advanced/ointment(src) + new /obj/item/stack/medical/advanced/ointment(src) + new /obj/item/stack/medical/splint(src) + new /obj/item/stack/medical/splint(src) + new /obj/item/reagent_container/hypospray/autoinjector/oxycodone(src) + new /obj/item/storage/pill_bottle/bicaridine(src) + new /obj/item/storage/pill_bottle/kelotane(src) + new /obj/item/storage/pill_bottle/inaprovaline(src) + new /obj/item/storage/pill_bottle/tramadol(src) /obj/item/storage/belt/security name = "\improper M276 pattern security rig" @@ -436,6 +478,10 @@ for(var/i = 1 to storage_slots) new /obj/item/ammo_magazine/rifle/m16/ap (src) +/obj/item/storage/belt/marine/dutch/m60/fill_preset_inventory() + for(var/i in 1 to storage_slots) + new /obj/item/ammo_magazine/m60 (src) + // Outer Rim Weapon Belts /obj/item/storage/belt/marine/ar10/fill_preset_inventory() // AR-10 @@ -626,7 +672,7 @@ /obj/item/storage/belt/shotgun/van_bandolier name = "two bore bandolier" - desc = "A leather bandolier designed to hold extremely heavy shells. Can be attached to armour, worn over the back, or attached to belt loops." + desc = "A leather bandolier designed to hold extremely heavy shells. Can be attached to armor, worn over the back, or attached to belt loops." icon_state = "van_bandolier_5" flags_equip_slot = SLOT_WAIST|SLOT_BACK storage_slots = null @@ -733,14 +779,14 @@ ) cant_hold = list() flap = FALSE - var/draw_cooldown = 0 - var/draw_cooldown_interval = 1 SECONDS + + COOLDOWN_DECLARE(draw_cooldown) /obj/item/storage/belt/knifepouch/fill_preset_inventory() for(var/i = 1 to storage_slots) new /obj/item/weapon/throwing_knife(src) -/obj/item/storage/belt/knifepouch/_item_insertion(obj/item/W, prevent_warning = 0) +/obj/item/storage/belt/knifepouch/_item_insertion(obj/item/new_item, prevent_warning = FALSE) ..() playsound(src, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) @@ -749,9 +795,9 @@ playsound(src, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) /obj/item/storage/belt/knifepouch/attack_hand(mob/user, mods) - if(draw_cooldown < world.time) + if(COOLDOWN_FINISHED(src, draw_cooldown)) ..() - draw_cooldown = world.time + draw_cooldown_interval + COOLDOWN_START(src, draw_cooldown, BAYONET_DRAW_DELAY) playsound(src, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) else to_chat(user, SPAN_WARNING("You need to wait before drawing another knife!")) @@ -814,8 +860,15 @@ new /obj/item/explosive/grenade/high_explosive/airburst(src) new /obj/item/explosive/grenade/high_explosive/airburst(src) +/obj/item/storage/belt/grenade/large/dutch + name = "\improper Dutch's Grenadier Rigging" + desc = "A high capacity rig filled to the brim with all the explosives you could ask for, what else is there to want?" - +/obj/item/storage/belt/grenade/large/dutch/full/fill_preset_inventory() + for(var/i in 1 to 6) + new /obj/item/explosive/grenade/incendiary/impact(src) + new /obj/item/explosive/grenade/high_explosive/impact(src) + new /obj/item/explosive/grenade/high_explosive/airburst/buckshot(src) @@ -880,6 +933,7 @@ for(var/slot in holster_slots) if(AM == holster_slots[slot]["gun"]) holster_slots[slot]["gun"] = null + update_gun_icon(slot) return @@ -955,7 +1009,7 @@ to_chat(usr, SPAN_WARNING("[src] can't hold any more ammo.")) return FALSE -/obj/item/storage/belt/gun/_item_insertion(obj/item/W, prevent_warning = 0) +/obj/item/storage/belt/gun/_item_insertion(obj/item/W, prevent_warning = FALSE) if(isgun(W)) holstered_guns += W for(var/slot in holster_slots) @@ -1113,6 +1167,22 @@ for(var/i = 1 to storage_slots - 1) new /obj/item/ammo_magazine/pistol/highpower/black(src) +/obj/item/storage/belt/gun/m39 + name = "\improper M276 pattern M39 holster rig" + desc = "Special issue variant of the M276 designed to holster a M39 submachine gun and two spare magazines. Uncommonly issued to USCM support and specialist personnel." + icon_state = "m39_armor" + item_state = "s_marinebelt" + storage_slots = 3 + max_w_class = 5 + can_hold = list( + /obj/item/weapon/gun/smg/m39, + /obj/item/ammo_magazine/smg, + ) + holster_slots = list( + "1" = list( + "icon_x" = -11, + "icon_y" = -5)) + /obj/item/storage/belt/gun/m44 name = "\improper M276 pattern M44 holster rig" desc = "The M276 is the standard load-bearing equipment of the USCM. It consists of a modular belt with various clips. This version is for the M44 magnum revolver, along with six small pouches for speedloaders. It smells faintly of hay." diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 8d93357f52da..6266f0eef77d 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -465,15 +465,6 @@ if(istype(W) && !W.heat_source && !W.burnt) W.light_match() -/obj/item/storage/box/quickclot - name = "box of quickclot injectors" - desc = "Contains quickclot autoinjectors." - icon_state = "syringe" - -/obj/item/storage/box/quickclot/fill_preset_inventory() - for (var/i; i < 7; i++) - new /obj/item/reagent_container/hypospray/autoinjector/quickclot(src) - /obj/item/storage/box/lights name = "box of replacement bulbs" icon = 'icons/obj/items/storage.dmi' diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm index 2e54d725511d..ea43d6b074b9 100644 --- a/code/game/objects/items/storage/fancy.dm +++ b/code/game/objects/items/storage/fancy.dm @@ -12,6 +12,8 @@ * Crayon Box * Cigarette Box * Cigar Box + * Match Box + * Vial Box */ /obj/item/storage/fancy @@ -20,9 +22,10 @@ name = "donut box" desc = "A box where round, heavenly, holey pastries reside." var/icon_type = "donut" + var/plural = "s" /obj/item/storage/fancy/update_icon() - icon_state = "[icon_type]box[contents.len]" + icon_state = "[icon_type]box[length(contents)]" /obj/item/storage/fancy/remove_from_storage(obj/item/W, atom/new_location) . = ..() @@ -32,17 +35,14 @@ /obj/item/storage/fancy/get_examine_text(mob/user) . = ..() - if(contents.len <= 0) - . += "There are no [src.icon_type]s left in the box." - else if(contents.len == 1) + if(!length(contents)) + . += "There are no [src.icon_type][plural] left in the box." + else if(length(contents) == 1) . += "There is one [src.icon_type] left in the box." else - . += "There are [src.contents.len] [src.icon_type]s in the box." - + . += "There are [length(src.contents)] [src.icon_type][plural] in the box." -/* - * Egg Box - */ +// EGG BOX /obj/item/storage/fancy/egg_box icon = 'icons/obj/items/food.dmi' @@ -59,9 +59,7 @@ new /obj/item/reagent_container/food/snacks/egg(src) return -/* - * Candle Box - */ +// CANDLE BOX /obj/item/storage/fancy/candle_box name = "candle pack" @@ -80,9 +78,7 @@ new /obj/item/tool/candle(src) return -/* - * Crayon Box - */ +// CRAYON BOX /obj/item/storage/fancy/crayons name = "box of crayons" @@ -120,9 +116,8 @@ return ..() -//////////// -//CIG PACK// -//////////// +// CIGARETTES BOX + /obj/item/storage/fancy/cigarettes icon = 'icons/obj/items/cigarettes.dmi' icon_state = "cigpacket" @@ -153,14 +148,14 @@ icon_state = "[initial(icon_state)]" /obj/item/storage/fancy/cigarettes/update_icon() - icon_state = "[initial(icon_state)][contents.len]" + icon_state = "[initial(icon_state)][length(contents)]" return /obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) if(!istype(M, /mob)) return - if(M == user && user.zone_selected == "mouth" && contents.len > 0 && !user.wear_mask) + if(M == user && user.zone_selected == "mouth" && length(contents) > 0 && !user.wear_mask) var/obj/item/clothing/mask/cigarette/C = locate() in src if(C) remove_from_storage(C, get_turf(user)) @@ -223,9 +218,7 @@ default_cig_type = /obj/item/clothing/mask/cigarette/ucigarette storage_slots = 4 -///////////// -//CIGAR BOX// -///////////// +// CIGAR BOX /obj/item/storage/fancy/cigar name = "cigar case" @@ -253,14 +246,14 @@ icon_state = "[initial(icon_state)]" /obj/item/storage/fancy/cigar/update_icon() - icon_state = "[initial(icon_state)][contents.len]" + icon_state = "[initial(icon_state)][length(contents)]" return /obj/item/storage/fancy/cigar/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) if(!istype(M, /mob)) return - if(M == user && user.zone_selected == "mouth" && contents.len > 0 && !user.wear_mask) + if(M == user && user.zone_selected == "mouth" && length(contents) > 0 && !user.wear_mask) var/obj/item/clothing/mask/cigarette/cigar/C = locate() in src if(C) remove_from_storage(C, get_turf(user)) @@ -286,6 +279,8 @@ storage_slots = 1 default_cigar_type = /obj/item/clothing/mask/cigarette/cigar/tarbacks +// MATCH BOX + /obj/item/storage/fancy/cigar/matchbook name = "\improper Lucky Strikes matchbook" desc = "A small book of cheap paper matches. Good luck getting them to light. Made by Lucky Strikes, but you'll be anything but lucky when you burn your hand trying to light a match on this." @@ -298,6 +293,7 @@ w_class = SIZE_TINY var/light_chance = 70 //how likely you are to light the match on the book var/burn_chance = 20 //how likely you are to burn yourself once you light it + plural = "es" /obj/item/storage/fancy/cigar/matchbook/attackby(obj/item/tool/match/W as obj, mob/living/carbon/human/user as mob) if(!istype(user)) @@ -340,9 +336,7 @@ light_chance = 60 burn_chance = 40 -/* - * Vial Box - */ +// VIAL BOX /obj/item/storage/fancy/vials icon = 'icons/obj/items/vialbox.dmi' @@ -401,7 +395,7 @@ req_access = list(ACCESS_MARINE_MEDBAY) /obj/item/storage/lockbox/vials/update_icon(itemremoved = 0) - var/total_contents = src.contents.len - itemremoved + var/total_contents = length(src.contents) - itemremoved src.icon_state = "vialbox[total_contents]" src.overlays.Cut() if (!broken) diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm index d61816f99508..5816da7740c3 100644 --- a/code/game/objects/items/storage/firstaid.dm +++ b/code/game/objects/items/storage/firstaid.dm @@ -69,6 +69,7 @@ /obj/item/storage/firstaid/regular icon_state = "firstaid" + desc = "It's an emergency medical kit containing basic medication and equipment. No training required to use." /obj/item/storage/firstaid/regular/fill_preset_inventory() new /obj/item/device/healthanalyzer(src) @@ -99,7 +100,7 @@ /obj/item/storage/firstaid/toxin name = "toxin first-aid kit" - desc = "Used to treat when you have a high amount of toxins in your body." + desc = "It's an emergency medical kit containing lifesaving anti-toxic medication." icon_state = "antitoxin" item_state = "firstaid-toxin" possible_icons_full = list("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3") @@ -134,7 +135,7 @@ /obj/item/storage/firstaid/adv name = "advanced first-aid kit" - desc = "Contains advanced medical treatments." + desc = "Contains more effective methods of medical treatment than a basic first-aid kit, such as burn and trauma kits." icon_state = "advfirstaid" item_state = "firstaid-advanced" @@ -211,6 +212,22 @@ /obj/item/storage/firstaid/surgical/empty/fill_preset_inventory() return +//---------TOOLKIT--------- + +/obj/item/storage/firstaid/toolkit + name = "toolkit" + desc = "An combat engineering toolkit intended to carry electrical and mechanical supplies into combat." + icon_state = "toolkit" + item_state = "fulton" + +/obj/item/storage/firstaid/toolkit/update_icon() + if(content_watchers || !length(contents)) + icon_state = "toolkit_empty" + else + icon_state = icon_full + +/obj/item/storage/firstaid/toolkit/empty/fill_preset_inventory() + return //---------SYRINGE CASE--------- @@ -259,6 +276,37 @@ new /obj/item/reagent_container/glass/bottle/inaprovaline( src ) new /obj/item/reagent_container/glass/bottle/dexalin( src ) +//---------SURGICAL CASE--------- + + +/obj/item/storage/surgical_case + name = "surgical case" + desc = "It's a medical case for storing basic surgical tools. It comes with a brief description for treating common internal bleeds.\ + \nBefore surgery: Verify correct location and patient is adequately numb to pain.\ + \nStep one: Open an incision at the site with the scalpel.\ + \nStep two: Clamp bleeders with the hemostat.\ + \nStep three: Draw back the skin with the retracter.\ + \nStep four: Patch the damaged vein with a surgical line.\ + \nStep five: Close the incision with a surgical line." + + icon_state = "surgical_case" + throw_speed = SPEED_FAST + throw_range = 8 + storage_slots = 3 + w_class = SIZE_SMALL + matter = list("plastic" = 1000) + can_hold = list( + /obj/item/tool/surgery/scalpel, + /obj/item/tool/surgery/hemostat, + /obj/item/tool/surgery/retractor, + ) + +/obj/item/storage/surgical_case/regular + +/obj/item/storage/surgical_case/regular/fill_preset_inventory() + new /obj/item/tool/surgery/scalpel(src) + new /obj/item/tool/surgery/hemostat(src) + new /obj/item/tool/surgery/retractor(src) //---------PILL BOTTLES--------- @@ -423,6 +471,22 @@ ..() update_icon() +/obj/item/storage/pill_bottle/attack_hand(mob/user, mods) + if(loc != user) + return ..() + + if(!mods || !mods["alt"]) + return ..() + + if(!ishuman(user)) + return ..() + + if(skilllock && !skillcheck(user, SKILL_MEDICAL, SKILL_MEDICAL_MEDIC)) + error_idlock(user) + return FALSE + + return ..() + /obj/item/storage/pill_bottle/proc/error_idlock(mob/user) to_chat(user, SPAN_WARNING("It must have some kind of ID lock...")) @@ -546,56 +610,41 @@ /obj/item/storage/pill_bottle/russianRed/skillless skilllock = SKILL_MEDICAL_DEFAULT - -/obj/item/storage/pill_bottle/quickclot - name = "\improper Quickclot pill bottle" - icon_state = "pill_canister8" - pill_type_to_fill = /obj/item/reagent_container/pill/quickclot - maptext_label = "Qc" - -/obj/item/storage/pill_bottle/quickclot/skillless - skilllock = SKILL_MEDICAL_DEFAULT - //Ultrazine /obj/item/storage/pill_bottle/ultrazine name = "pill bottle" icon_state = "pill_canister11" max_storage_space = 5 skilllock = SKILL_MEDICAL_DEFAULT //CL can open it - var/idlock = 1 + var/idlock = TRUE pill_type_to_fill = /obj/item/reagent_container/pill/ultrazine/unmarked display_maptext = FALSE //for muh corporate secrets - Stan_Albatross - req_access = list(ACCESS_WY_CORPORATE) - var/req_role = JOB_CORPORATE_LIAISON + req_one_access = list(ACCESS_WY_EXEC, ACCESS_WY_RESEARCH) black_market_value = 35 /obj/item/storage/pill_bottle/ultrazine/proc/id_check(mob/user) if(!idlock) - return 1 + return TRUE var/mob/living/carbon/human/H = user if(!allowed(user)) to_chat(user, SPAN_NOTICE("It must have some kind of ID lock...")) - return 0 + return FALSE var/obj/item/card/id/I = H.wear_id if(!istype(I)) //not wearing an ID to_chat(H, SPAN_NOTICE("It must have some kind of ID lock...")) - return 0 + return FALSE if(I.registered_name != H.real_name) to_chat(H, SPAN_WARNING("Wrong ID card owner detected.")) - return 0 - - if(req_role && I.rank != req_role) - to_chat(H, SPAN_NOTICE("It must have some kind of ID lock...")) - return 0 + return FALSE - return 1 + return TRUE /obj/item/storage/pill_bottle/ultrazine/attack_self(mob/living/user) if(!id_check(user)) @@ -609,7 +658,7 @@ /obj/item/storage/pill_bottle/ultrazine/skillless name = "\improper Ultrazine pill bottle" - idlock = 0 + idlock = FALSE display_maptext = TRUE maptext_label = "Uz" diff --git a/code/game/objects/items/storage/lockbox.dm b/code/game/objects/items/storage/lockbox.dm index aa9d91921fae..50a6cc92cb5f 100644 --- a/code/game/objects/items/storage/lockbox.dm +++ b/code/game/objects/items/storage/lockbox.dm @@ -51,14 +51,12 @@ /obj/item/storage/lockbox/loyalty name = "\improper Wey-Yu equipment lockbox" - req_access = list(ACCESS_WY_CORPORATE) + req_one_access = list(ACCESS_WY_EXEC, ACCESS_WY_SECURITY) /obj/item/storage/lockbox/loyalty/fill_preset_inventory() - new /obj/item/ammo_magazine/pistol/mod88(src) - new /obj/item/ammo_magazine/pistol/mod88(src) - new /obj/item/ammo_magazine/pistol/mod88/rubber(src) - new /obj/item/ammo_magazine/pistol/mod88/rubber(src) - + new /obj/item/ammo_magazine/pistol/es4(src) + new /obj/item/ammo_magazine/pistol/es4(src) + new /obj/item/ammo_magazine/pistol/es4(src) /obj/item/storage/lockbox/cluster name = "lockbox of cluster flashbangs" diff --git a/code/game/objects/items/storage/misc.dm b/code/game/objects/items/storage/misc.dm index 37feb6c50fc3..eb6f100f6e8b 100644 --- a/code/game/objects/items/storage/misc.dm +++ b/code/game/objects/items/storage/misc.dm @@ -124,17 +124,17 @@ new /obj/item/weapon/gun/pistol/clfpistol(src) new /obj/item/ammo_magazine/pistol/clfpistol(src) -/obj/item/storage/box/c02_knife +/obj/item/storage/box/co2_knife name = "M8 cartridge bayonet packaging" - desc = "Contains one M8 Cartridge Bayonet and two sister C02 cartridges. Thanks for being a dedicated Boots magazine subscriber!" - icon_state = "c02_box" - can_hold = list(/obj/item/attachable/bayonet/c02, /obj/item/c02_cartridge) + desc = "Contains one M8 Cartridge Bayonet and two sister CO2 cartridges. Thanks for being a dedicated Boots magazine subscriber!" + icon_state = "co2_box" + can_hold = list(/obj/item/attachable/bayonet/co2, /obj/item/co2_cartridge) foldable = TRUE storage_slots = 3 w_class = SIZE_SMALL max_w_class = SIZE_SMALL -/obj/item/storage/box/c02_knife/fill_preset_inventory() - new /obj/item/attachable/bayonet/c02(src) - new /obj/item/c02_cartridge(src) - new /obj/item/c02_cartridge(src) +/obj/item/storage/box/co2_knife/fill_preset_inventory() + new /obj/item/attachable/bayonet/co2(src) + new /obj/item/co2_cartridge(src) + new /obj/item/co2_cartridge(src) diff --git a/code/game/objects/items/storage/pouch.dm b/code/game/objects/items/storage/pouch.dm index 65e44a1dd7e2..6397c33b76c1 100644 --- a/code/game/objects/items/storage/pouch.dm +++ b/code/game/objects/items/storage/pouch.dm @@ -58,29 +58,12 @@ max_w_class = SIZE_MEDIUM cant_hold = list( //Prevent inventory bloat /obj/item/storage/firstaid, - /obj/item/storage/bible + /obj/item/storage/bible, + /obj/item/storage/box, ) storage_slots = null max_storage_space = 2 -/obj/item/storage/pouch/general/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/ammo_magazine/shotgun)) - var/obj/item/ammo_magazine/shotgun/M = W - dump_ammo_to(M,user) - else if(istype(W, /obj/item/storage/box/nade_box) || istype(W, /obj/item/storage/box/m94)) - dump_into(W, user) - else - return ..() - -/obj/item/storage/pouch/general/can_be_inserted(obj/item/W, stop_messages) - . = ..() - if(. && W.w_class == SIZE_MEDIUM) - for(var/obj/item/I in return_inv()) - if(I.w_class >= SIZE_MEDIUM) - if(!stop_messages) - to_chat(usr, SPAN_NOTICE("[src] is already too bulky with [I].")) - return FALSE - /obj/item/storage/pouch/general/medium name = "medium general pouch" desc = "A general-purpose pouch used to carry a variety of differently sized items." @@ -128,10 +111,10 @@ icon_state = "bayonet" storage_slots = 5 storage_flags = STORAGE_FLAGS_POUCH|STORAGE_USING_DRAWING_METHOD|STORAGE_ALLOW_QUICKDRAW - var/draw_cooldown = 0 - var/draw_cooldown_interval = 1 SECONDS var/default_knife_type = /obj/item/weapon/throwing_knife + COOLDOWN_DECLARE(draw_cooldown) + /obj/item/storage/pouch/bayonet/Initialize() . = ..() for(var/total_storage_slots in 1 to storage_slots) @@ -149,9 +132,9 @@ playsound(src, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) /obj/item/storage/pouch/bayonet/attack_hand(mob/user, mods) - if(draw_cooldown < world.time) + if(COOLDOWN_FINISHED(src, draw_cooldown)) ..() - draw_cooldown = world.time + draw_cooldown_interval + COOLDOWN_START(src, draw_cooldown, BAYONET_DRAW_DELAY) playsound(src, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) else to_chat(user, SPAN_WARNING("You need to wait before drawing another knife!")) @@ -243,22 +226,14 @@ desc = "It can contain autoinjectors, ointments, and bandages. This one has some extra stuff." icon_state = "firstaid" storage_slots = 5 - can_hold = list( - /obj/item/stack/medical/ointment, - /obj/item/reagent_container/hypospray/autoinjector/skillless, - /obj/item/storage/pill_bottle/packet/tramadol, - /obj/item/storage/pill_bottle/packet/tricordrazine, - /obj/item/stack/medical/bruise_pack, - /obj/item/stack/medical/splint, - /obj/item/reagent_container/hypospray/autoinjector/emergency, - ) /obj/item/storage/pouch/firstaid/ert/fill_preset_inventory() - new /obj/item/stack/medical/ointment(src) - new /obj/item/reagent_container/hypospray/autoinjector/skillless(src) + new /obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless(src) + new /obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless(src) + new /obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless(src) + new /obj/item/reagent_container/hypospray/autoinjector/emergency/skillless(src) new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/splint(src) - new /obj/item/reagent_container/hypospray/autoinjector/emergency(src) + ///Pistol pouch. /obj/item/storage/pouch/pistol @@ -326,7 +301,7 @@ ///CO pouch. This pouch can hold only 1 of each type of item: 1 sidearm, 1 pair of binoculars, 1 CO tablet /obj/item/storage/pouch/pistol/command name = "command pouch" - desc = "A specialized, sturdy pouch issued to Captains. Can hold their sidearm, the command tablet and a set of binoculars." + desc = "A specialized, sturdy pouch issued to Commanding Officers. Can hold their sidearm, the command tablet and a set of binoculars." storage_slots = 3 icon_state = "command_pouch" can_hold = list( @@ -425,6 +400,7 @@ /obj/item/ammo_magazine/pistol, /obj/item/ammo_magazine/revolver, /obj/item/ammo_magazine/sniper, + /obj/item/ammo_magazine/m60, /obj/item/ammo_magazine/handful, ) @@ -475,13 +451,6 @@ for(var/i = 1 to storage_slots) new /obj/item/ammo_magazine/pistol/vp78(src) -/obj/item/storage/pouch/magazine/shotgun/attackby(obj/item/W, mob/living/user) - if(istype(W, /obj/item/ammo_magazine/shotgun)) - var/obj/item/ammo_magazine/shotgun/M = W - dump_ammo_to(M, user, M.transfer_handful_amount) - else - return ..() - /obj/item/storage/pouch/magazine/pulse_rifle/fill_preset_inventory() for(var/i = 1 to storage_slots) new /obj/item/ammo_magazine/rifle(src) @@ -558,6 +527,10 @@ for(var/i = 1 to storage_slots) new /obj/item/ammo_magazine/smg/m39/heap(src) +/obj/item/storage/pouch/magazine/large/m60/fill_preset_inventory() + for(var/i in 1 to storage_slots) + new /obj/item/ammo_magazine/m60(src) + /obj/item/storage/pouch/shotgun name = "shotgun shell pouch" desc = "It can contain handfuls of shells, or bullets if you choose to for some reason." @@ -615,13 +588,12 @@ name = "explosive pouch" desc = "It can carry grenades, plastic explosives, mine boxes, and other explosives." icon_state = "large_explosive" - storage_slots = 3 + storage_slots = 6 max_w_class = SIZE_MEDIUM can_hold = list( /obj/item/explosive/plastic, /obj/item/explosive/mine, /obj/item/explosive/grenade, - /obj/item/storage/box/explosive_mines, ) /obj/item/storage/pouch/explosive/attackby(obj/item/W, mob/user) @@ -1129,6 +1101,7 @@ /obj/item/stock_parts/micro_laser, /obj/item/stock_parts/scanning_module, /obj/item/stock_parts/capacitor, + /obj/item/smartgun_battery, ) /obj/item/storage/pouch/electronics/full/fill_preset_inventory() @@ -1238,6 +1211,12 @@ new /obj/item/explosive/plastic(src) new /obj/item/explosive/plastic(src) +/obj/item/storage/pouch/tools/uppsynth/fill_preset_inventory() + new /obj/item/tool/crowbar(src) + new /obj/item/tool/wirecutters(src) + new /obj/item/tool/weldingtool(src) + new /obj/item/tool/wrench(src) + /obj/item/storage/pouch/sling name = "sling strap" desc = "Keeps a single item attached to a strap." diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index 5c0f35cf54b7..5a6b7d2b9b05 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -22,9 +22,7 @@ var/atom/movable/screen/storage/storage_start = null //storage UI var/atom/movable/screen/storage/storage_continue = null var/atom/movable/screen/storage/storage_end = null - var/atom/movable/screen/storage/stored_start = null - var/atom/movable/screen/storage/stored_continue = null - var/atom/movable/screen/storage/stored_end = null + var/datum/item_storage_box/stored_ISB = null // This contains what previously was known as stored_start, stored_continue, and stored_end var/atom/movable/screen/close/closer = null var/foldable = null var/use_sound = "rustle" //sound played when used. null for no sound. @@ -33,7 +31,6 @@ var/storage_flags = STORAGE_FLAGS_DEFAULT var/has_gamemode_skin = FALSE ///Whether to use map-variant skins. - /obj/item/storage/MouseDrop(obj/over_object as obj) if(CAN_PICKUP(usr, src)) if(over_object == usr) // this must come before the screen objects only block @@ -204,6 +201,8 @@ var/list/global/item_storage_box_cache = list() var/atom/movable/screen/storage/start = null var/atom/movable/screen/storage/continued = null var/atom/movable/screen/storage/end = null + /// The index that indentifies me inside item_storage_box_cache + var/index /datum/item_storage_box/New() start = new() @@ -213,6 +212,13 @@ var/list/global/item_storage_box_cache = list() end = new() end.icon_state = "stored_end" +/datum/item_storage_box/Destroy(force, ...) + QDEL_NULL(start) + QDEL_NULL(continued) + QDEL_NULL(end) + item_storage_box_cache[index] = null // Or would it be better to -= src? + return ..() + /obj/item/storage/proc/space_orient_objs(list/obj/item/display_contents) var/baseline_max_storage_space = 21 //should be equal to default backpack capacity var/storage_cap_width = 2 //length of sprite for start and end of the box representing total storage space @@ -243,11 +249,12 @@ var/list/global/item_storage_box_cache = list() for(var/obj/item/O in contents) startpoint = endpoint + 1 endpoint += storage_width * O.get_storage_cost()/max_storage_space + var/isb_index = "[startpoint], [endpoint], [stored_cap_width]" click_border_start.Add(startpoint) click_border_end.Add(endpoint) - if(!item_storage_box_cache["[startpoint], [endpoint], [stored_cap_width]"]) + if(!item_storage_box_cache[isb_index]) var/datum/item_storage_box/box = new() var/matrix/M_start = matrix() var/matrix/M_continue = matrix() @@ -259,16 +266,15 @@ var/list/global/item_storage_box_cache = list() box.start.apply_transform(M_start) box.continued.apply_transform(M_continue) box.end.apply_transform(M_end) - item_storage_box_cache["[startpoint], [endpoint], [stored_cap_width]"] = box + box.index = isb_index + item_storage_box_cache[isb_index] = box - var/datum/item_storage_box/ISB = item_storage_box_cache["[startpoint], [endpoint], [stored_cap_width]"] - stored_start = ISB.start - stored_continue = ISB.continued - stored_end = ISB.end + var/datum/item_storage_box/ISB = item_storage_box_cache[isb_index] + stored_ISB = ISB - storage_start.overlays += src.stored_start - storage_start.overlays += src.stored_continue - storage_start.overlays += src.stored_end + storage_start.overlays += ISB.start + storage_start.overlays += ISB.continued + storage_start.overlays += ISB.end O.screen_loc = "4:[round((startpoint+endpoint)/2)+(2+O.hud_offset)],2:16" O.layer = ABOVE_HUD_LAYER @@ -301,7 +307,10 @@ var/list/global/item_storage_box_cache = list() for(var/i in 1 to length(S.click_border_start)) if(S.click_border_start[i] <= click_x && click_x <= S.click_border_end[i]) - I = LAZYACCESS(S.contents, i) + var/list/content_items = list() + for(var/obj/item/content_item in S.contents) + content_items += content_item + I = LAZYACCESS(content_items, i) if(I && I.Adjacent(user)) //Catches pulling items out of nested storage. if(I.clicked(user, mods)) //Examine, alt-click etc. return TRUE @@ -368,12 +377,12 @@ var/list/global/item_storage_box_cache = list() return ///Returns TRUE if there is room for the given item. W_class_override allows checking for just a generic W_class, meant for checking shotgun handfuls without having to spawn and delete one just to check. -/obj/item/storage/proc/has_room(obj/item/W as obj, W_class_override = null) +/obj/item/storage/proc/has_room(obj/item/new_item, W_class_override = null) if(storage_slots != null && contents.len < storage_slots) return TRUE //At least one open slot. //calculate storage space only for containers that don't have slots if (storage_slots == null) - var/sum_storage_cost = W_class_override ? W_class_override : W.get_storage_cost() //Takes the override if there is one, the given item otherwise. + var/sum_storage_cost = W_class_override ? W_class_override : new_item.get_storage_cost() //Takes the override if there is one, the given item otherwise. for(var/obj/item/I in contents) sum_storage_cost += I.get_storage_cost() //Adds up the combined storage costs which will be in the storage item if the item is added to it. @@ -445,23 +454,23 @@ That's done by can_be_inserted(). Its checks are whether the item exists, is an 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. user can be null, it refers to the potential mob doing the insertion.**/ -/obj/item/storage/proc/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) - if(!istype(W)) +/obj/item/storage/proc/handle_item_insertion(obj/item/new_item, prevent_warning = FALSE, mob/user) + if(!istype(new_item)) return FALSE - if(user && W.loc == user) - if(!user.drop_inv_item_to_loc(W, src)) + if(user && new_item.loc == user) + if(!user.drop_inv_item_to_loc(new_item, src)) return FALSE else - W.forceMove(src) + new_item.forceMove(src) - _item_insertion(W, prevent_warning, user) + _item_insertion(new_item, prevent_warning, user) return TRUE /**Inserts the item. Separate proc because handle_item_insertion isn't guaranteed to insert and it therefore isn't safe to override it before calling parent. Updates icon when done. Can be called directly but only if the item was spawned inside src - handle_item_insertion is safer. W is always an item. stop_warning prevents messaging. user may be null.**/ -/obj/item/storage/proc/_item_insertion(obj/item/W, prevent_warning = 0, mob/user) +/obj/item/storage/proc/_item_insertion(obj/item/W, prevent_warning = FALSE, mob/user) W.on_enter_storage(src) if(user) if (user.client && user.s_active != src) @@ -670,6 +679,8 @@ W is always an item. stop_warning prevents messaging. user may be null.**/ item_obj = contents[1] else item_obj = contents[contents.len] + if(!istype(item_obj)) + return remove_from_storage(item_obj, tile) user.visible_message(SPAN_NOTICE("[user] shakes \the [src] and \a [item_obj] falls out."), SPAN_NOTICE("You shake \the [src] and \a [item_obj] falls out.")) @@ -709,25 +720,26 @@ W is always an item. stop_warning prevents messaging. user may be null.**/ to_chat(user, SPAN_WARNING("[ammo_dumping] is empty.")) return TRUE -/obj/item/storage/proc/dump_into(obj/item/storage/M, mob/user) +/obj/item/storage/proc/dump_into(obj/item/storage/origin_storage, mob/user) + if(user.action_busy) return - if(!M.contents.len) - to_chat(user, SPAN_WARNING("[M] is empty.")) + if(!origin_storage.contents.len) + to_chat(user, SPAN_WARNING("[origin_storage] is empty.")) return - if(!has_room(M.contents[1])) //Does it have room for the first item to be inserted? + if(!has_room(origin_storage.contents[1])) //Does it have room for the first item to be inserted? to_chat(user, SPAN_WARNING("[src] is full.")) return - to_chat(user, SPAN_NOTICE("You start refilling [src] with [M].")) + to_chat(user, SPAN_NOTICE("You start refilling [src] with [origin_storage].")) if(!do_after(user, 1.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC)) return - for(var/obj/item/I in M) - if(!has_room(I)) + for(var/obj/item/new_item in origin_storage) + if(!has_room(new_item)) break - M.remove_from_storage(I) - handle_item_insertion(I, TRUE, user) //quiet insertion + origin_storage.remove_from_storage(new_item) + handle_item_insertion(new_item, TRUE, user) //quiet insertion playsound(user.loc, "rustle", 15, TRUE, 6) return TRUE @@ -787,9 +799,9 @@ W is always an item. stop_warning prevents messaging. user may be null.**/ storage_close(watcher) /obj/item/storage/proc/dump_objectives() - for(var/obj/item/I in src) - if(I.is_objective) - I.forceMove(loc) + for(var/obj/item/cur_item in src) + if(cur_item.is_objective) + remove_from_storage(cur_item, loc) /obj/item/storage/Destroy() @@ -801,9 +813,7 @@ W is always an item. stop_warning prevents messaging. user may be null.**/ 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(stored_ISB) QDEL_NULL(closer) return ..() @@ -840,7 +850,7 @@ W is always an item. stop_warning prevents messaging. user may be null.**/ if(isturf(target) && get_dist(src, target) <= 1 && storage_flags & STORAGE_CLICK_EMPTY) empty(user, target) -/obj/item/storage/hear_talk(mob/living/M as mob, msg, verb="says", datum/language/speaking, italics = 0) +/obj/item/storage/hear_talk(mob/living/M, msg, verb, datum/language/speaking, italics) // Whatever is stored in /storage/ substypes should ALWAYS be an item for (var/obj/item/I as anything in hearing_items) I.hear_talk(M, msg, verb, speaking, italics) diff --git a/code/game/objects/items/storage/surgical_tray.dm b/code/game/objects/items/storage/surgical_tray.dm index d86918c697b2..16c0d1352961 100644 --- a/code/game/objects/items/storage/surgical_tray.dm +++ b/code/game/objects/items/storage/surgical_tray.dm @@ -4,7 +4,7 @@ icon_state = "surgical_tray" flags_atom = FPRINT|CONDUCT w_class = SIZE_LARGE //Should not fit in backpacks - storage_slots = 13 + storage_slots = 14 max_storage_space = 24 use_sound = "toolbox" matter = list("plastic" = 3000) @@ -31,6 +31,7 @@ new /obj/item/tool/surgery/FixOVein(src) new /obj/item/stack/nanopaste(src) new /obj/item/tool/surgery/surgical_line(src) + new /obj/item/tool/surgery/synthgraft(src) /obj/item/storage/surgical_tray/update_icon() if(!contents.len) diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm index 92a0d51e9276..3a5afef6cf1e 100644 --- a/code/game/objects/items/tanks/jetpack.dm +++ b/code/game/objects/items/tanks/jetpack.dm @@ -18,6 +18,10 @@ src.ion_trail = new /datum/effect_system/ion_trail_follow() src.ion_trail.set_up(src) +/obj/item/tank/jetpack/Destroy() + QDEL_NULL(ion_trail) + return ..() + /obj/item/tank/jetpack/verb/toggle_rockets() set name = "Toggle Jetpack Stabilization" @@ -79,9 +83,3 @@ distribute_pressure = 0 icon_state = "jetpack-black" item_state = "jetpack-black" - -/obj/item/tank/jetpack/carbondioxide/New() - ..() - src.ion_trail = new /datum/effect_system/ion_trail_follow() - src.ion_trail.set_up(src) - diff --git a/code/game/objects/items/tools/experimental_tools.dm b/code/game/objects/items/tools/experimental_tools.dm index 4e89fdb73730..d27272881e1e 100644 --- a/code/game/objects/items/tools/experimental_tools.dm +++ b/code/game/objects/items/tools/experimental_tools.dm @@ -76,7 +76,7 @@ SPAN_NOTICE("You start fitting \the [src] onto [M]'s chest."), SPAN_WARNING("[user] starts fitting \the [src] onto your chest!"), SPAN_NOTICE("[user] starts fitting \the [src] onto [M]'s chest.")) - if(!(do_after(user, HUMAN_STRIP_DELAY * user.get_skill_duration_multiplier(), INTERRUPT_ALL, BUSY_ICON_GENERIC, M, INTERRUPT_MOVED, BUSY_ICON_MEDICAL))) + if(!(do_after(user, HUMAN_STRIP_DELAY * user.get_skill_duration_multiplier(SKILL_MEDICAL), INTERRUPT_ALL, BUSY_ICON_GENERIC, M, INTERRUPT_MOVED, BUSY_ICON_MEDICAL))) return if(!mob_can_equip(M, WEAR_JACKET)) return diff --git a/code/game/objects/items/tools/flame_tools.dm b/code/game/objects/items/tools/flame_tools.dm index db35d3300ae7..6ebd8ee5982e 100644 --- a/code/game/objects/items/tools/flame_tools.dm +++ b/code/game/objects/items/tools/flame_tools.dm @@ -170,13 +170,20 @@ CIGARETTE PACKETS ARE IN FANCY.DM damtype = "brute" icon_state = "[initial(icon_state)]_burnt" item_state = "cigoff" - if(user && loc != user) - user.SetLuminosity(0, FALSE, src) SetLuminosity(0) name = burnt_name desc = "A match. This one has seen better days." STOP_PROCESSING(SSobj, src) + if(user) + user.SetLuminosity(0, FALSE, src) + return + + if(ismob(loc)) + user = loc + user.SetLuminosity(0, FALSE, src) + return + /obj/item/tool/match/paper name = "paper match" desc = "A simple match stick, used for lighting fine smokables." diff --git a/code/game/objects/items/tools/kitchen_tools.dm b/code/game/objects/items/tools/kitchen_tools.dm index 98974f25be29..bb763ada9911 100644 --- a/code/game/objects/items/tools/kitchen_tools.dm +++ b/code/game/objects/items/tools/kitchen_tools.dm @@ -45,6 +45,10 @@ return ..() if (reagents.total_volume > 0) + var/fullness = M.nutrition + (M.reagents.get_reagent_amount("nutriment") * 25) + if(fullness > NUTRITION_HIGH) + to_chat(user, SPAN_WARNING("[user == M ? "You" : "They"] don't feel like eating more right now.")) + return ..() reagents.set_source_mob(user) reagents.trans_to_ingest(M, reagents.total_volume) if(M == user) diff --git a/code/game/objects/items/tools/maintenance_tools.dm b/code/game/objects/items/tools/maintenance_tools.dm index bb68958eb105..b8affb0de616 100644 --- a/code/game/objects/items/tools/maintenance_tools.dm +++ b/code/game/objects/items/tools/maintenance_tools.dm @@ -219,49 +219,51 @@ toggle(TRUE) -/obj/item/tool/weldingtool/attack(mob/M, mob/user) +/obj/item/tool/weldingtool/attack(mob/target, mob/user) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/limb/S = H.get_limb(user.zone_selected) + if(ishuman(target)) + var/mob/living/carbon/human/human = target + var/obj/limb/limb = human.get_limb(user.zone_selected) - if (!S) return - if(!(S.status & (LIMB_ROBOT|LIMB_SYNTHSKIN)) || user.a_intent != INTENT_HELP) + if (!limb) return + if(!(limb.status & (LIMB_ROBOT|LIMB_SYNTHSKIN)) || user.a_intent != INTENT_HELP) return ..() if(user.action_busy) return var/self_fixing = FALSE - if(H.species.flags & IS_SYNTHETIC && M == user) + if(human.species.flags & IS_SYNTHETIC && target == user) self_fixing = TRUE - if(S.brute_dam && welding) + if(limb.brute_dam && welding) remove_fuel(1,user) if(self_fixing) - user.visible_message(SPAN_WARNING("\The [user] begins fixing some dents on their [S.display_name]."), \ - SPAN_WARNING("You begin to carefully patch some dents on your [S.display_name] so as not to void your warranty.")) + user.visible_message(SPAN_WARNING("\The [user] begins fixing some dents on their [limb.display_name]."), \ + SPAN_WARNING("You begin to carefully patch some dents on your [limb.display_name] so as not to void your warranty.")) if(!do_after(user, 30, INTERRUPT_ALL, BUSY_ICON_FRIENDLY)) return - S.heal_damage(15, 0, TRUE) - H.pain.recalculate_pain() - H.UpdateDamageIcon() - user.visible_message(SPAN_WARNING("\The [user] patches some dents on \the [H]'s [S.display_name] with \the [src]."), \ - SPAN_WARNING("You patch some dents on \the [H]'s [S.display_name] with \the [src].")) + limb.heal_damage(15, 0, TRUE) + human.pain.recalculate_pain() + human.UpdateDamageIcon() + user.visible_message(SPAN_WARNING("\The [user] patches some dents on \the [human]'s [limb.display_name] with \the [src]."), \ + SPAN_WARNING("You patch some dents on \the [human]'s [limb.display_name] with \the [src].")) return else to_chat(user, SPAN_WARNING("Nothing to fix!")) else + if(ismob(target)) + remove_fuel(1) return ..() -/obj/item/tool/weldingtool/afterattack(obj/O as obj, mob/user as mob, proximity) +/obj/item/tool/weldingtool/afterattack(obj/target, mob/user, proximity) if(!proximity) return - if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1) + if (istype(target, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,target) <= 1) if(!welding) - O.reagents.trans_to(src, max_fuel) + target.reagents.trans_to(src, max_fuel) weld_tick = 0 user.visible_message(SPAN_NOTICE("[user] refills [src]."), \ SPAN_NOTICE("You refill [src].")) @@ -270,14 +272,12 @@ message_admins("[key_name_admin(user)] triggered a fueltank explosion with a blowtorch.") log_game("[key_name(user)] triggered a fueltank explosion with a blowtorch.") to_chat(user, SPAN_DANGER("You begin welding on the fueltank, and in a last moment of lucidity realize this might not have been the smartest thing you've ever done.")) - var/obj/structure/reagent_dispensers/fueltank/tank = O + var/obj/structure/reagent_dispensers/fueltank/tank = target tank.explode() return if (welding) - remove_fuel(1) - - if(isliving(O)) - var/mob/living/L = O + if(isliving(target)) + var/mob/living/L = target L.IgniteMob() @@ -501,7 +501,23 @@ flags_equip_slot = SLOT_SUIT_STORE pry_capable = IS_PRY_CAPABLE_FORCE //but not really ///Whether the Maintenance Jack is on crowbar or wrench mode - var/crowbar_mode = TRUE + var/crowbar_mode = TRUE //False for wrench mode + ///Whether you need the "super strength" trait to pry open doors + var/requires_superstrength_pry = TRUE + ///Whether you get the speed penalty from not having engi 3 + var/requires_skills_unbolt = TRUE + ///How long it takes (in seconds) to pry open an airlock + var/prying_time = 3 SECONDS + ///How long it takes (in seconds) to pry open a resin door + var/resin_prying_time = 5 SECONDS + ///How long it takes (in seconds) to unbolt an airlock + var/unbolt_time = 5 SECONDS + ///How long extra will it take (in seconds) people who do not have engi 3 (if requires_skills_unbolt is true) + var/unskilled_unbolt_time = 15 SECONDS + +/obj/item/maintenance_jack/Initialize() + . = ..() + RegisterSignal(src, COMSIG_ITEM_ATTACK_AIRLOCK, PROC_REF(handle_airlock_attack)) /obj/item/maintenance_jack/get_examine_text(mob/user) . = ..() @@ -523,7 +539,6 @@ animate(transform = matrix(180, MATRIX_ROTATE), time = 2, easing = EASE_OUT) REMOVE_TRAIT(src, TRAIT_TOOL_CROWBAR, TRAIT_SOURCE_INHERENT) ADD_TRAIT(src, TRAIT_TOOL_WRENCH, TRAIT_SOURCE_INHERENT) - pry_capable = null return //Switch to crowbar mode | Pry open doors if super strong trait @@ -535,72 +550,113 @@ animate(transform = matrix(360, MATRIX_ROTATE), time = 2, easing = EASE_OUT) REMOVE_TRAIT(src, TRAIT_TOOL_WRENCH, TRAIT_SOURCE_INHERENT) ADD_TRAIT(src, TRAIT_TOOL_CROWBAR, TRAIT_SOURCE_INHERENT) - pry_capable = IS_PRY_CAPABLE_FORCE - -/obj/item/maintenance_jack/afterattack(obj/door, mob/living/user, proximity) - if(!crowbar_mode) //Otherwise it lets you pry open right after unbolting - return - if(!proximity) - return - if(istype(door, /obj/structure/machinery/door/airlock)) - var/obj/structure/machinery/door/airlock/airlock = door - if(airlock.locked) - to_chat(user, SPAN_DANGER("You can't pry open [airlock] while it is bolted shut.")) +/obj/item/maintenance_jack/proc/handle_airlock_attack(source, obj/structure/machinery/door/airlock/attacked_door, mob/user) + . = COMPONENT_CANCEL_AIRLOCK_ATTACK + if(crowbar_mode) + if(attacked_door.locked) //Bolted + to_chat(user, SPAN_DANGER("You can't pry open [attacked_door] while it is bolted shut.")) return - if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) //basically IS_PRY_CAPABLE_CROWBAR - if(!airlock.arePowerSystemsOn()) - if(!airlock.operating) - if(airlock.density) - airlock.open(TRUE) - else - airlock.close(TRUE) - else - to_chat(user, SPAN_WARNING("The airlock's motors resist your efforts to force it.")) + + if(requires_superstrength_pry) + if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) //basically IS_PRY_CAPABLE_CROWBAR + return + if(!attacked_door.density) //If its open return - if(!airlock.density) + if(attacked_door.heavy) //Unopenable + to_chat(usr, SPAN_DANGER("You cannot force [attacked_door] open.")) return - if(airlock.heavy) - to_chat(usr, SPAN_DANGER("You cannot force [airlock] open.")) - return FALSE - if(user.action_busy || user.a_intent == INTENT_HARM) + if(user.action_busy) return - user.visible_message(SPAN_DANGER("[user] jams [src] into [airlock] and starts to pry it open."), - SPAN_DANGER("You jam [src] into [airlock] and start to pry it open.")) + user.visible_message(SPAN_DANGER("[user] jams [src] into [attacked_door] and starts to pry it open."), + SPAN_DANGER("You jam [src] into [attacked_door] and start to pry it open.")) playsound(src, "pry", 15, TRUE) - if(!do_after(user, 3 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + if(!do_after(user, prying_time, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) return - if(!airlock.density) + if(!attacked_door.density) return - if(airlock.locked) - user.visible_message(SPAN_DANGER("[user] fails to force [airlock] open with [src]."), - SPAN_DANGER("You fail to force [airlock] open with [src].")) + if(attacked_door.locked) + user.visible_message(SPAN_DANGER("[user] fails to force [attacked_door] open with [src]."), + SPAN_DANGER("You fail to force [attacked_door] open with [src].")) return - user.visible_message(SPAN_DANGER("[user] forces [airlock] open with [src]."), - SPAN_DANGER("You force [airlock] open with [src].")) - airlock.open(TRUE) + user.visible_message(SPAN_DANGER("[user] forces [attacked_door] open with [src]."), + SPAN_DANGER("You force [attacked_door] open with [src].")) + attacked_door.open(TRUE) + return - else if(istype(door, /obj/structure/mineral_door/resin)) - var/obj/structure/mineral_door/resin/resin_door = door - if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) //basically IS_PRY_CAPABLE_CROWBAR - return - if(resin_door.isSwitchingStates) - return - if(!resin_door.density || user.action_busy || user.a_intent == INTENT_HARM) - return + //Wrench Mode + if(!attacked_door.locked) + to_chat(user, SPAN_NOTICE("You cannot disable bolts on a door that is already unbolted.")) + return + + if(requires_skills_unbolt) + if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_MASTER)) //Engi 3 is much faster + user.visible_message(SPAN_DANGER("[user] begins to search for [attacked_door]'s bolts!"),\ + SPAN_NOTICE("You search for [attacked_door]'s bolts.")) + if(!do_after(user, unskilled_unbolt_time, INTERRUPT_ALL, BUSY_ICON_HOSTILE, src, INTERRUPT_ALL)) //Otherwise it takes an extra 15 seconds + to_chat(user, SPAN_WARNING("You fail to find the bolts on [attacked_door].")) + return + + user.visible_message(SPAN_DANGER("[user] begins to disable [attacked_door]'s bolts!"),\ + SPAN_NOTICE("You start to disable [attacked_door]'s bolts.")) + playsound(attacked_door, "pry", 25, TRUE) + + if(!do_after(user, unbolt_time, INTERRUPT_ALL, BUSY_ICON_HOSTILE, src, INTERRUPT_ALL)) + to_chat(user, SPAN_WARNING("You decide not to disable the bolts on [attacked_door].")) + return - user.visible_message(SPAN_DANGER("[user] jams [src] into [resin_door] and starts to pry it open."), - SPAN_DANGER("You jam [src] into [resin_door] and start to pry it open.")) - playsound(user, 'sound/weapons/wristblades_hit.ogg', 15, TRUE) + user.visible_message(SPAN_DANGER("[user] disables the bolts on [attacked_door]."),\ + SPAN_NOTICE("You unbolt [attacked_door].")) + attacked_door.unlock(TRUE) + return + +/obj/item/maintenance_jack/afterattack(atom/attacked_obj, mob/living/user, proximity) + if(!proximity) + return + + if(istype(attacked_obj, /obj/structure/mineral_door/resin)) + var/obj/structure/mineral_door/resin/resin_door = attacked_obj + + if(resin_door) + if(crowbar_mode) + if(requires_superstrength_pry) + if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) //basically IS_PRY_CAPABLE_CROWBAR + return ..() + if(resin_door.isSwitchingStates) + return + if(!resin_door.density || user.action_busy || user.a_intent == INTENT_HARM) + return + + user.visible_message(SPAN_DANGER("[user] jams [src] into [resin_door] and starts to pry it open."), + SPAN_DANGER("You jam [src] into [resin_door] and start to pry it open.")) + playsound(user, 'sound/weapons/wristblades_hit.ogg', 15, TRUE) - if(do_after(user, 5 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE) && resin_door.density) - user.visible_message(SPAN_DANGER("[user] forces [resin_door] open with [src]."), - SPAN_DANGER("You force [resin_door] open with [src].")) - resin_door.Open() + if(!do_after(user, resin_prying_time, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + to_chat(user, SPAN_NOTICE("You stop prying [resin_door] open.")) + return + + user.visible_message(SPAN_DANGER("[user] forces [resin_door] open with [src]."), + SPAN_DANGER("You force [resin_door] open with [src].")) + resin_door.Open() + return + else if(istype(attacked_obj, /turf/open/floor)) + var/turf/open/floor/flooring = attacked_obj + + if(crowbar_mode && user.a_intent == INTENT_HELP) //Only pry flooring on help intent + if(flooring.hull_floor) //no interaction for hulls + return + if(flooring.weeds) + return attackby(src, user) + + to_chat(user, SPAN_WARNING("You forcefully pry off [flooring], destroying it in the process.")) + playsound(src, 'sound/items/Crowbar.ogg', 25, 1) + flooring.make_plating() + return + return ..() /* Welding backpack */ @@ -651,17 +707,22 @@ Welding backpack to_chat(user, SPAN_NOTICE("You cannot figure out how to use \the [W] with [src].")) return -/obj/item/tool/weldpack/afterattack(obj/O as obj, mob/user as mob, 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(src, max_fuel) - to_chat(user, SPAN_NOTICE(" You crack the cap off the top of \the [src] and fill it back up again from the tank.")) - playsound(src.loc, 'sound/effects/refill.ogg', 25, 1, 3) - return - else if (istype(O, /obj/structure/reagent_dispensers/fueltank) && src.reagents.total_volume == max_fuel) - to_chat(user, SPAN_NOTICE(" \The [src] is already full!")) +/obj/item/tool/weldpack/afterattack(obj/target as obj, mob/user as mob, proximity) + if(!proximity) // this replaces and improves the get_dist(src,target) <= 1 checks used previously return + if(istype(target, /obj/structure/reagent_dispensers)) + if(!(istypestrict(target, /obj/structure/reagent_dispensers/fueltank))) + to_chat(user, SPAN_NOTICE("This must be filled with a fuel tank.")) + return + if(reagents.total_volume < max_fuel) + target.reagents.trans_to(src, max_fuel) + to_chat(user, SPAN_NOTICE("You crack the cap off the top of \the [src] and fill it back up again from the tank.")) + playsound(loc, 'sound/effects/refill.ogg', 25, 1, 3) + return + if (reagents.total_volume >= max_fuel) + to_chat(user, SPAN_NOTICE("[src] is already full!")) + return + ..() /obj/item/tool/weldpack/get_examine_text(mob/user) . = ..() diff --git a/code/game/objects/items/tools/misc_tools.dm b/code/game/objects/items/tools/misc_tools.dm index d2265759bc15..505006285881 100644 --- a/code/game/objects/items/tools/misc_tools.dm +++ b/code/game/objects/items/tools/misc_tools.dm @@ -200,7 +200,7 @@ if(input == oldname || !input) to_chat(user, SPAN_NOTICE("You changed [target] to... well... [target].")) else - msg_admin_niche("[key_name(usr)] changed \the [src]'s name to [input] (JMP)") + msg_admin_niche("[key_name(usr)] changed \the [src]'s name to [input] [ADMIN_JMP(src)]") target.AddComponent(/datum/component/rename, input, target.desc) var/datum/component/label/label = target.GetComponent(/datum/component/label) if(label) @@ -218,7 +218,7 @@ if(input == olddesc || !input) to_chat(user, SPAN_NOTICE("You decide against changing [target]'s description.")) else - msg_admin_niche("[key_name(usr)] changed \the [src]'s description to [input] (JMP)") + msg_admin_niche("[key_name(usr)] changed \the [src]'s description to [input] [ADMIN_JMP(src)]") target.AddComponent(/datum/component/rename, target.name, input) to_chat(user, SPAN_NOTICE("You have successfully changed [target]'s description.")) obj_target.renamedByPlayer = TRUE @@ -275,6 +275,41 @@ desc = "It's an invisible pen marker." pen_colour = "white" +/obj/item/tool/pen/fountain + desc = "A lavish testament to the ingenuity of ARMAT's craftsmanship, this fountain pen is a paragon of design and functionality. Detailed with golden accents and intricate mechanics, the pen allows for a swift change between a myriad of ink colors with a simple twist. A product of precision engineering, each mechanism inside the pen is designed to provide a seamless, effortless transition from one color to the next, creating an instrument of luxurious versatility." + desc_lore = "More than just a tool for writing, ARMAT's fountain pen is a symbol of distinction and authority within the ranks of the United States Colonial Marine Corps (USCM). It is a legacy item, exclusively handed out to the top-tier command personnel, each pen a tribute to the recipient's leadership and dedication.\n \nARMAT, renowned for their weapons technology, took a different approach in crafting this piece. The fountain pen, though seemingly a departure from their usual field, is deeply ingrained with the company's engineering philosophy, embodying precision, functionality, and robustness.\n \nThe golden accents are not mere embellishments; they're an identifier, setting apart these pens and their owners from the rest. The gold is meticulously alloyed with a durable metallic substance, granting it resilience to daily wear and tear. Such resilience is symbolic of the tenacity and perseverance required of USCM command personnel.\n \nEach pen is equipped with an intricate color changing mechanism, allowing the user to switch between various ink colors. This feature, inspired by the advanced targeting systems of ARMAT's weaponry, uses miniaturized actuators and precision-ground components to smoothly transition the ink flow. A simple twist of the pen's body activates the change, rotating the internal ink cartridges into place with mechanical grace, ready for the user's command.\n \nThe ink colors are not chosen arbitrarily. Each represents a different echelon within the USCM, allowing the pen's owner to write in the hue that corresponds with their rank or the rank of the recipient of their written orders. This acts as a silent testament to the authority of their words, as if each stroke of the pen echoes through the halls of USCM authority.\n \nDespite its ornate appearance, the pen is as robust as any ARMAT weapon, reflecting the company's commitment to reliability and durability. The metal components are corrosion-resistant, ensuring the pen's longevity, even under the challenging conditions often faced by USCM high command.\n \nThe fusion of luxury and utility, the blend of gold and metal, is an embodiment of the hard-won elegance of command, of the fusion between power and grace. It's more than a writing instrument - it's an emblem of leadership, an accolade to the dedication and strength of those who bear it. ARMAT's fountain pen stands as a monument to the precision, integrity, and courage embodied by the USCM's highest-ranking officers." + name = "fountain pen" + icon_state = "fountain_pen" + item_state = "fountain_pen" + matter = list("metal" = 20, "gold" = 10) + var/static/list/colour_list = list("red", "blue", "green", "yellow", "purple", "pink", "brown", "black", "orange") // Can add more colors as required + var/current_colour_index = 1 + var/owner = "hard to read text" + +/obj/item/tool/pen/fountain/Initialize(mapload, mob/living/carbon/human/user) + . = ..() + var/turf/current_turf = get_turf(src) + var/mob/living/carbon/human/new_owner = locate() in current_turf + if(new_owner) + owner = new_owner.real_name + var/obj/structure/machinery/cryopod/new_owners_pod = locate() in current_turf + if(new_owners_pod) + owner = new_owners_pod.occupant?.real_name + +/obj/item/tool/pen/fountain/get_examine_text(mob/user) + . = ..() + . += "There's a laser engraving of [owner] on it." + +/obj/item/tool/pen/fountain/attack_self(mob/living/carbon/human/user) + if(on) + current_colour_index = (current_colour_index % length(colour_list)) + 1 + pen_colour = colour_list[current_colour_index] + balloon_alert(user,"you twist the pen and change the ink color to [pen_colour].") + if(clicky) + playsound(user.loc, 'sound/items/pen_click_on.ogg', 100, 1, 5) + update_pen_state() + else + ..() /obj/item/tool/pen/attack(mob/M as mob, mob/user as mob) if(!ismob(M)) diff --git a/code/game/objects/items/tools/shovel_tools.dm b/code/game/objects/items/tools/shovel_tools.dm index 29bc19f65bbf..008b37705fe3 100644 --- a/code/game/objects/items/tools/shovel_tools.dm +++ b/code/game/objects/items/tools/shovel_tools.dm @@ -233,7 +233,7 @@ /obj/item/tool/shovel/etool/attack_self(mob/user as mob) folded = !folded if(folded) - w_class = SIZE_MEDIUM + w_class = SIZE_SMALL force = 2 else w_class = SIZE_LARGE @@ -242,7 +242,7 @@ /obj/item/tool/shovel/etool/folded folded = TRUE - w_class = SIZE_MEDIUM + w_class = SIZE_SMALL force = 2 icon_state = "etool_c" item_state = "etool_c" diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm index 1d0165f12738..b2a66becd869 100644 --- a/code/game/objects/items/toys/toys.dm +++ b/code/game/objects/items/toys/toys.dm @@ -397,7 +397,7 @@ /obj/item/toy/dice name = "d6" - desc = "A dice with six sides." + desc = "A die with six sides." icon = 'icons/obj/items/dice.dmi' icon_state = "d66" w_class = SIZE_TINY @@ -406,11 +406,11 @@ /obj/item/toy/dice/Initialize() . = ..() - icon_state = "[name][rand(sides)]" + icon_state = "[name][rand(1, sides)]" /obj/item/toy/dice/d20 name = "d20" - desc = "A dice with twenty sides." + desc = "A die with twenty sides." icon_state = "d2020" sides = 20 diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index 36bb6634f642..d9d40e003c7a 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -68,6 +68,10 @@ name = "Kepler wrapper" icon_state = "kepler" +/obj/item/trash/kepler/flamehot + name = "Kepler Flamehot wrapper" + icon_state = "flamehotkepler" + /obj/item/trash/liquidfood name = "\improper \"LiquidFood\" ration" icon_state = "liquidfood" diff --git a/code/game/objects/items/weapons/misc.dm b/code/game/objects/items/weapons/misc.dm index 6ffb179c4ed0..26a0a59b8090 100644 --- a/code/game/objects/items/weapons/misc.dm +++ b/code/game/objects/items/weapons/misc.dm @@ -56,3 +56,20 @@ new/obj/item/shard(src.loc) playsound(src, "shatter", 25, 1) qdel(src) + +/obj/item/weapon/dart + name = "red throwing dart" + desc = "A dart. For throwing. This one's red." + icon = 'icons/obj/items/items.dmi' + icon_state = "red_dart" + force = MELEE_FORCE_WEAK + throwforce = MELEE_FORCE_WEAK + throw_speed = SPEED_VERY_FAST + throw_range = 5 + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("stabbed", "poked", "attacked") + +/obj/item/weapon/dart/green + name = "green throwing dart" + desc = "A dart. For throwing. This one's green." + icon_state = "green_dart" diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 20e5ac4f9bdc..6cb9f58aae37 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -11,7 +11,7 @@ w_class = SIZE_MEDIUM attack_verb = list("beaten") - req_one_access = list(ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_SENIOR, ACCESS_WY_CORPORATE, ACCESS_WY_PMC_GREEN, ACCESS_CIVILIAN_BRIG) + req_one_access = list(ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_SENIOR, ACCESS_WY_GENERAL, ACCESS_WY_SECURITY, ACCESS_CIVILIAN_BRIG) var/stunforce = 50 var/status = 0 //whether the thing is on or not var/obj/item/cell/bcell = null diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index ec7ee0b173da..cdab7db87ed7 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -45,7 +45,7 @@ w_class = SIZE_SMALL force = MELEE_FORCE_WEAK var/on = 0 - var/stunforce = 60 + var/stun_force = 10 /obj/item/weapon/telebaton/attack(mob/living/carbon/human/target, mob/living/user) if(!istype(target) || !on) @@ -67,6 +67,7 @@ item_state = "telebaton_1" w_class = SIZE_MEDIUM force = MELEE_FORCE_VERY_STRONG + stun_force = 40 attack_verb = list("smacked", "struck", "slapped", "beat") else user.visible_message(SPAN_NOTICE("Using a smooth, practiced movement, [user] collapses \his [src]."),\ @@ -75,7 +76,8 @@ icon_state = "telebaton_0" item_state = "telebaton_0" w_class = SIZE_SMALL - force = MELEE_FORCE_WEAK//not so robust now + force = MELEE_FORCE_WEAK + stun_force = initial(stun_force) attack_verb = list("hit", "punched") if(istype(user,/mob/living/carbon/human)) @@ -100,8 +102,17 @@ user.flick_attack_overlay(target, "punch") log_interact(user, target, "[key_name(user)] stunned [key_name(target)] with \the [src]") // Hit 'em + var/final_stun_force = stun_force + var/datum/skills/user_skills = user.skills + if(user_skills) + switch(user_skills.get_skill_level(SKILL_POLICE)) + if(SKILL_POLICE_FLASH) + final_stun_force *= 1.5 + if(SKILL_POLICE_SKILLED) + final_stun_force *= 3 + var/target_zone = check_zone(user.zone_selected) - target.apply_stamina_damage(stunforce, target_zone, ARMOR_MELEE) + target.apply_stamina_damage(final_stun_force, target_zone, ARMOR_MELEE) if(target.stamina.current_stamina <= 0) user.visible_message(SPAN_DANGER("[user] knocks down [target] with \the [src]!"),\ SPAN_WARNING("You knock down [target] with \the [src]!")) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index c9bfb9b9f757..be7571fa84a1 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -323,13 +323,25 @@ item_state = "syn_breacher" force_wielded = MELEE_FORCE_VERY_STRONG really_heavy = TRUE + var/move_delay_addition = 1.5 /obj/item/weapon/twohanded/breacher/synth/pickup(mob/user) if(!(HAS_TRAIT(user, TRAIT_SUPER_STRONG))) - to_chat(user, SPAN_WARNING("You barely manage to lift \the [src] above your knees. This thing will probably be useless to you.")) + to_chat(user, SPAN_HIGHDANGER("You barely manage to lift [src] above your knees. This thing will probably be useless to you.")) + user.apply_effect(3, EYE_BLUR) + RegisterSignal(user, COMSIG_HUMAN_POST_MOVE_DELAY, PROC_REF(handle_movedelay)) + return ..() +/obj/item/weapon/twohanded/breacher/synth/proc/handle_movedelay(mob/living/M, list/movedata) + SIGNAL_HANDLER + movedata["move_delay"] += move_delay_addition + +/obj/item/weapon/twohanded/breacher/synth/dropped(mob/user, silent) + . = ..() + UnregisterSignal(user, COMSIG_HUMAN_POST_MOVE_DELAY) + /obj/item/weapon/twohanded/breacher/synth/attack(target as mob, mob/living/user as mob) if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) to_chat(user, SPAN_WARNING("\The [src] is too heavy for you to use as a weapon!")) diff --git a/code/game/objects/items/weapons/weapon.dm b/code/game/objects/items/weapons/weapon.dm index 07de71d250f7..3d53dfb86b73 100644 --- a/code/game/objects/items/weapons/weapon.dm +++ b/code/game/objects/items/weapons/weapon.dm @@ -11,22 +11,23 @@ switch(force) if((MELEE_FORCE_WEAK + 1) to MELEE_FORCE_NORMAL) strong_text = "a normal" - if(MELEE_FORCE_NORMAL to MELEE_FORCE_STRONG) + if((MELEE_FORCE_NORMAL + 1) to MELEE_FORCE_STRONG) strong_text = "a strong" - if(MELEE_FORCE_STRONG to MELEE_FORCE_VERY_STRONG) + if((MELEE_FORCE_STRONG + 1) to MELEE_FORCE_VERY_STRONG) strong_text = "a very strong" - if(MELEE_FORCE_VERY_STRONG to INFINITY) + if((MELEE_FORCE_VERY_STRONG + 1) to INFINITY) strong_text = "an inhumanely strong" - . += SPAN_INFO("[src] would be [strong_text] weapon if you were hit someone with it.") + . += SPAN_INFO("[src] would be [strong_text] weapon if you were to hit someone with it.") - if(force != throwforce && throwforce >= MELEE_FORCE_TIER_1) + if(throwforce >= MELEE_FORCE_TIER_1) + strong_text = "a weak" switch(throwforce) if((MELEE_FORCE_WEAK + 1) to MELEE_FORCE_NORMAL) strong_text = "a normal" - if(MELEE_FORCE_NORMAL to MELEE_FORCE_STRONG) + if((MELEE_FORCE_NORMAL + 1) to MELEE_FORCE_STRONG) strong_text = "a strong" - if(MELEE_FORCE_STRONG to MELEE_FORCE_VERY_STRONG) + if((MELEE_FORCE_STRONG + 1) to MELEE_FORCE_VERY_STRONG) strong_text = "a very strong" - if(MELEE_FORCE_VERY_STRONG to INFINITY) + if((MELEE_FORCE_VERY_STRONG + 1) to INFINITY) strong_text = "an inhumanely strong" - . += SPAN_INFO("[src] would be [strong_text] weapon if you were throw it at someone.") + . += SPAN_INFO("[src] would be [strong_text] weapon if you were to throw it at someone.") diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 58342e5c2528..24f019b9f89f 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -29,6 +29,8 @@ var/list/req_one_access = null var/req_access_txt = null var/req_one_access_txt = null + ///Whether or not this instance is using accesses different from initial code. Used for easy locating in map files. + var/access_modified = FALSE var/flags_obj = NO_FLAGS /// set when a player uses a pen on a renamable object @@ -223,6 +225,7 @@ /obj/proc/afterbuckle(mob/M as mob) // Called after somebody buckled / unbuckled handle_rotation() + SEND_SIGNAL(src, COSMIG_OBJ_AFTER_BUCKLE, buckled_mob) return buckled_mob /obj/proc/unbuckle() @@ -232,6 +235,7 @@ buckled_mob.update_canmove() var/M = buckled_mob + REMOVE_TRAITS_IN(buckled_mob, TRAIT_SOURCE_BUCKLE) buckled_mob = null afterbuckle(M) @@ -301,11 +305,9 @@ src.add_fingerprint(user) afterbuckle(target) if(buckle_lying) // Make sure buckling to beds/nests etc only turns, and doesn't give a random offset - var/matrix/M = matrix() - var/matrix/L = matrix() //Counterrotation for langchat text. - M.Turn(90) - L.Turn(270) - target.apply_transform(M) + var/matrix/new_matrix = matrix() + new_matrix.Turn(90) + target.apply_transform(new_matrix) return TRUE /obj/proc/send_buckling_message(mob/M, mob/user) @@ -450,3 +452,7 @@ /obj/proc/set_origin_name_prefix(name_prefix) return + +/// override for subtypes that require extra behaviour when spawned from a vendor +/obj/proc/post_vendor_spawn_hook(mob/living/carbon/human/user) + return diff --git a/code/game/objects/prop.dm b/code/game/objects/prop.dm index 8e0791c6c027..e59c24b30d5f 100644 --- a/code/game/objects/prop.dm +++ b/code/game/objects/prop.dm @@ -88,3 +88,141 @@ desc = "It has some sort of a tube at the end of its tail. What the hell is this thing?" icon = 'icons/mob/xenos/effects.dmi' icon_state = "facehugger_impregnated" + +//-----USS Almayer Props -----// +//Put any props that don't function properly, they could function in the future but for now are for looks. This system could be expanded for other maps too. ~Art + +/obj/item/prop/almayer + name = "GENERIC USS ALMAYER PROP" + desc = "THIS SHOULDN'T BE VISIBLE, IF YOU SEE THIS THERE IS A PROBLEM IN THE PROP.DM FILE MAKE A BUG REPORT " + icon = 'icons/obj/structures/props/almayer_props.dmi' + icon_state = "hangarbox" + +/obj/item/prop/almayer/box + name = "metal crate" + desc = "A metal crate used often for storing small electronics that go into dropships" + icon_state = "hangarbox" + w_class = SIZE_LARGE + +/obj/item/prop/almayer/flight_recorder + name = "\improper FR-112 flight recorder" + desc = "A small red box that contains flight data from a dropship while it's on mission. Usually referred to as the black box, although this one comes in bloody red." + icon_state = "flight_recorder" + w_class = SIZE_LARGE + +/obj/item/prop/almayer/flight_recorder/colony + name = "\improper CIR-60 colony information recorder" + desc = "A small red box that records colony announcements, colonist flatlines and other key readouts. Usually refered to the black box, although this one comes in bloody red." + icon_state = "flight_recorder" + w_class = SIZE_LARGE + +/obj/item/prop/almayer/flare_launcher + name = "\improper MJU-77/C case" + desc = "A flare launcher that usually gets mounted onto dropships to help survivability against infrared tracking missiles." + icon_state = "flare_launcher" + w_class = SIZE_SMALL + +/obj/item/prop/almayer/chaff_launcher + name = "\improper RR-247 Chaff case" + desc = "A chaff launcher that usually gets mounted onto dropships to help survivability against radar tracking missiles." + icon_state = "chaff_launcher" + w_class = SIZE_MEDIUM + +/obj/item/prop/almayer/handheld1 + name = "small handheld" + desc = "A small piece of electronic doodads" + icon_state = "handheld1" + w_class = SIZE_SMALL + +/obj/item/prop/almayer/comp_closed + name = "dropship maintenance computer" + desc = "A closed dropship maintenance computer that technicians and pilots use to find out what's wrong with a dropship. It has various outlets for different systems." + icon_state = "hangar_comp" + w_class = SIZE_LARGE + +/obj/item/prop/almayer/comp_open + name = "dropship maintenance computer" + desc = "An opened dropship maintenance computer, it seems to be off however. It's used by technicians and pilots to find damaged or broken systems on a dropship. It has various outlets for different systems." + icon_state = "hangar_comp_open" + w_class = SIZE_LARGE + +//lore fluff books and magazines + +/obj/item/prop/magazine + name = "generic prop magazine" + desc = "A Magazine with a picture of a pretty girl on it..wait isn't that my mom?" + icon = 'icons/obj/structures/props/posters.dmi' + icon_state = "poster15" + throw_speed = SPEED_FAST + throw_range = 5 + w_class = SIZE_MEDIUM + attack_verb = list("bashed", "whacked", "educated") + pickup_sound = "sound/handling/book_pickup.ogg" + drop_sound = "sound/handling/book_pickup.ogg" + black_market_value = 15 + +//random magazines +/obj/item/prop/magazine/dirty + name = "Dirty Magazine" + desc = "Wawaweewa." + icon_state = "poster17" + +/obj/item/prop/magazine/dirty/torn + name = "\improper torn magazine page" + desc = "Hubba hubba." + +/obj/item/prop/magazine/dirty/torn/alt + icon_state = "poster3" + + +//books +/obj/item/prop/magazine/book + name = "generic prop book" + desc = "some generic hardcover book, probably sucked" + icon = 'icons/obj/items/books.dmi' + icon_state = "bookSpaceLaw" + +/obj/item/prop/magazine/book/spacebeast + name = "\improper Space Beast, by Robert Morse" + desc = "An autobiography focusing on the events of 'Fury 161' in August 2179 following the arrival of 'Ellen Ripley' and an unknown alien creature known as 'The Dragon' the books writing is extremely crude and was book banned shorty after publication." + +/obj/item/prop/magazine/book/borntokill + name = "\improper Born to Kill" + desc = "An autobiography penned by Derik A.W. Tomahawk it recounts his service in the USCM. The book was harshly criticised for its bland and uncreative writing and wasn't well received by the general public or members of the UA military. However, artificial soldiers typically value the information contained within." + +/obj/item/prop/magazine/book/bladerunner + name = "\improper Bladerunner: A True Detectives Story" + desc = "In the dark undercity of Luna 2119, blade runner Richard Ford is called out of retirement to terminate a cult of replicants who have escaped Earth seeking the meaning of their existence." + +/obj/item/prop/magazine/book/starshiptroopers + name = "Starship Troopers" + desc = "Written by Robert A. Heinlein, this book really missed the mark when it comes to the individual equipment it depicts 'troopers' having, but it's still issued to every marine in basic so it must have some value." + +/obj/item/prop/magazine/book/theartofwar + name = "The Art of War" + desc = "A treatise on war written by Sun Tzu a great general, strategist, and philosopher from ancient Earth. This book is on the Commandant of the United States Colonial Marine Corps reading list and most officers can be found in possession of a copy. Most officers who've read it claim to know a little bit more about fighting than most enlisted but results may vary. " + +//boots magazine +/obj/item/prop/magazine/boots + name = "generic Boots! magazine" + desc = "The only official USCM magazine!" + +/obj/item/prop/magazine/boots/n117 + name = "Boots!: Issue No.117" + desc = "The only official USCM magazine, the headline reads 'STOP CANNING' the short paragraph further explains the dangers of marines throwing CN-20 Nerve gas into bathrooms as a prank." + +/obj/item/prop/magazine/boots/n150 + name = "Boots!: Issue No.150" + desc = "The only official USCM magazine, the headline reads 'UPP Rations, The truth.' the short paragraph further explains UPP field rations aren't standardized and are produced at a local level. Because of this, captured and confiscated UPP rations have included some odd choices such as duck liver, century eggs, lutefisk, pickled pig snout, canned tripe, and dehydrated candied radish snacks." + +/obj/item/prop/magazine/boots/n160 + name = "Boots!: Issue No.160" + desc = "The only official USCM magazine, the headline reads 'Corporate Liaison 'emotionally exhausted' from screwing so many people over.'" + +/obj/item/prop/magazine/boots/n054 + name = "Boots!: Issue No.54" + desc = "The only official USCM magazine, the headline reads 'ARMAT strikes back against litigants in M41A-MK2 self cleaning case'" + +/obj/item/prop/magazine/boots/n055 + name = "Boots!: Issue No.55" + desc = "The only official USCM magazine, the headline reads 'TEN tips to keep your UD4 cockpit both safer and more relaxing.'" diff --git a/code/game/objects/structures/airlock_assembly.dm b/code/game/objects/structures/airlock_assembly.dm index 49a594e96a52..0679e1287ff7 100644 --- a/code/game/objects/structures/airlock_assembly.dm +++ b/code/game/objects/structures/airlock_assembly.dm @@ -316,6 +316,7 @@ /obj/structure/airlock_assembly/multi_tile icon = 'icons/obj/structures/doors/airlock_assembly2x1.dmi' + icon_state = "door_as_g0" dir = EAST var/width = 1 diff --git a/code/game/objects/structures/barricade/barricade.dm b/code/game/objects/structures/barricade/barricade.dm index b522889d8429..eac5f154e26e 100644 --- a/code/game/objects/structures/barricade/barricade.dm +++ b/code/game/objects/structures/barricade/barricade.dm @@ -30,22 +30,26 @@ var/brute_multiplier = 1 var/burn_multiplier = 1 var/explosive_multiplier = 1 + var/brute_projectile_multiplier = 1 + var/burn_flame_multiplier = 1 var/repair_materials = list() var/metallic = TRUE /obj/structure/barricade/Initialize(mapload, mob/user) . = ..() + if(health != maxhealth) //Update cades mapped with a custom health + update_health(0, TRUE) if(user) user.count_niche_stat(STATISTICS_NICHE_CADES) addtimer(CALLBACK(src, PROC_REF(update_icon)), 0) starting_maxhealth = maxhealth -/obj/structure/barricade/initialize_pass_flags(datum/pass_flags_container/PF) +/obj/structure/barricade/initialize_pass_flags(datum/pass_flags_container/pass_flags) ..() - if (PF) - PF.flags_can_pass_all = NONE - PF.flags_can_pass_front = NONE - PF.flags_can_pass_behind = PASS_OVER^(PASS_OVER_ACID_SPRAY|PASS_OVER_THROW_MOB) + if (pass_flags) + pass_flags.flags_can_pass_all = NONE + pass_flags.flags_can_pass_front = NONE + pass_flags.flags_can_pass_behind = PASS_OVER^(PASS_OVER_ACID_SPRAY|PASS_OVER_THROW_MOB) flags_can_pass_front_temp = PASS_OVER_THROW_MOB flags_can_pass_behind_temp = PASS_OVER_THROW_MOB @@ -93,7 +97,7 @@ overlays += image('icons/obj/structures/barricades.dmi', icon_state = "+burn_upgrade_[damage_state]") if(BARRICADE_UPGRADE_BRUTE) overlays += image('icons/obj/structures/barricades.dmi', icon_state = "+brute_upgrade_[damage_state]") - if(BARRICADE_UPGRADE_EXPLOSIVE) + if(BARRICADE_UPGRADE_ANTIFF) overlays += image('icons/obj/structures/barricades.dmi', icon_state = "+explosive_upgrade_[damage_state]") if(is_wired) @@ -104,34 +108,34 @@ ..() -/obj/structure/barricade/hitby(atom/movable/AM) - if(AM.throwing && is_wired) - if(iscarbon(AM)) - var/mob/living/carbon/C = AM - if(C.mob_size <= MOB_SIZE_XENO) - C.visible_message(SPAN_DANGER("The barbed wire slices into [C]!"), +/obj/structure/barricade/hitby(atom/movable/atom_movable) + if(atom_movable.throwing && is_wired) + if(iscarbon(atom_movable)) + var/mob/living/carbon/living_carbon = atom_movable + if(living_carbon.mob_size <= MOB_SIZE_XENO) + living_carbon.visible_message(SPAN_DANGER("The barbed wire slices into [living_carbon]!"), SPAN_DANGER("The barbed wire slices into you!")) - C.apply_damage(10) - C.apply_effect(2, WEAKEN) //Leaping into barbed wire is VERY bad - playsound(C, "bonk", 75, FALSE) + living_carbon.apply_damage(10) + living_carbon.apply_effect(2, WEAKEN) //Leaping into barbed wire is VERY bad + playsound(living_carbon, "bonk", 75, FALSE) ..() -/obj/structure/barricade/Collided(atom/movable/AM) +/obj/structure/barricade/Collided(atom/movable/atom_movable) ..() - if(istype(AM, /mob/living/carbon/xenomorph/crusher)) - var/mob/living/carbon/xenomorph/crusher/C = AM + if(istype(atom_movable, /mob/living/carbon/xenomorph/crusher)) + var/mob/living/carbon/xenomorph/crusher/living_carbon = atom_movable - if (!C.throwing) + if (!living_carbon.throwing) return if(crusher_resistant) - visible_message(SPAN_DANGER("[C] smashes into [src]!")) + visible_message(SPAN_DANGER("[living_carbon] smashes into [src]!")) take_damage(150) playsound(src, barricade_hitsound, 25, TRUE) - else if(!C.stat) - visible_message(SPAN_DANGER("[C] smashes through [src]!")) + else if(!living_carbon.stat) + visible_message(SPAN_DANGER("[living_carbon] smashes through [src]!")) deconstruct(FALSE) playsound(src, barricade_hitsound, 25, TRUE) @@ -161,8 +165,8 @@ if(closed) return NO_BLOCKED_MOVEMENT - var/obj/structure/S = locate(/obj/structure) in get_turf(mover) - if(S && S.climbable && !(S.flags_atom & ON_BORDER) && climbable && isliving(mover)) //Climbable objects allow you to universally climb over others + var/obj/structure/structure = locate(/obj/structure) in get_turf(mover) + if(structure && structure.climbable && !(structure.flags_atom & ON_BORDER) && climbable && isliving(mover)) //Climbable objects allow you to universally climb over others return NO_BLOCKED_MOVEMENT return ..() @@ -178,33 +182,33 @@ /obj/structure/barricade/attack_animal(mob/user as mob) return attack_alien(user) -/obj/structure/barricade/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/weapon/zombie_claws)) +/obj/structure/barricade/attackby(obj/item/item, mob/user) + if(istype(item, /obj/item/weapon/zombie_claws)) user.visible_message(SPAN_DANGER("The zombie smashed at the [src.barricade_type] barricade!"), SPAN_DANGER("You smack the [src.barricade_type] barricade!")) if(barricade_hitsound) playsound(src, barricade_hitsound, 35, 1) - hit_barricade(W) + hit_barricade(item) return - for(var/obj/effect/xenomorph/acid/A in src.loc) - if(A.acid_t == src) + for(var/obj/effect/xenomorph/acid/acid in src.loc) + if(acid.acid_t == src) to_chat(user, "You can't get near that, it's melting!") return - if(istype(W, /obj/item/stack/barbed_wire)) - var/obj/item/stack/barbed_wire/B = W + if(istype(item, /obj/item/stack/barbed_wire)) + var/obj/item/stack/barbed_wire/barbed_wire = item if(can_wire) - user.visible_message(SPAN_NOTICE("[user] starts setting up [W.name] on [src]."), - SPAN_NOTICE("You start setting up [W.name] on [src].")) + user.visible_message(SPAN_NOTICE("[user] starts setting up [item.name] on [src]."), + SPAN_NOTICE("You start setting up [item.name] on [src].")) if(do_after(user, 20, INTERRUPT_NO_NEEDHAND|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD, src) && can_wire) // Make sure there's still enough wire in the stack - if(!B.use(1)) + if(!barbed_wire.use(1)) return playsound(src.loc, 'sound/effects/barbed_wire_movement.ogg', 25, 1) - user.visible_message(SPAN_NOTICE("[user] sets up [W.name] on [src]."), - SPAN_NOTICE("You set up [W.name] on [src].")) + user.visible_message(SPAN_NOTICE("[user] sets up [item.name] on [src]."), + SPAN_NOTICE("You set up [item.name] on [src].")) maxhealth += 50 update_health(-50) @@ -216,7 +220,7 @@ update_icon() return - if(HAS_TRAIT(W, TRAIT_TOOL_WIRECUTTERS)) + if(HAS_TRAIT(item, TRAIT_TOOL_WIRECUTTERS)) if(is_wired) user.visible_message(SPAN_NOTICE("[user] begin removing the barbed wire on [src]."), SPAN_NOTICE("You begin removing the barbed wire on [src].")) @@ -238,27 +242,27 @@ new/obj/item/stack/barbed_wire( src.loc ) return - if(W.force > force_level_absorption) + if(item.force > force_level_absorption) ..() if(barricade_hitsound) playsound(src, barricade_hitsound, 35, 1) - hit_barricade(W) + hit_barricade(item) -/obj/structure/barricade/bullet_act(obj/item/projectile/P) - bullet_ping(P) +/obj/structure/barricade/bullet_act(obj/item/projectile/bullet) + bullet_ping(bullet) - if(P.ammo.damage_type == BURN) - P.damage = P.damage * burn_multiplier + if(bullet.ammo.damage_type == BURN) + bullet.damage = bullet.damage * burn_multiplier else - P.damage = P.damage * brute_multiplier + bullet.damage = bullet.damage * brute_projectile_multiplier - if(istype(P.ammo, /datum/ammo/xeno/boiler_gas)) + if(istype(bullet.ammo, /datum/ammo/xeno/boiler_gas)) take_damage(round(50 * burn_multiplier)) - else if(P.ammo.flags_ammo_behavior & AMMO_ANTISTRUCT) - take_damage(P.damage * ANTISTRUCT_DMG_MULT_BARRICADES) + else if(bullet.ammo.flags_ammo_behavior & AMMO_ANTISTRUCT) + take_damage(bullet.damage * ANTISTRUCT_DMG_MULT_BARRICADES) - take_damage(P.damage) + take_damage(bullet.damage) return TRUE @@ -280,11 +284,11 @@ /obj/structure/barricade/ex_act(severity, direction, cause_data) - for(var/obj/structure/barricade/B in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade - if(B.dir == reverse_direction(dir)) + for(var/obj/structure/barricade/barricade in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade + if(barricade.dir == reverse_direction(dir)) spawn(1) - if(B) - B.ex_act(severity, direction) + if(barricade) + barricade.ex_act(severity, direction) if(health <= 0) var/location = get_turf(src) handle_debris(severity, direction) @@ -319,15 +323,15 @@ new /datum/effects/acid(src, null, null) /obj/structure/barricade/flamer_fire_act(dam = BURN_LEVEL_TIER_1) - take_damage(dam * burn_multiplier) + take_damage(dam * burn_flame_multiplier) -/obj/structure/barricade/proc/hit_barricade(obj/item/I) - take_damage(I.force * 0.5 * brute_multiplier) +/obj/structure/barricade/proc/hit_barricade(obj/item/item) + take_damage(item.force * 0.5 * brute_multiplier) /obj/structure/barricade/proc/take_damage(damage) - for(var/obj/structure/barricade/B in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade - if(B.dir == reverse_direction(dir)) - B.update_health(damage) + for(var/obj/structure/barricade/barricade in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade + if(barricade.dir == reverse_direction(dir)) + barricade.update_health(damage) update_health(damage) @@ -355,12 +359,12 @@ if(50 to 75) damage_state = BARRICADE_DMG_SLIGHT if(75 to INFINITY) damage_state = BARRICADE_DMG_NONE -/obj/structure/barricade/proc/weld_cade(obj/item/tool/weldingtool/WT, mob/user) +/obj/structure/barricade/proc/weld_cade(obj/item/tool/weldingtool/welder, mob/user) if(!metallic) user.visible_message(SPAN_WARNING("You can't weld \the [src]!")) return FALSE - if(!(WT.remove_fuel(2, user))) + if(!(welder.remove_fuel(2, user))) return FALSE user.visible_message(SPAN_NOTICE("[user] begins repairing damage to [src]."), @@ -411,20 +415,20 @@ return ..() -/obj/structure/barricade/proc/try_nailgun_usage(obj/item/W, mob/user) - if(length(repair_materials) == 0 || health >= maxhealth || !istype(W, /obj/item/weapon/gun/smg/nailgun)) +/obj/structure/barricade/proc/try_nailgun_usage(obj/item/item, mob/user) + if(length(repair_materials) == 0 || health >= maxhealth || !istype(item, /obj/item/weapon/gun/smg/nailgun)) return FALSE - var/obj/item/weapon/gun/smg/nailgun/NG = W + var/obj/item/weapon/gun/smg/nailgun/nailgun = item - if(!NG.in_chamber || !NG.current_mag || NG.current_mag.current_rounds < 3) + if(!nailgun.in_chamber || !nailgun.current_mag || nailgun.current_mag.current_rounds < 3) to_chat(user, SPAN_WARNING("You require at least 4 nails to complete this task!")) return FALSE // Check if either hand has a metal stack by checking the weapon offhand // Presume the material is a sheet until proven otherwise. var/obj/item/stack/sheet/material = null - if(user.l_hand == NG) + if(user.l_hand == nailgun) material = user.r_hand else material = user.l_hand @@ -443,8 +447,8 @@ to_chat(user, SPAN_WARNING("You'll need some adequate repair material in your other hand to patch up [src]!")) return FALSE - var/soundchannel = playsound(src, NG.repair_sound, 25, 1) - if(!do_after(user, NG.nailing_speed, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src)) + var/soundchannel = playsound(src, nailgun.repair_sound, 25, 1) + if(!do_after(user, nailgun.nailing_speed, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src)) playsound(src, null, channel = soundchannel) return FALSE @@ -452,7 +456,7 @@ to_chat(user, SPAN_WARNING("You seems to have misplaced the repair material!")) return FALSE - if(!NG.in_chamber || !NG.current_mag || NG.current_mag.current_rounds < 3) + if(!nailgun.in_chamber || !nailgun.current_mag || nailgun.current_mag.current_rounds < 3) to_chat(user, SPAN_WARNING("You require at least 4 nails to complete this task!")) return FALSE @@ -460,7 +464,7 @@ to_chat(user, SPAN_WARNING("You nail [material] to [src], restoring some of its integrity!")) update_damage_state() material.use(1) - NG.current_mag.current_rounds -= 3 - NG.in_chamber = null - NG.load_into_chamber() + nailgun.current_mag.current_rounds -= 3 + nailgun.in_chamber = null + nailgun.load_into_chamber() return TRUE diff --git a/code/game/objects/structures/barricade/deployable.dm b/code/game/objects/structures/barricade/deployable.dm index b64d0ab1bd0e..77aa6b7e6816 100644 --- a/code/game/objects/structures/barricade/deployable.dm +++ b/code/game/objects/structures/barricade/deployable.dm @@ -4,7 +4,7 @@ icon_state = "folding_0" health = 350 maxhealth = 350 - burn_multiplier = 1.15 + burn_multiplier = 0.85 brute_multiplier = 1 crusher_resistant = TRUE force_level_absorption = 15 @@ -23,56 +23,38 @@ . = ..() . += SPAN_INFO("Drag its sprite onto yourself to undeploy.") -/obj/structure/barricade/deployable/attackby(obj/item/W, mob/user) +/obj/structure/barricade/deployable/attackby(obj/item/item, mob/user) - if(iswelder(W)) - if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH)) + if(iswelder(item)) + if(!HAS_TRAIT(item, TRAIT_TOOL_BLOWTORCH)) to_chat(user, SPAN_WARNING("You need a stronger blowtorch!")) return if(user.action_busy) return - var/obj/item/tool/weldingtool/WT = W + var/obj/item/tool/weldingtool/welder = item if(health == maxhealth) to_chat(user, SPAN_WARNING("[src] doesn't need repairs.")) return - weld_cade(WT, user) + weld_cade(welder, user) return - else if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + else if(HAS_TRAIT(item, TRAIT_TOOL_CROWBAR)) if(user.action_busy) return - if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) - to_chat(user, SPAN_WARNING("You do not know where the loosening bolts are on [src]...")) - return - else - if(build_state == BARRICADE_BSTATE_UNSECURED) - to_chat(user, SPAN_NOTICE("You tighten the bolts on [src].")) - playsound(src.loc, 'sound/items/Ratchet.ogg', 25, 1) - build_state = BARRICADE_BSTATE_SECURED - else - to_chat(user, SPAN_NOTICE("You loosen the bolts on [src].")) - playsound(src.loc, 'sound/items/Ratchet.ogg', 25, 1) - build_state = BARRICADE_BSTATE_UNSECURED - - else if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) - if(build_state != BARRICADE_BSTATE_UNSECURED) - return - if(user.action_busy) - return - if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) + if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_TRAINED)) to_chat(user, SPAN_WARNING("You do not know how to collapse [src] using a crowbar...")) return else user.visible_message(SPAN_NOTICE("[user] starts collapsing [src]."), \ SPAN_NOTICE("You begin collapsing [src]...")) - playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) - if(do_after(user, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src)) + playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) + if(do_after(user, 1.5 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_FRIENDLY, src)) collapse(usr) else to_chat(user, SPAN_WARNING("You stop collapsing [src].")) - if(try_nailgun_usage(W, user)) + if(try_nailgun_usage(item, user)) return . = ..() @@ -87,26 +69,27 @@ if(over_object == usr && Adjacent(usr)) usr.visible_message(SPAN_NOTICE("[usr] starts collapsing [src]."), SPAN_NOTICE("You begin collapsing [src].")) - playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) - if(do_after(usr, 3 SECONDS, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src)) + playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) + if(do_after(usr, 3 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_FRIENDLY, src)) collapse(usr) else to_chat(usr, SPAN_WARNING("You stop collapsing [src].")) /obj/structure/barricade/deployable/proc/collapse(mob/living/carbon/human/user) - var/obj/item/stack/folding_barricade/FB = new source_type(loc) - FB.health = health - FB.maxhealth = maxhealth + var/obj/item/stack/folding_barricade/folding = new source_type(loc) + folding.stack_health = list(health) + folding.maxhealth = maxhealth if(istype(user)) user.visible_message(SPAN_NOTICE("[user] collapses [src]."), SPAN_NOTICE("You collapse [src].")) - user.put_in_active_hand(FB) + user.put_in_active_hand(folding) qdel(src) /obj/structure/barricade/deployable/initialize_pass_flags(datum/pass_flags_container/PF) ..() if(PF) PF.flags_can_pass_front &= ~PASS_OVER_THROW_MOB + PF.flags_can_pass_behind &= ~PASS_OVER_THROW_MOB // Cade in hands @@ -132,6 +115,14 @@ ) icon = 'icons/obj/items/marine-items.dmi' + var/list/stack_health = list() + +/obj/item/stack/folding_barricade/Initialize(mapload, init_amount) + . = ..() + for(var/counter in 1 to amount) + stack_health += initial(health) + + /obj/item/stack/folding_barricade/update_icon() . = ..() icon_state = "folding-[amount]" @@ -152,16 +143,16 @@ var/obj/structure/blocker/anti_cade/AC = locate(/obj/structure/blocker/anti_cade) in OT // for M2C HMG, look at smartgun_mount.dm if(!OT.allow_construction) - to_chat(usr, SPAN_WARNING("[src.singular_name] must be constructed on a proper surface!")) + to_chat(usr, SPAN_WARNING("[singular_name] must be constructed on a proper surface!")) return if(AC) - to_chat(usr, SPAN_WARNING("[src.singular_name] cannot be built here!")) + to_chat(usr, SPAN_WARNING("[singular_name] cannot be built here!")) return - user.visible_message(SPAN_NOTICE("[user] begins deploying [src.singular_name]."), - SPAN_NOTICE("You begin deploying [src.singular_name].")) + user.visible_message(SPAN_NOTICE("[user] begins deploying [singular_name]."), + SPAN_NOTICE("You begin deploying [singular_name].")) - playsound(src.loc, 'sound/items/Ratchet.ogg', 25, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 25, 1) if(!do_after(user, 1 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) to_chat(user, SPAN_WARNING("You were interrupted.")) @@ -172,12 +163,12 @@ to_chat(user, SPAN_WARNING("There is already \a [B] in this direction!")) return - user.visible_message(SPAN_NOTICE("[user] has finished deploying [src.singular_name]."), - SPAN_NOTICE("You finish deploying [src.singular_name].")) + user.visible_message(SPAN_NOTICE("[user] has finished deploying [singular_name]."), + SPAN_NOTICE("You finish deploying [singular_name].")) var/obj/structure/barricade/deployable/cade = new(user.loc) cade.setDir(user.dir) - cade.health = health + cade.health = pop(stack_health) cade.maxhealth = maxhealth cade.source_type = singular_type cade.update_damage_state() @@ -185,76 +176,90 @@ use(1) -/obj/item/stack/folding_barricade/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/stack/folding_barricade)) - var/obj/item/stack/folding_barricade/F = W - - if(health != maxhealth || F.health != F.maxhealth) - to_chat(user, "You cannot stack damaged [src.singular_name]\s.") +/obj/item/stack/folding_barricade/attackby(obj/item/item, mob/user) + if(istype(item, /obj/item/stack/folding_barricade)) + var/obj/item/stack/folding_barricade/folding = item + if(!ismob(loc)) //gather from ground + if(amount >= max_amount) + to_chat(user, "You cannot stack more [folding.singular_name]\s.") + return + var/to_transfer = min(folding.max_amount - folding.amount, amount) + for(var/counter in 1 to to_transfer) + folding.stack_health += pop(stack_health) + use(to_transfer) + folding.add(to_transfer) + to_chat(user, SPAN_INFO("You transfer [to_transfer] between the stacks.")) return - - if(!ismob(src.loc)) - return ..() - if(amount >= max_amount) - to_chat(user, "You cannot stack more [src.singular_name]\s.") + to_chat(user, "You cannot stack more [singular_name]\s.") return - var/to_transfer = min(max_amount - amount, F.amount) - F.use(to_transfer) + var/to_transfer = min(max_amount - amount, folding.amount) + for(var/counter in 1 to to_transfer) + stack_health += pop(folding.stack_health) + folding.use(to_transfer) add(to_transfer) to_chat(user, SPAN_INFO("You transfer [to_transfer] between the stacks.")) return - else if(iswelder(W)) - if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH)) + else if(iswelder(item)) + if(!HAS_TRAIT(item, TRAIT_TOOL_BLOWTORCH)) to_chat(user, SPAN_WARNING("You need a stronger blowtorch!")) return - if(src != user.get_inactive_hand()) - to_chat(user, SPAN_WARNING("You need to hold [src.singular_name] in hand or deploy to repair it.")) - return if(user.action_busy) return - var/obj/item/tool/weldingtool/WT = W - if(health == maxhealth) - to_chat(user, SPAN_WARNING("[src.singular_name] doesn't need repairs.")) + var/need_repairs = 0 + for(var/counter in 1 to length(stack_health)) + if(stack_health[counter] < maxhealth) + need_repairs++ + + if(!need_repairs) + to_chat(user, SPAN_WARNING("[singular_name] doesn't need repairs.")) return - if(!(WT.remove_fuel(2, user))) + var/obj/item/tool/weldingtool/welder = item + if(!(welder.remove_fuel(2, user))) return user.visible_message(SPAN_NOTICE("[user] begins repairing damage to [src]."), SPAN_NOTICE("You begin repairing the damage to [src].")) - playsound(src.loc, 'sound/items/Welder2.ogg', 25, TRUE) + playsound(loc, 'sound/items/Welder2.ogg', 25, TRUE) - var/welding_time = skillcheck(user, SKILL_CONSTRUCTION, 2) ? 5 SECONDS : 10 SECONDS - if(!do_after(user, welding_time, INTERRUPT_NO_NEEDHAND|BEHAVIOR_IMMOBILE, BUSY_ICON_FRIENDLY, src)) - return + var/welding_time = (skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED) ? 5 SECONDS : 10 SECONDS) * need_repairs + + if(src != user.get_inactive_hand()) + if(!do_after(user, welding_time, INTERRUPT_NO_NEEDHAND|BEHAVIOR_IMMOBILE, BUSY_ICON_FRIENDLY, src)) + return + else + if(!do_after(user, welding_time, (INTERRUPT_ALL & (~INTERRUPT_MOVED)), BUSY_ICON_FRIENDLY, src, INTERRUPT_DIFF_LOC)) //you can move while repairing if you have cade in hand + return user.visible_message(SPAN_NOTICE("[user] repairs some damage on [src]."), SPAN_NOTICE("You repair [src].")) user.count_niche_stat(STATISTICS_NICHE_REPAIR_CADES) - health += 200 - if(health > maxhealth) - health = maxhealth + for(var/counter in 1 to length(stack_health)) + stack_health[counter] += 200 + if(stack_health[counter] > maxhealth) + stack_health[counter] = maxhealth - playsound(src.loc, 'sound/items/Welder2.ogg', 25, TRUE) + playsound(loc, 'sound/items/Welder2.ogg', 25, TRUE) return . = ..() /obj/item/stack/folding_barricade/attack_hand(mob/user) - var/mob/living/carbon/human/H = user - if(!(amount > 1 && H.back == src)) + var/mob/living/carbon/human/human = user + if(!(amount > 1 && (human.back == src || human.get_inactive_hand() == src))) return ..() - var/obj/item/stack/F = new singular_type(user, 1) - transfer_fingerprints_to(F) - user.put_in_hands(F) - src.add_fingerprint(user) - F.add_fingerprint(user) + var/obj/item/stack/folding_barricade/folding = new singular_type(user, 1) + transfer_fingerprints_to(folding) + folding.stack_health = list(pop(stack_health)) + user.put_in_hands(folding) + add_fingerprint(user) + folding.add_fingerprint(user) use(1) /obj/item/stack/folding_barricade/MouseDrop(obj/over_object as obj) @@ -276,7 +281,7 @@ /obj/item/stack/folding_barricade/get_examine_text(mob/user) . = ..() - if(health < maxhealth) + if(round(min(stack_health)/maxhealth * 100) <= 75) . += SPAN_WARNING("It appears to be damaged.") /obj/item/stack/folding_barricade/three diff --git a/code/game/objects/structures/barricade/metal.dm b/code/game/objects/structures/barricade/metal.dm index 40f784b064e4..4056ac9021f8 100644 --- a/code/game/objects/structures/barricade/metal.dm +++ b/code/game/objects/structures/barricade/metal.dm @@ -39,12 +39,12 @@ . += SPAN_NOTICE("The cade is protected by a biohazardous upgrade.") if(BARRICADE_UPGRADE_BRUTE) . += SPAN_NOTICE("The cade is protected by a reinforced upgrade.") - if(BARRICADE_UPGRADE_EXPLOSIVE) - . += SPAN_NOTICE("The cade is protected by an explosive upgrade.") + if(BARRICADE_UPGRADE_ANTIFF) + . += SPAN_NOTICE("The cade is protected by a composite upgrade.") -/obj/structure/barricade/metal/attackby(obj/item/W, mob/user) - if(iswelder(W)) - if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH)) +/obj/structure/barricade/metal/attackby(obj/item/item, mob/user) + if(iswelder(item)) + if(!HAS_TRAIT(item, TRAIT_TOOL_BLOWTORCH)) to_chat(user, SPAN_WARNING("You need a stronger blowtorch!")) return if(user.action_busy) @@ -52,7 +52,7 @@ if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_TRAINED)) to_chat(user, SPAN_WARNING("You're not trained to repair [src]...")) return - var/obj/item/tool/weldingtool/WT = W + var/obj/item/tool/weldingtool/welder = item if(damage_state == BARRICADE_DMG_HEAVY) to_chat(user, SPAN_WARNING("[src] has sustained too much structural damage to be repaired.")) return @@ -61,10 +61,10 @@ to_chat(user, SPAN_WARNING("[src] doesn't need repairs.")) return - weld_cade(WT, user) + weld_cade(welder, user) return - if(try_nailgun_usage(W, user)) + if(try_nailgun_usage(item, user)) return for(var/obj/effect/xenomorph/acid/A in src.loc) @@ -74,7 +74,7 @@ switch(build_state) if(BARRICADE_BSTATE_SECURED) //Fully constructed step. Use screwdriver to remove the protection panels to reveal the bolts - if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) + if(HAS_TRAIT(item, TRAIT_TOOL_SCREWDRIVER)) if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) to_chat(user, SPAN_WARNING("You are not trained to touch [src]...")) return @@ -88,16 +88,16 @@ build_state = BARRICADE_BSTATE_UNSECURED return - if(istype(W, /obj/item/stack/sheet/metal)) + if(istype(item, /obj/item/stack/sheet/metal)) if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) to_chat(user, SPAN_WARNING("You are not trained to touch [src]...")) return if(upgraded) to_chat(user, SPAN_NOTICE("This barricade is already upgraded.")) return - var/obj/item/stack/sheet/metal/M = W + var/obj/item/stack/sheet/metal/metal = item if(user.client?.prefs?.no_radials_preference) - var/choice = tgui_input_list(user, "Choose an upgrade to apply to the barricade", "Apply Upgrade", list(BARRICADE_UPGRADE_BURN, BARRICADE_UPGRADE_BRUTE, BARRICADE_UPGRADE_EXPLOSIVE)) + var/choice = tgui_input_list(user, "Choose an upgrade to apply to the barricade", "Apply Upgrade", list(BARRICADE_UPGRADE_BURN, BARRICADE_UPGRADE_BRUTE, BARRICADE_UPGRADE_ANTIFF)) if(!choice) return if(!user.Adjacent(src)) @@ -106,33 +106,37 @@ if(upgraded) to_chat(user, SPAN_NOTICE("This barricade is already upgraded.")) return - if(M.get_amount() < 2) + if(metal.get_amount() < 2) to_chat(user, SPAN_NOTICE("You lack the required metal.")) return - if((usr.get_active_hand()) != M) - to_chat(user, SPAN_WARNING("You must be holding the [M] to upgrade \the [src]!")) + if((usr.get_active_hand()) != metal) + to_chat(user, SPAN_WARNING("You must be holding the [metal] to upgrade \the [src]!")) return switch(choice) if(BARRICADE_UPGRADE_BURN) burn_multiplier = 0.75 + burn_flame_multiplier = 0.75 upgraded = BARRICADE_UPGRADE_BURN to_chat(user, SPAN_NOTICE("You applied a biohazardous upgrade.")) if(BARRICADE_UPGRADE_BRUTE) brute_multiplier = 0.75 + brute_projectile_multiplier = 0.75 upgraded = BARRICADE_UPGRADE_BRUTE to_chat(user, SPAN_NOTICE("You applied a reinforced upgrade.")) - if(BARRICADE_UPGRADE_EXPLOSIVE) - explosive_multiplier = 0.75 - upgraded = BARRICADE_UPGRADE_EXPLOSIVE - to_chat(user, SPAN_NOTICE("You applied an explosive upgrade.")) + if(BARRICADE_UPGRADE_ANTIFF) + explosive_multiplier = 0.5 + brute_projectile_multiplier = 0.5 + burn_flame_multiplier = 0.5 + upgraded = BARRICADE_UPGRADE_ANTIFF + to_chat(user, SPAN_NOTICE("You applied a composite upgrade.")) - M.use(2) + metal.use(2) user.count_niche_stat(STATISTICS_NICHE_UPGRADE_CADES) update_icon() return else - var/static/list/cade_types = list(BARRICADE_UPGRADE_EXPLOSIVE = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "explosive_obj"), BARRICADE_UPGRADE_BRUTE = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "brute_obj"), BARRICADE_UPGRADE_BURN = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "burn_obj")) + var/static/list/cade_types = list(BARRICADE_UPGRADE_ANTIFF = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "explosive_obj"), BARRICADE_UPGRADE_BRUTE = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "brute_obj"), BARRICADE_UPGRADE_BURN = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "burn_obj")) var/choice = show_radial_menu(user, src, cade_types, require_near = TRUE) if(!choice) return @@ -142,33 +146,37 @@ if(upgraded) to_chat(user, SPAN_NOTICE("This barricade is already upgraded.")) return - if(M.get_amount() < 2) + if(metal.get_amount() < 2) to_chat(user, SPAN_NOTICE("You lack the required metal.")) return - if((usr.get_active_hand()) != M) - to_chat(user, SPAN_WARNING("You must be holding the [M] to upgrade \the [src]!")) + if((usr.get_active_hand()) != metal) + to_chat(user, SPAN_WARNING("You must be holding the [metal] to upgrade \the [src]!")) return switch(choice) if(BARRICADE_UPGRADE_BURN) burn_multiplier = 0.75 + burn_flame_multiplier = 0.75 upgraded = BARRICADE_UPGRADE_BURN to_chat(user, SPAN_NOTICE("You applied a biohazardous upgrade.")) if(BARRICADE_UPGRADE_BRUTE) brute_multiplier = 0.75 + brute_projectile_multiplier = 0.75 upgraded = BARRICADE_UPGRADE_BRUTE to_chat(user, SPAN_NOTICE("You applied a reinforced upgrade.")) - if(BARRICADE_UPGRADE_EXPLOSIVE) - explosive_multiplier = 0.75 - upgraded = BARRICADE_UPGRADE_EXPLOSIVE - to_chat(user, SPAN_NOTICE("You applied an explosive upgrade.")) + if(BARRICADE_UPGRADE_ANTIFF) + explosive_multiplier = 0.5 + brute_projectile_multiplier = 0.5 + burn_flame_multiplier = 0.5 + upgraded = BARRICADE_UPGRADE_ANTIFF + to_chat(user, SPAN_NOTICE("You applied a composite upgrade.")) - M.use(2) + metal.use(2) user.count_niche_stat(STATISTICS_NICHE_UPGRADE_CADES) update_icon() return - if(HAS_TRAIT(W, TRAIT_TOOL_MULTITOOL)) + if(HAS_TRAIT(item, TRAIT_TOOL_MULTITOOL)) if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) to_chat(user, SPAN_WARNING("You are not trained to touch [src]...")) return @@ -181,13 +189,15 @@ upgraded = null explosive_multiplier = initial(explosive_multiplier) brute_multiplier = initial(brute_multiplier) + brute_projectile_multiplier = initial(brute_projectile_multiplier) burn_multiplier = initial(burn_multiplier) + burn_flame_multiplier = initial(burn_flame_multiplier) new stack_type (loc, 1) update_icon() return if(BARRICADE_BSTATE_UNSECURED) //Protection panel removed step. Screwdriver to put the panel back, wrench to unsecure the anchor bolts - if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) + if(HAS_TRAIT(item, TRAIT_TOOL_SCREWDRIVER)) if(user.action_busy) return if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) @@ -199,7 +209,7 @@ SPAN_NOTICE("You set [src]'s protection panel back.")) build_state = BARRICADE_BSTATE_SECURED return - if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + if(HAS_TRAIT(item, TRAIT_TOOL_WRENCH)) if(user.action_busy) return if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) @@ -214,7 +224,7 @@ update_icon() //unanchored changes layer return if(BARRICADE_BSTATE_MOVABLE) //Anchor bolts loosened step. Apply crowbar to unseat the panel and take apart the whole thing. Apply wrench to resecure anchor bolts - if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + if(HAS_TRAIT(item, TRAIT_TOOL_WRENCH)) if(user.action_busy) return if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) @@ -224,8 +234,8 @@ if(B != src && B.dir == dir) to_chat(user, SPAN_WARNING("There's already a barricade here.")) return - var/turf/open/T = loc - if(!(istype(T) && T.allow_construction)) + var/turf/open/turf = loc + if(!(istype(turf) && turf.allow_construction)) to_chat(user, SPAN_WARNING("[src] must be secured on a proper surface!")) return playsound(src.loc, 'sound/items/Ratchet.ogg', 25, 1) @@ -236,7 +246,7 @@ anchored = TRUE update_icon() //unanchored changes layer return - if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) + if(HAS_TRAIT(item, TRAIT_TOOL_CROWBAR)) if(user.action_busy) return if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) diff --git a/code/game/objects/structures/barricade/sandbags.dm b/code/game/objects/structures/barricade/sandbags.dm index d3dce285ab92..0e2b77b4c1e5 100644 --- a/code/game/objects/structures/barricade/sandbags.dm +++ b/code/game/objects/structures/barricade/sandbags.dm @@ -90,7 +90,7 @@ user.visible_message(SPAN_NOTICE("[user] starts adding more [SB] to [src]."), \ SPAN_NOTICE("You start adding sandbags to [src].")) for(var/i = build_stage to BARRICADE_SANDBAG_5) - if(build_stage >= BARRICADE_SANDBAG_5 || !do_after(user, 5, INTERRUPT_NO_NEEDHAND, BUSY_ICON_FRIENDLY, src) || build_stage >= BARRICADE_SANDBAG_5) + if(build_stage >= BARRICADE_SANDBAG_5 || !do_after(user, 5, INTERRUPT_NO_NEEDHAND, BUSY_ICON_FRIENDLY, src) || build_stage >= BARRICADE_SANDBAG_5 || SB.amount == 0) break SB.use(1) increment_build_stage() diff --git a/code/game/objects/structures/blocker.dm b/code/game/objects/structures/blocker.dm index 333fdbd8f3a9..aadf6d2a099e 100644 --- a/code/game/objects/structures/blocker.dm +++ b/code/game/objects/structures/blocker.dm @@ -46,9 +46,14 @@ icon_state = "smoke" opacity = TRUE -/obj/structure/blocker/fog/New() - ..() - dir = pick(CARDINAL_DIRS) +/obj/structure/blocker/fog/Initialize(mapload, time_to_dispel) + . = ..() + + if(!time_to_dispel) + return INITIALIZE_HINT_QDEL + + dir = pick(CARDINAL_DIRS) + QDEL_IN(src, time_to_dispel + rand(-5 SECONDS, 5 SECONDS)) /obj/structure/blocker/fog/attack_hand(mob/M) to_chat(M, SPAN_NOTICE("You peer through the fog, but it's impossible to tell what's on the other side...")) diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index 793d47e8954e..00db6520495c 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -36,11 +36,11 @@ /obj/structure/catwalk/prison icon = 'icons/turf/floors/prison.dmi' - icon_state = "catwalk_plating" + icon_state = "plating_catwalk" base_state = "catwalk" /obj/structure/catwalk/prison/alt - icon_state = "catwalk_plating_alt" + icon_state = "plating_catwalk_alt" base_state = "catwalk_alt" /obj/structure/catwalk/bigred diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 3449c9d74278..8c8d6b6920a8 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -31,10 +31,7 @@ /obj/structure/closet/Initialize() . = ..() if(!opened && fill_from_loc) // if closed, any item at the crate's loc is put in the contents - for(var/obj/item/I in src.loc) - if(I.density || I.anchored || I == src) - continue - I.forceMove(src) + store_items() GLOB.closet_list += src flags_atom |= USES_HEARING @@ -138,21 +135,23 @@ return stored_units /obj/structure/closet/proc/store_mobs(stored_units) - for(var/mob/M in src.loc) + for(var/mob/cur_mob in src.loc) if(stored_units + mob_size > storage_capacity) break - if(istype (M, /mob/dead/observer)) + if(istype (cur_mob, /mob/dead/observer)) continue - if(M.buckled) + if(cur_mob.buckled) + continue + if(cur_mob.anchored) continue - M.forceMove(src) + cur_mob.forceMove(src) stored_units += mob_size return stored_units /obj/structure/closet/proc/toggle(mob/living/user) user.next_move = world.time + 5 - if(!(src.opened ? src.close() : src.open())) + if(!(src.opened ? src.close(user) : src.open())) to_chat(user, SPAN_NOTICE("It won't budge!")) return @@ -246,19 +245,22 @@ else if(istype(W, /obj/item/packageWrap) || istype(W, /obj/item/explosive/plastic)) return else if(iswelder(W)) + if(material != MATERIAL_METAL && material != MATERIAL_PLASTEEL) + to_chat(user, SPAN_WARNING("You cannot weld [material]!")) + return FALSE//Can't weld wood/plastic. if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH)) to_chat(user, SPAN_WARNING("You need a stronger blowtorch!")) - return + return FALSE var/obj/item/tool/weldingtool/WT = W if(!WT.isOn()) to_chat(user, SPAN_WARNING("\The [WT] needs to be on!")) - return + return FALSE if(!WT.remove_fuel(0, user)) to_chat(user, SPAN_NOTICE("You need more welding fuel to complete this task.")) - return + return FALSE playsound(src, 'sound/items/Welder.ogg', 25, 1) if(!do_after(user, 10 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) - return + return FALSE welded = !welded update_icon() for(var/mob/M as anything in viewers(src)) @@ -267,9 +269,9 @@ if(isxeno(user)) var/mob/living/carbon/xenomorph/opener = user src.attack_alien(opener) - return + return FALSE src.attack_hand(user) - return + return TRUE /obj/structure/closet/MouseDrop_T(atom/movable/O, mob/user) if(!opened) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm index 56328404702e..5772db33198d 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm @@ -5,7 +5,7 @@ GLOBAL_LIST_EMPTY(co_secure_boxes) //MARINE COMMAND CLOSET /obj/structure/closet/secure_closet/commander name = "commanding officer's locker" - req_access = list(ACCESS_MARINE_CAPTAIN) + req_access = list(ACCESS_MARINE_CO) icon_state = "secure_locked_commander" icon_closed = "secure_unlocked_commander" icon_locked = "secure_locked_commander" @@ -22,7 +22,7 @@ GLOBAL_LIST_EMPTY(co_secure_boxes) /obj/structure/closet/secure_closet/securecom name = "commanding officer's secure box" - req_access = list(ACCESS_MARINE_CAPTAIN) + req_access = list(ACCESS_MARINE_CO) desc = "A safe for the Commanding Officer to store any equipment they need to have ready at a moment's notice. There's a note inside saying that whatever was inside it before was moved out." icon = 'icons/obj/structures/marine_closet.dmi' icon_state = "commander_safe" @@ -134,7 +134,7 @@ GLOBAL_LIST_EMPTY(co_secure_boxes) new /obj/item/clothing/under/marine/officer/pilot(src) new /obj/item/clothing/shoes/marine(src) new /obj/item/clothing/suit/armor/vest/pilot(src) - new /obj/item/storage/large_holster/m39(src) + new /obj/item/storage/belt/gun/m39(src) new /obj/item/storage/backpack/marine/satchel(src) new /obj/item/clothing/gloves/yellow(src) new /obj/item/clothing/glasses/sunglasses(src) @@ -306,8 +306,8 @@ GLOBAL_LIST_EMPTY(co_secure_boxes) /obj/structure/closet/secure_closet/req_officer/Initialize() . = ..() - new /obj/item/device/radio/headset/almayer/ro(src) - new /obj/item/clothing/under/rank/ro_suit(src) + new /obj/item/device/radio/headset/almayer/qm(src) + new /obj/item/clothing/under/rank/qm_suit(src) new /obj/item/clothing/shoes/marine(src) new /obj/item/storage/belt/marine(src) new /obj/item/clothing/head/cmcap/req(src) 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 357606e01ee6..8bb00a349fce 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm @@ -130,4 +130,4 @@ /obj/structure/closet/secure_closet/guncabinet/wy name = "weyland yutani gun cabinet" - req_access = ACCESS_WY_CORPORATE + req_access = ACCESS_WY_SECURITY 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 11bd32b8fdb7..e290a23a61e9 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 @@ -41,7 +41,7 @@ open() else src.req_access = list() - src.req_access += pick(get_all_accesses()) + src.req_access += pick(get_access(ACCESS_LIST_MARINE_MAIN)) ..() /obj/structure/closet/secure_closet/proc/togglelock(mob/living/user) 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 8a0f126be71b..11b440e0e2ec 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -1,13 +1,12 @@ /obj/structure/closet/secure_closet/warden name = "Warden's Locker" req_one_access = list(ACCESS_MARINE_BRIG, ACCESS_CIVILIAN_BRIG) - icon_state = "wardensecure1" - icon_closed = "wardensecure" - icon_locked = "wardensecure1" - icon_opened = "wardensecureopen" - icon_broken = "wardensecurebroken" - icon_off = "wardensecureoff" - + icon_state = "secure_locked_warden" + icon_closed = "secure_unlocked_warden" + icon_locked = "secure_locked_warden" + icon_opened = "secure_open_warden" + icon_broken = "secure_broken_warden" + icon_off = "secure_closed_warden" /obj/structure/closet/secure_closet/warden/Initialize() . = ..() if(prob(50)) @@ -224,15 +223,15 @@ new /obj/item/storage/briefcase(src) /obj/structure/closet/secure_closet/wall - name = "wall locker" + name = "security wall locker" req_access = list(ACCESS_MARINE_BRIG, ACCESS_CIVILIAN_BRIG) - icon_state = "wall-locker1" + icon_state = "security_wall_locked" density = TRUE - icon_closed = "wall-locker" - icon_locked = "wall-locker1" - icon_opened = "wall-lockeropen" - icon_broken = "wall-lockerbroken" - icon_off = "wall-lockeroff" + icon_closed = "security_wall_closed" + icon_locked = "security_wall_locked" + icon_opened = "security_wall_open" + icon_broken = "security_wall_spark" + icon_off = "security_wall_off" //too small to put a man in large = 0 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 89393ee9a43b..7848aaba4897 100644 --- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm @@ -22,7 +22,12 @@ /obj/structure/closet/emcloset/Initialize() . = ..() +#ifndef UNIT_TESTS switch (pickweight(list("small" = 55, "aid" = 25, "tank" = 10, "both" = 10, "nothing" = 0, "delete" = 0))) +#else + var/test = "both" + switch (test) // We don't want randomness in tests +#endif if ("small") new /obj/item/tank/emergency_oxygen(src) new /obj/item/tank/emergency_oxygen(src) @@ -51,12 +56,12 @@ // teehee - Ah, tg coders... if ("delete") - qdel(src) + return INITIALIZE_HINT_QDEL //If you want to re-add fire, just add "fire" = 15 to the pick list. /*if ("fire") new /obj/structure/closet/firecloset(src.loc) - qdel(src)*/ + return INITIALIZE_HINT_QDEL*/ /obj/structure/closet/emcloset/legacy/Initialize() . = ..() diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm index fbf852333046..2393b5df8265 100644 --- a/code/game/objects/structures/crates_lockers/largecrate.dm +++ b/code/game/objects/structures/crates_lockers/largecrate.dm @@ -18,16 +18,36 @@ return /obj/structure/largecrate/proc/unpack() - for(var/atom/movable/A in contents) - A.forceMove(loc) + var/turf/current_turf = get_turf(src) // Get the turf the crate is on + playsound(src, unpacking_sound, 35) + + /// Store the reference of the crate material + var/obj/item/stack/sheet/material_sheet + if(parts_type) // Create the crate material and store its reference + material_sheet = new parts_type(current_turf, 2) + + // Move the objects back to the turf, above the crate material + for(var/atom/movable/moving_atom in contents) + var/atom/movable/current_atom = contents[1] + current_atom.forceMove(current_turf) + deconstruct(TRUE) + // Move the crate material to the bottom of the turf's contents + if(material_sheet) + move_to_bottom(material_sheet, current_turf) + +/// Custom proc to move an object to the bottom of the turf's contents +/obj/structure/largecrate/proc/move_to_bottom(obj/moving_down, turf/current_turf) + if(!istype(moving_down) || !istype(current_turf)) + return + for(var/atom/movable/checking_atom in current_turf.contents) + if(checking_atom != moving_down) + checking_atom.layer = max(checking_atom.layer, moving_down.layer + 0.1) + /obj/structure/largecrate/deconstruct(disassembled = TRUE) - if(disassembled) - if(parts_type) - new parts_type(loc, 2) - else + if(!disassembled) new /obj/item/stack/sheet/wood(loc) return ..() @@ -44,13 +64,22 @@ M.animation_attack_on(src) unpack() M.visible_message(SPAN_DANGER("[M] smashes [src] apart!"), \ - SPAN_DANGER("You smash [src] apart!"), 5, CHAT_TYPE_XENO_COMBAT) + SPAN_DANGER("You smash [src] apart!"), null, 5, CHAT_TYPE_XENO_COMBAT) return XENO_ATTACK_ACTION /obj/structure/largecrate/ex_act(power) if(power >= EXPLOSION_THRESHOLD_VLOW) unpack() +/obj/structure/largecrate/proc/take_damage(damage) + health -= damage + if(health <= 0) + unpack() + +/obj/structure/largecrate/bullet_act(obj/item/projectile/P) + take_damage(P.calculate_damage(P.damage)) + return TRUE + /obj/structure/largecrate/mule icon_state = "mulecrate" @@ -327,13 +356,10 @@ /obj/item/weapon/gun/revolver/cmb = /obj/item/ammo_magazine/revolver/cmb, /obj/item/weapon/gun/shotgun/merc = /obj/item/ammo_magazine/handful/shotgun/buckshot, /obj/item/weapon/gun/shotgun/pump/dual_tube/cmb = /obj/item/ammo_magazine/handful/shotgun/buckshot, - /obj/item/weapon/gun/shotgun/double = /obj/item/ammo_magazine/handful/shotgun/buckshot, - /obj/item/weapon/gun/shotgun/double/with_stock = /obj/item/ammo_magazine/handful/shotgun/buckshot, /obj/item/weapon/gun/smg/mp27 = /obj/item/ammo_magazine/smg/mp27, /obj/item/weapon/gun/pistol/skorpion = /obj/item/ammo_magazine/pistol/skorpion, /obj/item/weapon/gun/smg/mac15 = /obj/item/ammo_magazine/smg/mac15, /obj/item/weapon/gun/smg/uzi = /obj/item/ammo_magazine/smg/uzi, - /obj/item/weapon/gun/m60 = /obj/item/ammo_magazine/m60, /obj/item/weapon/gun/rifle/mar40/carbine = /obj/item/ammo_magazine/rifle/mar40, /obj/item/weapon/gun/smg/ppsh = /obj/item/ammo_magazine/smg/ppsh, /obj/item/weapon/gun/rifle/l42a = /obj/item/ammo_magazine/rifle/l42a, @@ -391,7 +417,6 @@ new /obj/item/storage/pill_bottle/inaprovaline(src) new /obj/item/storage/pouch/medical(src) new /obj/item/storage/pouch/firstaid/full(src) - new /obj/item/storage/box/quickclot(src) /obj/structure/largecrate/hunter_games_surgery name = "surgery crate" diff --git a/code/game/objects/structures/crates_lockers/secure_crates.dm b/code/game/objects/structures/crates_lockers/secure_crates.dm index abdab195fa11..0bd77d877ee6 100644 --- a/code/game/objects/structures/crates_lockers/secure_crates.dm +++ b/code/game/objects/structures/crates_lockers/secure_crates.dm @@ -104,7 +104,7 @@ open() else src.req_access = list() - src.req_access += pick(get_all_accesses()) + src.req_access += pick(get_access(ACCESS_LIST_MARINE_MAIN)) ..() diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index 6f365220116d..e8e4b3b0966e 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -62,7 +62,38 @@ PLANT_CUT_MACHETE = 3 = Needs at least a machete to be cut down /obj/structure/flora/flamer_fire_act() fire_act() +/obj/structure/flora/fire_act() + if(QDELETED(src) || (fire_flag & FLORA_NO_BURN) || burning) + return + burning = TRUE + var/spread_time = rand(75, 150) + if(!(fire_flag & FLORA_BURN_NO_SPREAD)) + addtimer(CALLBACK(src, PROC_REF(spread_fire)), spread_time) + addtimer(CALLBACK(src, PROC_REF(burn_up)), spread_time + 5 SECONDS) + +/obj/structure/flora/proc/spread_fire() + for(var/D in cardinal) //Spread fire + var/turf/T = get_step(src.loc, D) + if(T) + for(var/obj/structure/flora/F in T) + if(fire_flag & FLORA_BURN_SPREAD_ONCE) + F.fire_flag |= FLORA_BURN_NO_SPREAD + if(!(locate(/obj/flamer_fire) in T)) + new /obj/flamer_fire(T, create_cause_data("wildfire")) + +/obj/structure/flora/proc/burn_up() + new /obj/effect/decal/cleanable/dirt(loc) + if(center) + new /obj/effect/decal/cleanable/dirt(loc) //Produces more ash at the center + qdel(src) +/obj/structure/flora/ex_act(power) + if(power >= EXPLOSION_THRESHOLD_VLOW) + deconstruct(FALSE) + +/obj/structure/flora/get_projectile_hit_boolean(obj/item/projectile/P) + . = ..() + return FALSE //trees /obj/structure/flora/tree @@ -80,10 +111,30 @@ PLANT_CUT_MACHETE = 3 = Needs at least a machete to be cut down icon = 'icons/obj/structures/props/pinetrees.dmi' icon_state = "pine_c" +//dead /obj/structure/flora/tree/dead icon = 'icons/obj/structures/props/deadtrees.dmi' icon_state = "tree_1" +/obj/structure/flora/tree/dead/tree_1 + icon_state = "tree_1" + +/obj/structure/flora/tree/dead/tree_2 + icon_state = "tree_2" + +/obj/structure/flora/tree/dead/tree_3 + icon_state = "tree_3" + +/obj/structure/flora/tree/dead/tree_4 + icon_state = "tree_4" + +/obj/structure/flora/tree/dead/tree_5 + icon_state = "tree_5" + +/obj/structure/flora/tree/dead/tree_6 + icon_state = "tree_6" + +//joshua /obj/structure/flora/tree/joshua name = "joshua tree" desc = "A tall tree covered in spiky-like needles, covering its trunk." @@ -125,30 +176,138 @@ ICE GRASS /obj/structure/flora/grass/ice icon = 'icons/obj/structures/props/snowflora.dmi' + icon_state = "" variations = 3 +//brown /obj/structure/flora/grass/ice/brown + icon_state = "snowgrassbb_1" icon_tag = "snowgrassbb" +/obj/structure/flora/grass/ice/brown/snowgrassbb_1 + icon_state = "snowgrassbb_1" + +/obj/structure/flora/grass/ice/brown/snowgrassbb_2 + icon_state = "snowgrassbb_2" + +/obj/structure/flora/grass/ice/brown/snowgrassbb_3 + icon_state = "snowgrassbb_3" + +//green /obj/structure/flora/grass/ice/green + icon_state = "snowgrassgb_1" icon_tag = "snowgrassgb" +//both /obj/structure/flora/grass/ice/both + icon_state = "snowgrassall_1" icon_tag = "snowgrassall" /* +ICEY GRASS. IT LOOKS LIKE IT'S MADE OF ICE. + +*/ + +/obj/structure/flora/grass/ice/icey + icon_state = "icegrass5" //full patch of grass + icon_tag = "icegrass" + +/obj/structure/flora/grass/ice/icey/eightdirection + icon_state = "icegrass1" //8 different directional states. + +/obj/structure/flora/grass/ice/icey/fourdirection + icon_state = "icegrass2" //4 different directional states + +/obj/structure/flora/grass/ice/icey/center + icon_state = "icegrass3" //1 center piece of grass + +/obj/structure/flora/grass/ice/icey/centerfull + icon_state = "icegrass4" //More grass. + + +/* DESERT GRASS */ +//Light desert grass + /obj/structure/flora/grass/desert icon = 'icons/obj/structures/props/dam.dmi' icon_state = "lightgrass_1" +// to replace with +/obj/structure/flora/grass/desert/lightgrass_1 + icon_state = "lightgrass_1" + +/obj/structure/flora/grass/desert/lightgrass_2 + icon_state = "lightgrass_2" + +/obj/structure/flora/grass/desert/lightgrass_3 + icon_state = "lightgrass_3" + +/obj/structure/flora/grass/desert/lightgrass_4 + icon_state = "lightgrass_4" + +/obj/structure/flora/grass/desert/lightgrass_5 + icon_state = "lightgrass_5" + +/obj/structure/flora/grass/desert/lightgrass_6 + icon_state = "lightgrass_6" + +/obj/structure/flora/grass/desert/lightgrass_7 + icon_state = "lightgrass_7" + +/obj/structure/flora/grass/desert/lightgrass_8 + icon_state = "lightgrass_8" + +/obj/structure/flora/grass/desert/lightgrass_9 + icon_state = "lightgrass_9" + +/obj/structure/flora/grass/desert/lightgrass_10 + icon_state = "lightgrass_10" + +/obj/structure/flora/grass/desert/lightgrass_11 + icon_state = "lightgrass_11" + +/obj/structure/flora/grass/desert/lightgrass_12 + icon_state = "lightgrass_12" + +//heavy desert grass /obj/structure/flora/grass/desert/heavy icon_state = "heavygrass_1" +/obj/structure/flora/grass/desert/heavygrass_1 + icon_state = "heavygrass_1" + +/obj/structure/flora/grass/desert/heavygrass_2 + icon_state = "heavygrass_2" + +/obj/structure/flora/grass/desert/heavygrass_3 + icon_state = "heavygrass_3" + +/obj/structure/flora/grass/desert/heavygrass_4 + icon_state = "heavygrass_4" + +/obj/structure/flora/grass/desert/heavygrass_5 + icon_state = "heavygrass_5" + +/obj/structure/flora/grass/desert/heavygrass_6 + icon_state = "heavygrass_6" + +/obj/structure/flora/grass/desert/heavygrass_7 + icon_state = "heavygrass_7" + +/obj/structure/flora/grass/desert/heavygrass_8 + icon_state = "heavygrass_8" + +/obj/structure/flora/grass/desert/heavygrass_9 + icon_state = "heavygrass_9" + +/obj/structure/flora/grass/desert/heavygrass_10 + icon_state = "heavygrass_10" + /* TALLGRASS - SPREADS FIRES @@ -172,35 +331,6 @@ ICE GRASS overlays.Cut() overlays += image("icon"=src.icon,"icon_state"=overlay_type,"layer"=ABOVE_XENO_LAYER,"dir"=dir) -/obj/structure/flora/fire_act() - if(QDELETED(src) || (fire_flag & FLORA_NO_BURN) || burning) - return - burning = TRUE - var/spread_time = rand(75, 150) - if(!(fire_flag & FLORA_BURN_NO_SPREAD)) - addtimer(CALLBACK(src, PROC_REF(spread_fire)), spread_time) - addtimer(CALLBACK(src, PROC_REF(burn_up)), spread_time + 5 SECONDS) - -/obj/structure/flora/proc/spread_fire() - for(var/D in cardinal) //Spread fire - var/turf/T = get_step(src.loc, D) - if(T) - for(var/obj/structure/flora/F in T) - if(fire_flag & FLORA_BURN_SPREAD_ONCE) - F.fire_flag |= FLORA_BURN_NO_SPREAD - if(!(locate(/obj/flamer_fire) in T)) - new /obj/flamer_fire(T, create_cause_data("wildfire")) - -/obj/structure/flora/proc/burn_up() - new /obj/effect/decal/cleanable/dirt(loc) - if(center) - new /obj/effect/decal/cleanable/dirt(loc) //Produces more ash at the center - qdel(src) - -/obj/structure/flora/ex_act(power) - if(power >= EXPLOSION_THRESHOLD_VLOW) - deconstruct(FALSE) - // MAP VARIANTS // // PARENT FOR COLOR, CORNERS AND CENTERS, BASED ON DIRECTIONS // @@ -391,7 +521,50 @@ ICE GRASS icon = 'icons/obj/structures/props/plants.dmi' icon_state = "pottedplant_26" density = FALSE + var/stashed_item + var/static/possible_starting_items = list(/obj/item/clothing/mask/cigarette/weed, /obj/item/clothing/mask/cigarette, /obj/item/clothing/mask/cigarette/bcigarette) //breaking bad reference + /// For things that might affect someone/everyone's round if hidden. + var/static/blocked_atoms = list(/obj/item/device/cotablet, /obj/item/card/id) + var/static/blacklist_typecache + +/obj/structure/flora/pottedplant/Initialize(mapload) + . = ..() + + if(!blacklist_typecache) + blacklist_typecache = typecacheof(blocked_atoms) + if(prob(5)) + var/prestashed_item = pick(possible_starting_items) + stashed_item = new prestashed_item(src) + +/obj/structure/flora/pottedplant/attackby(obj/item/stash, mob/user) + if(stashed_item) + to_chat(user, SPAN_WARNING("There's already something stashed here!")) + return + + if(is_type_in_typecache(stash, blacklist_typecache)) + to_chat(user, SPAN_WARNING("You probably shouldn't hide [stash] in [src].")) + return + + if(stash.w_class == SIZE_TINY) + user.drop_inv_item_to_loc(stash, src) + stashed_item = stash + user.visible_message("[user] puts something in [src].", "You hide [stash] in [src].") + return + + to_chat(user, SPAN_WARNING("[stash] is too big to fit into [src]!")) + +/obj/structure/flora/pottedplant/attack_hand(mob/user) + if(!stashed_item) + return + user.put_in_hands(contents[1]) + user.visible_message( "[user] takes something out of [src].", "You take [stashed_item] from [src].") + stashed_item = null + +/obj/structure/flora/pottedplant/Destroy() + if(stashed_item) + QDEL_NULL(stashed_item) + return ..() /obj/structure/flora/pottedplant/random icon_tag = "pottedplant" variations = "30" @@ -412,7 +585,6 @@ ICE GRASS layer = ABOVE_XENO_LAYER projectile_coverage = PROJECTILE_COVERAGE_NONE - /obj/structure/flora/jungle/shrub desc = "Pretty thick scrub, it'll take something sharp and a lot of determination to clear away." icon_state = "grass4" @@ -422,6 +594,21 @@ ICE GRASS desc = "Some kind of bizarre alien tree. It oozes with a sickly yellow sap." icon_state = "plantbot1" +/obj/structure/flora/jungle/cart_wreck + name = "old janicart" + desc = "Doesn't look like it'll do much cleaning any more." + icon_state = "cart_wreck" + +/obj/structure/flora/jungle/alienplant1 + name = "strange tree" + desc = "Some kind of bizarre alien tree. It oozes with a sickly yellow sap." + icon_state = "alienplant1" + luminosity = 2 + +/obj/structure/flora/jungle/alienplant1/Destroy() + SetLuminosity(0) + return ..() + /obj/structure/flora/jungle/planttop1 name = "strange tree" desc = "Some kind of bizarre alien tree. It oozes with a sickly yellow sap." @@ -433,6 +620,7 @@ ICE GRASS icon_state = "" //will this break it?? - Nope density = TRUE +//light vines /obj/structure/flora/jungle/vines name = "vines" desc = "A mass of twisted vines." @@ -443,6 +631,19 @@ ICE GRASS cut_level = PLANT_CUT_MACHETE fire_flag = FLORA_BURN_NO_SPREAD +/obj/structure/flora/jungle/vines/light_1 + icon_state = "light_1" + icon_tag = "light_1" + +/obj/structure/flora/jungle/vines/light_2 + icon_state = "light_2" + icon_tag = "light_2" + +/obj/structure/flora/jungle/vines/light_3 + icon_state = "light_3" + icon_tag = "light_3" + +//heavy hide you /obj/structure/flora/jungle/vines/heavy desc = "A thick, coiled mass of twisted vines." opacity = TRUE diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 4907d18340dc..d014ebfe3b94 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -235,7 +235,7 @@ to_chat(user, SPAN_NOTICE("You are attaching the metal to the internal structure.")) if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_NO_NEEDHAND|BEHAVIOR_IMMOBILE, BUSY_ICON_FRIENDLY, src)) return TRUE - to_chat(user, SPAN_NOTICE("You are attached the metal to the internal structure!")) + to_chat(user, SPAN_NOTICE("You have attached the metal to the internal structure!")) step_state = STATE_SCREWDRIVER return TRUE @@ -285,7 +285,7 @@ to_chat(user, SPAN_NOTICE("You are attaching the plasteel to the internal structure.")) if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_NO_NEEDHAND|BEHAVIOR_IMMOBILE, BUSY_ICON_FRIENDLY, src)) return TRUE - to_chat(user, SPAN_NOTICE("You are attached the plasteel to the internal structure!")) + to_chat(user, SPAN_NOTICE("You have attached the plasteel to the internal structure!")) step_state = STATE_SCREWDRIVER return TRUE diff --git a/code/game/objects/structures/ice_caves.dm b/code/game/objects/structures/ice_caves.dm index 53fa8a6a40ce..1c89d27f608e 100644 --- a/code/game/objects/structures/ice_caves.dm +++ b/code/game/objects/structures/ice_caves.dm @@ -35,11 +35,28 @@ icon_state = "Intersection" -//Ice Secret Wall -/obj/structure/ice/secret - icon_state = "ice_wall_0" +//Thin Ice Secret Wall +/turf/closed/ice/thin/secret desc = "There is something inside..." +/turf/closed/ice/thin/secret/single + icon_state = "Single" + +/turf/closed/ice/thin/secret/end + icon_state = "End" + +/turf/closed/ice/thin/secret/straight + icon_state = "Straight" + +/turf/closed/ice/thin/secret/corner + icon_state = "Corner" + +/turf/closed/ice/thin/secret/junction + icon_state = "T-Junction" + +/turf/closed/ice/thin/secret/intersection + icon_state = "Intersection" + //ROCK WALLS------------------------------// /obj/structure/ice/ice_rock name = "Icy rock" diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm index 39411f9e6fe3..f2e6b172ad88 100644 --- a/code/game/objects/structures/ladders.dm +++ b/code/game/objects/structures/ladders.dm @@ -209,7 +209,7 @@ if(G.antigrief_protection && user.faction == FACTION_MARINE && explosive_antigrief_check(G, user)) to_chat(user, SPAN_WARNING("\The [G.name]'s safe-area accident inhibitor prevents you from priming the grenade!")) // Let staff know, in case someone's actually about to try to grief - msg_admin_niche("[key_name(user)] attempted to prime \a [G.name] in [get_area(src)] (JMP)") + msg_admin_niche("[key_name(user)] attempted to prime \a [G.name] in [get_area(src)] [ADMIN_JMP(src.loc)]") return user.visible_message(SPAN_WARNING("[user] takes position to throw [G] [ladder_dir_name] [src]."), @@ -265,7 +265,7 @@ GLOB.hijack_bustable_ladders += src /obj/structure/ladder/fragile_almayer/Destroy() - GLOB.hijack_bustable_windows -= src + GLOB.hijack_bustable_ladders -= src return ..() /obj/structure/ladder/fragile_almayer/deconstruct() diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 5b18908b37a8..5660f342f90b 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -8,7 +8,6 @@ anchored = TRUE var/shattered = 0 - /obj/structure/mirror/attack_hand(mob/user as mob) if(shattered) return @@ -17,14 +16,19 @@ var/mob/living/carbon/human/H = user if(H.a_intent == INTENT_HARM) + var/obj/limb/hand_target = H.get_limb(H.hand ? "l_hand" : "r_hand") if(shattered) playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 25, 1) + user.visible_message(SPAN_DANGER("[user] punches [src], but it's already broken!"), SPAN_DANGER("You punch [src], but it's already broken!")) + hand_target.take_damage(5) return if(prob(30) || H.species.can_shred(H)) - user.visible_message(SPAN_DANGER("[user] smashes [src]!")) - shatter() + user.visible_message(SPAN_DANGER("[user] punches [src], smashing it!"), SPAN_DANGER("You punch [src], smashing it!")) + shatter(user) else - user.visible_message(SPAN_DANGER("[user] hits [src] and bounces off!")) + user.visible_message(SPAN_DANGER("[user] punches [src] and bounces off!"), SPAN_DANGER("You punch [src] and bounce off!")) + hand_target.take_damage(5) + playsound(loc, 'sound/effects/glassbash.ogg', 25, 1) return var/userloc = H.loc @@ -68,12 +72,21 @@ H.update_hair() -/obj/structure/mirror/proc/shatter() - if(shattered) return - shattered = 1 +/obj/structure/mirror/proc/shatter(mob/living/carbon/human/user, grabbed = FALSE) + shattered = TRUE icon_state = "mirror_broke" playsound(src, "shatter", 70, 1) desc = "Oh no, seven years of bad luck!" + var/obj/item/shard/mirror_shard = new(loc) + if(!user) + return + var/obj/limb/shard_target + if(grabbed) + shard_target = user.get_limb("head") + else + shard_target = user.get_limb(user.hand ? "l_hand" : "r_hand") + shard_target.embed(mirror_shard) + shard_target.take_damage(15) /obj/structure/mirror/bullet_act(obj/item/projectile/Proj) @@ -87,15 +100,35 @@ /obj/structure/mirror/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/grab)) + if(user.grab_level < GRAB_AGGRESSIVE) + to_chat(user, SPAN_WARNING("You need a better grip to do that!")) + return + var/obj/item/grab/target_grab = I + var/mob/living/carbon/human/target = target_grab.grabbed_thing + var/obj/limb/head_target = target.get_limb("head") + if(shattered) + user.visible_message(SPAN_WARNING("[user] smashes [src] with [target]'s skull, but [src] is already broken!"), SPAN_WARNING("You smash [src] with [target]'s skull, but [src] is already broken!")) + head_target.take_damage(5) + playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 25, 1) + return + if(prob(30)) + user.visible_message(SPAN_WARNING("[user] smashes [src] with [target]'s skull, breaking [src]!"), SPAN_WARNING("You smash [src] with [target]'s skull, breaking [src]!")) + shatter(target, TRUE) + return + user.visible_message(SPAN_WARNING("[user] smashes [src] with [target]'s skull!"), SPAN_WARNING("You smash [src] with [target]'s skull!")) + head_target.take_damage(5) + playsound(loc, 'sound/effects/Glasshit.ogg', 25, 1) + return if(shattered) playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 25, 1) + user.visible_message(SPAN_WARNING("[user] hits [src] with [I], but it's already broken!"), SPAN_WARNING("You hit [src] with [I], but it's already broken!")) return - if(prob(I.force * 2)) - visible_message(SPAN_WARNING("[user] smashes [src] with [I]!")) + user.visible_message(SPAN_WARNING("[user] smashes [src] with [I]!"), SPAN_WARNING("You smash [src] with [I]!")) shatter() else - visible_message(SPAN_WARNING("[user] hits [src] with [I]!")) + user.visible_message(SPAN_WARNING("[user] hits [src] with [I]!"), SPAN_WARNING("You hit [src] with [I]!")) playsound(src.loc, 'sound/effects/Glasshit.ogg', 25, 1) /obj/structure/mirror/attack_animal(mob/user as mob) diff --git a/code/game/objects/structures/misc.dm b/code/game/objects/structures/misc.dm index 60f29c8b40e4..9323bca2877e 100644 --- a/code/game/objects/structures/misc.dm +++ b/code/game/objects/structures/misc.dm @@ -143,7 +143,7 @@ unslashable = TRUE unacidable = TRUE health = null - layer = TURF_LAYER + layer = ABOVE_TURF_LAYER//Being on turf layer was causing issues with cameras. This SHOULDN'T cause any problems. plane = FLOOR_PLANE density = FALSE opacity = FALSE diff --git a/code/game/objects/structures/pipes/pipes.dm b/code/game/objects/structures/pipes/pipes.dm index e9eda4c97ea2..ee18356a5d14 100644 --- a/code/game/objects/structures/pipes/pipes.dm +++ b/code/game/objects/structures/pipes/pipes.dm @@ -14,6 +14,8 @@ var/ventcrawl_message_busy = FALSE //Prevent spamming + /// Whether or not the pipe will explode (when on the Almayer) during hijack + var/explodey = TRUE /// The grenade subtypes that pipes will use when they explode var/static/list/exploding_types = list(/obj/item/explosive/grenade/high_explosive/bursting_pipe, /obj/item/explosive/grenade/incendiary/bursting_pipe) @@ -40,7 +42,8 @@ if(!is_mainship_level(z)) return - GLOB.mainship_pipes += src + if(explodey) + GLOB.mainship_pipes += src if(!HAS_TRAIT(SSround, TRAIT_ROUND_FAULTY_PIPING)) return diff --git a/code/game/objects/structures/pipes/standard/manifolds.dm b/code/game/objects/structures/pipes/standard/manifolds.dm index f7bd04ee3fb7..dfbc027455b6 100644 --- a/code/game/objects/structures/pipes/standard/manifolds.dm +++ b/code/game/objects/structures/pipes/standard/manifolds.dm @@ -104,6 +104,10 @@ layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE +/obj/structure/pipes/standard/manifold/hidden/supply/no_boom + name = "Reinforced Air supply pipe manifold" + explodey = FALSE + /obj/structure/pipes/standard/manifold/hidden/yellow color = PIPE_COLOR_YELLOW @@ -182,6 +186,10 @@ layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE +/obj/structure/pipes/standard/manifold/fourway/hidden/supply/no_boom + name = "reinforced 4-way air supply pipe manifold" + explodey = FALSE + /obj/structure/pipes/standard/manifold/fourway/hidden/yellow color = PIPE_COLOR_YELLOW diff --git a/code/game/objects/structures/pipes/standard/simple.dm b/code/game/objects/structures/pipes/standard/simple.dm index 7101bb3dd95f..93a92e51f71b 100644 --- a/code/game/objects/structures/pipes/standard/simple.dm +++ b/code/game/objects/structures/pipes/standard/simple.dm @@ -104,6 +104,10 @@ layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE +/obj/structure/pipes/standard/simple/hidden/supply/no_boom + name = "Reinforced Air supply pipe" + explodey = FALSE + /obj/structure/pipes/standard/simple/hidden/yellow color = PIPE_COLOR_YELLOW diff --git a/code/game/objects/structures/pipes/standard/standard_misc.dm b/code/game/objects/structures/pipes/standard/standard_misc.dm index dc29e2aae894..dc52da57c750 100644 --- a/code/game/objects/structures/pipes/standard/standard_misc.dm +++ b/code/game/objects/structures/pipes/standard/standard_misc.dm @@ -47,8 +47,8 @@ /obj/structure/pipes/standard/cap name = "pipe endcap" - desc = "An endcap for pipes" - icon = 'icons/obj/pipes/pipes.dmi' + desc = "An endcap for pipes." + icon = 'icons/obj/pipes/pipes3.dmi' icon_state = "" level = 2 dir = SOUTH @@ -72,14 +72,14 @@ /obj/structure/pipes/standard/cap/visible/scrubbers name = "scrubbers pipe endcap" - desc = "An endcap for scrubbers pipes" + desc = "An endcap for scrubbers pipes." icon_state = "cap-scrubbers" layer = ATMOS_PIPE_SCRUBBER_LAYER color = PIPE_COLOR_RED /obj/structure/pipes/standard/cap/visible/supply name = "supply pipe endcap" - desc = "An endcap for supply pipes" + desc = "An endcap for supply pipes." icon_state = "cap-supply" layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE @@ -95,18 +95,22 @@ /obj/structure/pipes/standard/cap/hidden/scrubbers name = "scrubbers pipe endcap" - desc = "An endcap for scrubbers pipes" + desc = "An endcap for scrubbers pipes." icon_state = "cap-f-scrubbers" layer = ATMOS_PIPE_SCRUBBER_LAYER color = PIPE_COLOR_RED /obj/structure/pipes/standard/cap/hidden/supply name = "supply pipe endcap" - desc = "An endcap for supply pipes" + desc = "An endcap for supply pipes." icon_state = "cap-f-supply" layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE +/obj/structure/pipes/standard/cap/hidden/supply/no_boom + name = "reinforced supply pipe endcap" + explodey = FALSE + /obj/structure/pipes/standard/tank icon = 'icons/obj/pipes/tank.dmi' diff --git a/code/game/objects/structures/pipes/vents/pump_scrubber.dm b/code/game/objects/structures/pipes/vents/pump_scrubber.dm index d0dd3f8301a7..a4565c610ad5 100644 --- a/code/game/objects/structures/pipes/vents/pump_scrubber.dm +++ b/code/game/objects/structures/pipes/vents/pump_scrubber.dm @@ -4,6 +4,10 @@ name = "Air Scrubber" vent_icon = "scrubber" +/obj/structure/pipes/vents/scrubber/no_boom + name = "Reinforced Air Scrubber" + explodey = FALSE + /obj/structure/pipes/vents/scrubber/on icon_state = "on" @@ -13,6 +17,10 @@ icon_state = "map_vent" name = "Air Vent" +/obj/structure/pipes/vents/pump/no_boom + name = "Reinforced Air Vent" + explodey = FALSE + /obj/structure/pipes/vents/pump/on icon_state = "on" diff --git a/code/game/objects/structures/pipes/vents/vents.dm b/code/game/objects/structures/pipes/vents/vents.dm index fa3395d9e91d..2b3d5409dc8a 100644 --- a/code/game/objects/structures/pipes/vents/vents.dm +++ b/code/game/objects/structures/pipes/vents/vents.dm @@ -12,6 +12,7 @@ var/uid var/vent_icon = "vent" + var/datum/effect_system/smoke_spread/gas_holder /obj/structure/pipes/vents/Initialize() . = ..() @@ -123,7 +124,35 @@ qdel(src) /obj/structure/pipes/vents/Destroy() + qdel(gas_holder) if(initial_loc) initial_loc.air_vent_info -= id_tag initial_loc.air_vent_names -= id_tag . = ..() + +/obj/structure/pipes/vents/proc/create_gas(gas_type = VENT_GAS_SMOKE, radius = 4, warning_time = 5 SECONDS) + if(welded) + to_chat(usr, SPAN_WARNING("You cannot release gas from a welded vent.")) + return FALSE + var/datum/effect_system/smoke_spread/spreader + switch(gas_type) + if(VENT_GAS_SMOKE) + spreader = new /datum/effect_system/smoke_spread/bad + if(VENT_GAS_CN20) + spreader = new /datum/effect_system/smoke_spread/cn20 + if(!spreader) + return FALSE + gas_holder = spreader + spreader.attach(src) + + new /obj/effect/warning/explosive/gas(loc, warning_time) + visible_message(SPAN_HIGHDANGER("[src] begins to hiss as gas builds up within it."), SPAN_HIGHDANGER("You hear a hissing."), radius) + addtimer(CALLBACK(src, PROC_REF(release_gas), radius), warning_time) + +/obj/structure/pipes/vents/proc/release_gas(radius = 4) + radius = Clamp(radius, 1, 10) + if(!gas_holder || welded) + return FALSE + playsound(loc, 'sound/effects/smoke.ogg', 25, 1, 4) + gas_holder.set_up(radius, 0, get_turf(src), null, 10 SECONDS) + gas_holder.start() diff --git a/code/game/objects/structures/platforms.dm b/code/game/objects/structures/platforms.dm index 283febd8b1b5..cfffbc90fb7c 100644 --- a/code/game/objects/structures/platforms.dm +++ b/code/game/objects/structures/platforms.dm @@ -158,10 +158,6 @@ /obj/structure/platform/kutjevo/smooth/stair_plate icon_state = "kutjevo_stair_plate" -/obj/structure/platform/kutjevo/smooth/stair_cut - icon_state = "kutjevo_stair_cm_stair" - - /obj/structure/platform_decoration/kutjevo/smooth name = "raised metal corner" desc = "The corner of what appears to be raised piece of metal, often used to imply the illusion of elevation in non-Euclidean 2d spaces. But you don't know that, you're just a spaceman with a rifle." diff --git a/code/game/objects/structures/props.dm b/code/game/objects/structures/props.dm index a79fab9d5d6e..66598d602691 100644 --- a/code/game/objects/structures/props.dm +++ b/code/game/objects/structures/props.dm @@ -24,7 +24,7 @@ . = ..() if(isxeno(user)) return - else if (ishuman(user) && istype(W, /obj/item/tool/wrench)) + else if (ishuman(user) && HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) on = !on visible_message("You wrench the controls of \the [src]. The drill jumps to life." , "[user] wrenches the controls of \the [src]. The drill jumps to life.") @@ -265,7 +265,6 @@ /obj/structure/prop/mech/mech_parts name = "mecha part" - icon_state = "blank" flags_atom = FPRINT|CONDUCT /obj/structure/prop/mech/mech_parts/chassis @@ -303,7 +302,7 @@ /obj/structure/prop/mech/mech_parts/chassis/gygax name = "Gygax Chassis" - icon_state = "gygas_chassis" + icon_state = "gygax_chassis" /obj/structure/prop/mech/mech_parts/part/gygax_torso name="Gygax Torso" @@ -333,13 +332,13 @@ name="Gygax Right Leg" icon_state = "gygax_r_leg" -/obj/structure/prop/mech/mech_parts/part/gygax_armour - name="Gygax Armour Plates" - icon_state = "gygax_armour" +/obj/structure/prop/mech/mech_parts/part/gygax_armor + name="Gygax Armor Plates" + icon_state = "gygax_armor" /obj/structure/prop/mech/mech_parts/chassis/durand name = "Durand Chassis" - icon_state = "gygas_chassis" + icon_state = "durand_chassis" /obj/structure/prop/mech/mech_parts/part/durand_torso name="Durand Torso" @@ -365,9 +364,9 @@ name="Durand Right Leg" icon_state = "durand_r_leg" -/obj/structure/prop/mech/mech_parts/part/durand_armour - name="Durand Armour Plates" - icon_state = "durand_armour" +/obj/structure/prop/mech/mech_parts/part/durand_armor + name="Durand Armor Plates" + icon_state = "durand_armor" /obj/structure/prop/mech/mech_parts/chassis/firefighter name = "Firefighter Chassis" @@ -375,6 +374,7 @@ /obj/structure/prop/mech/mech_parts/chassis/phazon name = "Phazon Chassis" + icon_state = "phazon_chassis" /obj/structure/prop/mech/mech_parts/part/phazon_torso name="Phazon Torso" @@ -400,9 +400,13 @@ name="Phazon Right Leg" icon_state = "phazon_r_leg" +/obj/structure/prop/mech/mech_parts/part/phazon_armor_plates + name="Phazon Armor Plates" + icon_state = "phazon_armor" + /obj/structure/prop/mech/mech_parts/chassis/odysseus name = "Odysseus Chassis" - icon_state = "gygas_chassis" + icon_state = "odysseus_chassis" /obj/structure/prop/mech/mech_parts/part/odysseus_head name="Odysseus Head" @@ -433,6 +437,10 @@ desc="A Odysseus right leg. Contains somewhat complex servodrives and balance maintaining systems." icon_state = "odysseus_r_leg" +/obj/structure/prop/mech/mech_parts/part/odysseus_armor_plates + name="Odysseus Armor Plates" + icon_state = "odysseus_armor" + //Use these to replace non-functional machinery 'props' around maps from bay12 /obj/structure/prop/server_equipment @@ -493,7 +501,7 @@ . = ..() if(isxeno(user)) return - else if (ishuman(user) && istype(W, /obj/item/tool/crowbar)) + else if (ishuman(user) && HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) on = !on visible_message("You pry at the control valve on [src]. The machine shudders." , "[user] pries at the control valve on [src]. The entire machine shudders.") @@ -566,7 +574,7 @@ icon_state = "cash_register_broken_open" /obj/structure/prop/cash_register/off - icon_state = "cash_registern_off" + icon_state = "cash_register_off" /obj/structure/prop/cash_register/off/open icon_state = "cash_register_off_open" @@ -611,9 +619,11 @@ name = "non-functional hatch" desc = "You'll need more than a prybar for this one." icon = 'icons/obj/structures/machinery/bolt_target.dmi' + icon_state = "closed" /obj/structure/prop/invuln/lifeboat_hatch_placeholder/terminal icon = 'icons/obj/structures/machinery/bolt_terminal.dmi' + icon_state = "closed" /obj/structure/prop/invuln/dropship_parts //for TG shuttle system density = TRUE @@ -626,8 +636,12 @@ /obj/structure/prop/invuln/dropship_parts/lifeboat name = "Lifeboat" + icon_state = "" icon = 'icons/turf/lifeboat.dmi' +#define STATE_COMPLETE 0 +#define STATE_FUEL 1 +#define STATE_IGNITE 2 /obj/structure/prop/brazier name = "brazier" @@ -637,6 +651,44 @@ density = TRUE health = 150 luminosity = 6 + /// What obj this becomes when it gets to its next stage of construction / ignition + var/frame_type + /// What is used to progress to the next stage + var/state = STATE_COMPLETE + +/obj/structure/prop/brazier/get_examine_text(mob/user) + . = ..() + switch(state) + if(STATE_FUEL) + . += "[src] requires wood to be fueled." + if(STATE_IGNITE) + . += "[src] needs to be lit." + +/obj/structure/prop/brazier/attackby(obj/item/hit_item, mob/user) + switch(state) + if(STATE_COMPLETE) + return ..() + if(STATE_FUEL) + if(!istype(hit_item, /obj/item/stack/sheet/wood)) + return ..() + var/obj/item/stack/sheet/wood/wooden_boards = hit_item + if(!wooden_boards.use(5)) + to_chat(user, SPAN_WARNING("Not enough wood!")) + return + user.visible_message(SPAN_NOTICE("[user] fills [src] with [hit_item].")) + if(STATE_IGNITE) + if(!hit_item.heat_source) + return ..() + if(!do_after(user, 3 SECONDS, INTERRUPT_MOVED, BUSY_ICON_BUILD)) + return + user.visible_message(SPAN_NOTICE("[user] ignites [src] with [hit_item].")) + + new frame_type(loc) + qdel(src) + +/obj/structure/prop/brazier/Destroy() + SetLuminosity(0) + return ..() /obj/structure/prop/brazier/Initialize() . = ..() @@ -648,31 +700,15 @@ desc = "An empty brazier." icon_state = "brazier_frame" luminosity = 0 + frame_type = /obj/structure/prop/brazier/frame/full + state = STATE_FUEL -/obj/structure/prop/brazier/frame/attackby(obj/item/hit_item, mob/user) - if(!istype(hit_item, /obj/item/stack/sheet/wood)) - return ..() - var/obj/item/stack/wooden_boards = hit_item - if(wooden_boards.amount < 5) - to_chat(user, SPAN_WARNING("Not enough wood!")) - return - wooden_boards.use(5) - user.visible_message(SPAN_NOTICE("[user] fills the brazier with wood.")) - new /obj/structure/prop/brazier/frame_woodened(loc) - qdel(src) - -/obj/structure/prop/brazier/frame_woodened +/obj/structure/prop/brazier/frame/full name = "empty full brazier" desc = "An empty brazier. Yet it's also full. What??? Use something hot to ignite it, like a welding tool." icon_state = "brazier_frame_filled" - luminosity = 0 - -/obj/structure/prop/brazier/frame_woodened/attackby(obj/item/hit_item, mob/user) - if(!hit_item.heat_source) - return ..() - user.visible_message(SPAN_NOTICE("[user] ignites the brazier with [hit_item].")) - new /obj/structure/prop/brazier(loc) - qdel(src) + frame_type = /obj/structure/prop/brazier + state = STATE_IGNITE /obj/structure/prop/brazier/torch name = "torch" @@ -681,25 +717,136 @@ density = FALSE luminosity = 5 -/obj/structure/prop/brazier/torch/frame +/obj/structure/prop/brazier/frame/full/torch name = "unlit torch" desc = "It's a torch, but it's not lit. Use something hot to ignite it, like a welding tool." icon_state = "torch_frame" - luminosity = 0 - -/obj/structure/prop/brazier/torch/frame/attackby(obj/item/hit_item, mob/user) - if(!hit_item.heat_source) - return ..() - user.visible_message(SPAN_NOTICE("[user] ignites the torch with [hit_item].")) - new /obj/structure/prop/brazier/torch(loc) - qdel(src) + frame_type = /obj/structure/prop/brazier/torch /obj/item/prop/torch_frame name = "unlit torch" icon = 'icons/obj/structures/structures.dmi' desc = "It's a torch, but it's not lit or placed down. Click on a wall to place it." icon_state = "torch_frame" - luminosity = 0 + +/obj/structure/prop/brazier/frame/full/campfire + name = "unlit campfire" + desc = "A circle of stones surrounding a pile of wood. If only you were to light it." + icon_state = "campfire" + frame_type = /obj/structure/prop/brazier/campfire + density = FALSE + +/obj/structure/prop/brazier/frame/full/campfire/smolder + name = "smoldering campfire" + desc = "A campfire that used to be lit, but was extinguished. You can still see the embers, and smoke rises from it." + state = STATE_FUEL + frame_type = /obj/structure/prop/brazier/frame/full/campfire + +/obj/structure/prop/brazier/campfire + name = "campfire" + desc = "A circle of stones surrounding a burning pile of wood. The fire is roaring and you can hear its crackle. You could probably stomp the fire out." + icon = 'icons/obj/structures/structures.dmi' + icon_state = "campfire_on" + density = FALSE + ///How many tiles the heating and sound goes + var/heating_range = 2 + /// time between sounds + var/time_to_sound = 20 + /// Time for it to burn through fuel + var/fuel_stage_time = 1 MINUTES + /// How much fuel it has + var/remaining_fuel = 5 //Maxes at 5, but burns one when made + /// If the fire can be manually put out + var/extinguishable = TRUE + /// Make no noise + var/quiet = FALSE + +/obj/structure/prop/brazier/campfire/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + fuel_drain(TRUE) + +/obj/structure/prop/brazier/campfire/get_examine_text(mob/user) + . = ..() + switch(remaining_fuel) + if(4 to INFINITY) + . += "The fire is roaring." + if(2 to 3) + . += "The fire is burning warm." + if(-INFINITY to 1) + . += "The embers of the fire barely burns." + +/obj/structure/prop/brazier/campfire/process(delta_time) + if(!isturf(loc)) + return + + for(var/mob/living/carbon/human/mob in range(heating_range, src)) + if(mob.bodytemperature < T20C) + mob.bodytemperature += min(round(T20C - mob.bodytemperature)*0.7, 25) + mob.recalculate_move_delay = TRUE + + if(quiet) + return + time_to_sound -= delta_time + if(time_to_sound <= 0) + playsound(loc, 'sound/machines/firepit_ambience.ogg', 15, FALSE, heating_range) + time_to_sound = initial(time_to_sound) + +/obj/structure/prop/brazier/campfire/attack_hand(mob/user) + . = ..() + if(!extinguishable) + to_chat(user, SPAN_WARNING("You cannot extinguish [src].")) + return + to_chat(user, SPAN_NOTICE("You begin to extinguish [src].")) + while(remaining_fuel) + if(user.action_busy || !do_after(user, 3 SECONDS, INTERRUPT_MOVED, BUSY_ICON_BUILD)) + return + fuel_drain() + to_chat(user, SPAN_NOTICE("You continue to extinguish [src].")) + visible_message(SPAN_NOTICE("[user] extinguishes [src].")) + +/obj/structure/prop/brazier/campfire/attackby(obj/item/attacking_item, mob/user) + if(!istype(attacking_item, /obj/item/stack/sheet/wood)) + to_chat(SPAN_NOTICE("You cannot fuel [src] with [attacking_item].")) + return + var/obj/item/stack/sheet/wood/fuel = attacking_item + if(remaining_fuel >= initial(remaining_fuel)) + to_chat(user, SPAN_NOTICE("You cannot fuel [src] further.")) + if(!fuel.use(1)) + to_chat(SPAN_NOTICE("You do not have enough [attacking_item] to fuel [src].")) + visible_message(SPAN_NOTICE("[user] fuels [src] with [fuel].")) + remaining_fuel++ + +/obj/structure/prop/brazier/campfire/attack_alien(mob/living/carbon/xenomorph/xeno) + if(!extinguishable) + to_chat(xeno, SPAN_WARNING("You cannot extinguish [src].")) + return + to_chat(xeno, SPAN_NOTICE("You begin to extinguish [src].")) + while(remaining_fuel) + if(xeno.action_busy || !do_after(xeno, 1 SECONDS, INTERRUPT_MOVED, BUSY_ICON_HOSTILE)) + return + fuel_drain() + to_chat(xeno, SPAN_NOTICE("You continue to extinguish [src].")) + visible_message(SPAN_WARNING("[xeno] extinguishes [src]!")) + +/obj/structure/prop/brazier/campfire/proc/fuel_drain(looping) + remaining_fuel-- + if(!remaining_fuel) + new /obj/structure/prop/brazier/frame/full/campfire/smolder(loc) + qdel(src) + return + if(!looping || !fuel_stage_time) + return + addtimer(CALLBACK(src, PROC_REF(fuel_drain), TRUE), fuel_stage_time) + +/obj/structure/prop/brazier/campfire/Destroy() + SetLuminosity(0) + STOP_PROCESSING(SSobj, src) + return ..() + +#undef STATE_COMPLETE +#undef STATE_FUEL +#undef STATE_IGNITE //ICE COLONY PROPS //Thematically look to Blackmesa's Xen levels. Generic science-y props n' stuff. @@ -726,7 +873,7 @@ icon_state = "small_wire" /obj/structure/prop/ice_colony/poly_kevlon_roll - name = "poly_kevlon roll" + name = "plastic roll" desc = "A big roll of poly-kevlon plastic used in temporary shelter construction." icon_state = "kevlon_roll" anchored = FALSE @@ -823,8 +970,8 @@ icon_state = "van" bound_height = 64 bound_width = 64 - unslashable = TRUE - unacidable = TRUE + unslashable = FALSE + unacidable = FALSE /obj/structure/prop/vehicles/crawler name = "colony crawler" @@ -869,13 +1016,6 @@ icon_state = "arcadeb" name = "Spirit Phone, The Game, The Movie: II" -/obj/structure/prop/maintenance_hatch - name = "\improper Maintenance Hatch" - icon = 'icons/obj/structures/structures.dmi' - icon_state = "hatchclosed" - desc = "Looks like it's rusted shut. Creepy." - layer = HATCH_LAYER - //INVULNERABLE PROPS /obj/structure/prop/invuln @@ -1130,3 +1270,99 @@ /obj/structure/prop/wooden_cross/update_icon() if(tagged) overlays += mutable_appearance('icons/obj/structures/props/crosses.dmi', "cross_overlay") + + +/obj/structure/prop/invuln/rope + name = "rope" + desc = "A secure rope looks like someone might've been hiding out on those rocks." + icon = 'icons/obj/structures/props/almayer_props.dmi' + icon_state = "rope" + density = FALSE + +/obj/structure/prop/pred_flight + name = "hunter flight console" + desc = "A console designed by the Hunters to assist in flight pathing and navigation." + icon = 'icons/obj/structures/machinery/computer.dmi' + icon_state = "overwatch" + density = TRUE + +/obj/structure/prop/invuln/joey + name = "Workin' Joey" + desc = "A defunct Seegson-brand Working Joe lifted from deep storage by a crew of marines after the last shore leave. Attempts have been made to modify the janitorial synthetic to serve as a crude bartender, but with little success." + icon = 'icons/obj/structures/props/props.dmi' + icon_state = "joey" + unslashable = FALSE + wrenchable = FALSE + /// converted into minutes when used to determine cooldown timer between quips + var/quip_delay_minimum = 5 + /// delay between Quips. Slightly randomized with quip_delay_minimum plus a random number + COOLDOWN_DECLARE(quip_delay) + /// delay between attack voicelines. Short but done for anti-spam + COOLDOWN_DECLARE(damage_delay) + /// list of quip emotes, taken from Working Joe + var/static/list/quips = list( + /datum/emote/living/carbon/human/synthetic/working_joe/quip/alwaysknow_damaged, + /datum/emote/living/carbon/human/synthetic/working_joe/quip/not_liking, + /datum/emote/living/carbon/human/synthetic/working_joe/greeting/how_can_i_help, + /datum/emote/living/carbon/human/synthetic/working_joe/task_update/day_never_done, + /datum/emote/living/carbon/human/synthetic/working_joe/task_update/required_by_apollo, + /datum/emote/living/carbon/human/synthetic/working_joe/warning/safety_breach + ) + /// list of voicelines to use when damaged + var/static/list/damaged = list( + /datum/emote/living/carbon/human/synthetic/working_joe/warning/damage, + /datum/emote/living/carbon/human/synthetic/working_joe/warning/that_stings, + /datum/emote/living/carbon/human/synthetic/working_joe/warning/irresponsible, + /datum/emote/living/carbon/human/synthetic/working_joe/warning/this_is_futile, + /datum/emote/living/carbon/human/synthetic/working_joe/warning/hysterical, + /datum/emote/living/carbon/human/synthetic/working_joe/warning/patience + ) + +/obj/structure/prop/invuln/joey/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/structure/prop/invuln/joey/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/structure/prop/invuln/joey/process() + //check if quip_delay cooldown finished. If so, random chance it says a line + if(COOLDOWN_FINISHED(src, quip_delay) && prob(10)) + emote(pick(quips)) + var/delay = rand(3) + quip_delay_minimum + COOLDOWN_START(src, quip_delay, delay MINUTES) + +// Advert your eyes. +/obj/structure/prop/invuln/joey/attackby(obj/item/W, mob/user) + attacked() + return ..() + +/obj/structure/prop/invuln/joey/bullet_act(obj/item/projectile/P) + attacked() + return ..() + +/// A terrible way of handling being hit. If signals would work it should be used. +/obj/structure/prop/invuln/joey/proc/attacked() + if(COOLDOWN_FINISHED(src, damage_delay) && prob(25)) + emote(pick(damaged)) + COOLDOWN_START(src, damage_delay, 8 SECONDS) + +/// SAY THE LINE JOE +/obj/structure/prop/invuln/joey/proc/emote(datum/emote/living/carbon/human/synthetic/working_joe/emote) + if (!emote) + return FALSE + + for(var/mob/mob in hearers(src, null)) + mob.show_message("[src] says, \"[initial(emote.say_message)]\"", SHOW_MESSAGE_AUDIBLE) + + var/list/viewers = get_mobs_in_view(7, src) + for(var/mob/current_mob in viewers) + if(!(current_mob.client?.prefs.toggles_langchat & LANGCHAT_SEE_EMOTES)) + viewers -= current_mob + langchat_speech(initial(emote.say_message), viewers, GLOB.all_languages, skip_language_check = TRUE) + + if(initial(emote.sound)) + playsound(loc, initial(emote.sound), 50, FALSE) + return TRUE + diff --git a/code/game/objects/structures/reagent_dispensers.dm b/code/game/objects/structures/reagent_dispensers.dm index 32e5f040ece0..f20a7cfc25d6 100644 --- a/code/game/objects/structures/reagent_dispensers.dm +++ b/code/game/objects/structures/reagent_dispensers.dm @@ -38,6 +38,11 @@ . += SPAN_NOTICE(" Nothing.") if(reagents) . += SPAN_NOTICE("Total volume: [reagents.total_volume] / [reagents.maximum_volume].") + if(dispensing) + . += SPAN_NOTICE("\nTransfer mode: Dispensing") + else + . += SPAN_NOTICE("\nTransfer mode: Filling") + . += SPAN_NOTICE("Transfer rate: [amount_per_transfer_from_this] units") /obj/structure/reagent_dispensers/Destroy() playsound(src.loc, 'sound/effects/slosh.ogg', 50, 1, 3) @@ -66,7 +71,7 @@ /obj/structure/reagent_dispensers/bullet_act(obj/item/projectile/Proj) health -= Proj.damage if(Proj.firer) - msg_admin_niche("[key_name_admin(Proj.firer)] fired a projectile at [name] in [loc.loc.name] ([loc.x],[loc.y],[loc.z]) (JMP).") + msg_admin_niche("[key_name_admin(Proj.firer)] fired a projectile at [name] in [loc.loc.name] ([loc.x],[loc.y],[loc.z]) [ADMIN_JMP(loc)].") log_game("[key_name(Proj.firer)] fired a projectile at [name] in [loc.loc.name] ([loc.x],[loc.y],[loc.z]).") playsound(src, 'sound/effects/metalhit.ogg', 25, 1) healthcheck() @@ -221,7 +226,7 @@ "You wrench [src]'s faucet [modded ? "closed" : "open"]") modded = modded ? 0 : 1 if (modded) - message_admins("[key_name_admin(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel. (JMP)") + message_admins("[key_name_admin(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel. [ADMIN_JMP(loc)]") log_game("[key_name(user)] opened fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]), leaking fuel.") leak_fuel(amount_per_transfer_from_this)*/ if(istype(W,/obj/item/device/assembly_holder)) @@ -243,7 +248,7 @@ var/obj/item/device/assembly_holder/H = W if (istype(H.a_left,/obj/item/device/assembly/igniter) || istype(H.a_right,/obj/item/device/assembly/igniter)) - msg_admin_niche("[key_name_admin(user)] rigged [name] at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion. (JMP)") + msg_admin_niche("[key_name_admin(user)] rigged [name] at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion. [ADMIN_JMP(loc)]") log_game("[key_name(user)] rigged [name] at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) for explosion.") rig = W @@ -298,7 +303,7 @@ if(Proj.damage > 10 && prob(60) && !reinforced) if(Proj.firer) - message_admins("[key_name_admin(Proj.firer)] fired a projectile at [name] in [loc.loc.name] ([loc.x],[loc.y],[loc.z]) (JMP).") + message_admins("[key_name_admin(Proj.firer)] fired a projectile at [name] in [loc.loc.name] ([loc.x],[loc.y],[loc.z]) [ADMIN_JMP(loc)].") log_game("[key_name(Proj.firer)] fired a projectile at [name] in [loc.loc.name] ([loc.x],[loc.y],[loc.z]).") exploding = TRUE explode() diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm index 70240452655b..fbd6920875ad 100644 --- a/code/game/objects/structures/signs.dm +++ b/code/game/objects/structures/signs.dm @@ -70,7 +70,7 @@ /obj/structure/sign/kiddieplaque name = "AI developers plaque" - desc = "Next to the extremely long list of names and job titles, there is a drawing of a little child. The child appears to be retarded. Beneath the image, someone has scratched the word \"PACKETS\"" + desc = "Next to the extremely long list of names and job titles, there is a drawing of a little child. Beneath the image, someone has scratched the word \"PACKETS\"" icon_state = "kiddieplaque" /obj/structure/sign/arcturianstopsign @@ -592,3 +592,9 @@ desc = "An unbelievably creepy cat clock that surveys the room with every tick and every tock." icon = 'icons/obj/structures/props/catclock.dmi' icon_state = "cat_clock_motion" + +/obj/structure/sign/dartboard + name = "dartboard" + desc = "A dartboard, secured with a nail and a string. It has bullet holes and knife stab marks over and around it." + icon = 'icons/obj/structures/props/props.dmi' + icon_state = "dart_board" diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index db6bb771154e..7979994915f4 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -51,7 +51,7 @@ /obj/structure/bed/deconstruct(disassembled = TRUE) if(!disassembled) - if(!isnull(buildstacktype)) + if(!isnull(buildstacktype) && buildstackamount) new buildstacktype(get_turf(src), buildstackamount) return ..() @@ -208,6 +208,20 @@ return ..() +/obj/structure/bed/roller/Collided(atom/movable/moving_atom) + if(!isxeno(moving_atom)) + return ..() + + if(buckled_mob && buckled_mob.stat != DEAD) + return ..() + + if(buckled_bodybag) + var/mob/mob_in_bodybag = locate(/mob) in buckled_bodybag + if(mob_in_bodybag && mob_in_bodybag.stat != DEAD) + return ..() + + return + /obj/item/roller name = "roller bed" desc = "A collapsed roller bed that can be carried around." @@ -330,9 +344,8 @@ var/global/list/activated_medevac_stretchers = list() if(buckled_mob || buckled_bodybag) overlays += image("icon_state"="stretcher_box","layer"=LYING_LIVING_MOB_LAYER + 0.1) - -/obj/structure/bed/medevac_stretcher/verb/activate_medevac_beacon() - set name = "Activate medevac" +/obj/structure/bed/medevac_stretcher/verb/toggle_medevac_beacon_verb() + set name = "Toggle medevac" set desc = "Toggle the medevac beacon inside the stretcher." set category = "Object" set src in oview(1) @@ -370,13 +383,10 @@ var/global/list/activated_medevac_stretchers = list() to_chat(user, SPAN_WARNING("[src] must be in the open or under a glass roof.")) return - if(buckled_mob || buckled_bodybag) - stretcher_activated = TRUE - activated_medevac_stretchers += src - to_chat(user, SPAN_NOTICE("You activate [src]'s beacon.")) - update_icon() - else - to_chat(user, SPAN_WARNING("You need to attach something to [src] before you can activate its beacon yet.")) + stretcher_activated = TRUE + activated_medevac_stretchers += src + to_chat(user, SPAN_NOTICE("You activate [src]'s beacon.")) + update_icon() /obj/item/roller/medevac name = "medevac stretcher" @@ -385,6 +395,13 @@ var/global/list/activated_medevac_stretchers = list() rollertype = /obj/structure/bed/medevac_stretcher matter = list("plastic" = 5000, "metal" = 5000) +/obj/item/roller/medevac/deploy_roller(mob/user, atom/location) + var/obj/structure/bed/medevac_stretcher/medevac_stretcher = new rollertype(location) + medevac_stretcher.add_fingerprint(user) + user.temp_drop_inv_item(src) + qdel(src) + medevac_stretcher.toggle_medevac_beacon(user) + //bedroll /obj/structure/bed/bedroll name = "bedroll" diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 918c58c71a9e..4186ae8608a9 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -37,6 +37,8 @@ if(!picked_up_item) return var/mob/living/carbon/human/H = over + if(usr != H) + return if(!CAN_PICKUP(H, src)) return if(buckled_mob) @@ -293,6 +295,11 @@ name = "Delta squad chair" desc = "A simple chair permanently attached to the floor. Covered with a squeaky and way too hard faux-leather, unevenly painted in Delta squad blue. This chair is most likely to be the first to fight and first to die." +/obj/structure/bed/chair/comfy/ares + icon_state = "comfychair_ares" + name = "AI core chair" + desc = "A functional chair designed for comfortably sitting a single person with intent to facilitate interactions with the ship AI." + /obj/structure/bed/chair/office anchored = FALSE drag_delay = 1 //Pulling something on wheels is easy diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index d7a7fcab5371..2b42e641f0cf 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -103,3 +103,8 @@ newdir = EAST B.setDir(newdir) bloodiness-- + +/obj/structure/bed/chair/wheelchair/do_buckle(mob/target, mob/user) + if(ishuman(target) && ishuman(user)) + ADD_TRAIT(target, TRAIT_USING_WHEELCHAIR, TRAIT_SOURCE_BUCKLE) + . = ..() diff --git a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm index 637bd07147ca..7a4274c2c16e 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm @@ -5,19 +5,21 @@ desc = "It's a gruesome pile of thick, sticky resin shaped like a nest." icon = 'icons/mob/xenos/effects.dmi' icon_state = "nest" - buckling_y = 6 buildstacktype = null //can't be disassembled and doesn't drop anything when destroyed unacidable = TRUE health = 100 + layer = ABOVE_MOB_LAYER + plane = GAME_PLANE + buckle_lying = FALSE var/on_fire = 0 var/resisting = 0 var/resisting_ready = 0 var/nest_resist_time = 1200 var/mob/dead/observer/ghost_of_buckled_mob = null var/hivenumber = XENO_HIVE_NORMAL - layer = RESIN_STRUCTURE_LAYER - var/force_nest = FALSE + /// counterpart to buckling_y --> offsets the buckled mob when it buckles + var/list/buckling_x /obj/structure/bed/nest/Initialize(mapload, hive) . = ..() @@ -27,6 +29,54 @@ set_hive_data(src, hivenumber) + buckling_y = list("[NORTH]" = 27, "[SOUTH]" = -19, "[EAST]" = 3, "[WEST]" = 3) + buckling_x = list("[NORTH]" = 0, "[SOUTH]" = 0, "[EAST]" = 18, "[WEST]" = -17) + + spawn_check() //nests mapped in without hosts shouldn't persist + +/obj/structure/bed/nest/proc/spawn_check(check_count = 0) + if(!buckled_mob || !locate(/mob/living/carbon) in get_turf(src)) + if(check_count > 3) + qdel(src) + else + check_count++ + addtimer(CALLBACK(src, PROC_REF(spawn_check), check_count), 10 SECONDS) + +/obj/structure/bed/nest/afterbuckle(mob/current_mob) + . = ..() + if(. && current_mob.pulledby) + current_mob.pulledby.stop_pulling() + resisting = FALSE //just in case + resisting_ready = FALSE + + if(buckled_mob == current_mob) + current_mob.pixel_y = buckling_y["[dir]"] + current_mob.pixel_x = buckling_x["[dir]"] + current_mob.dir = turn(dir, 180) + current_mob.density = FALSE + pixel_y = buckling_y["[dir]"] + pixel_x = buckling_x["[dir]"] + if(dir == SOUTH) + buckled_mob.layer = ABOVE_TURF_LAYER + if(ishuman(current_mob)) + var/mob/living/carbon/human/current_human = current_mob + for(var/obj/limb/current_mobs_limb in current_human.limbs) + current_mobs_limb.layer = TURF_LAYER + update_icon() + return + + current_mob.pixel_y = initial(buckled_mob.pixel_y) + current_mob.pixel_x = initial(buckled_mob.pixel_x) + current_mob.density = !(current_mob.lying || current_mob.stat == DEAD) + if(dir == SOUTH) + current_mob.layer = initial(current_mob.layer) + if(!ishuman(current_mob)) + var/mob/living/carbon/human/current_human = current_mob + for(var/obj/limb/current_mobs_limb in current_human.limbs) + current_mobs_limb.layer = initial(current_mobs_limb.layer) + if(!QDESTROYING(src)) + qdel(src) + /obj/structure/bed/nest/alpha color = "#ff4040" hivenumber = XENO_HIVE_ALPHA @@ -139,11 +189,12 @@ recently_nested = TRUE addtimer(VARSET_CALLBACK(src, recently_nested, FALSE), 5 SECONDS) -/obj/structure/bed/nest/buckle_mob(mob/M as mob, mob/user as mob) - if(!isliving(M) || islarva(user) || (get_dist(src, user) > 1) || (M.loc != loc) || user.is_mob_restrained() || user.stat || user.lying || M.buckled || !iscarbon(user)) +/obj/structure/bed/nest/buckle_mob(mob/mob, mob/user) + . = FALSE + if(!isliving(mob) || islarva(user) || (get_dist(src, user) > 1) || user.is_mob_restrained() || user.stat || user.lying || mob.buckled || !iscarbon(user)) return - if(isxeno(M)) + if(isxeno(mob)) to_chat(user, SPAN_WARNING("You can't buckle your sisters.")) return @@ -151,69 +202,66 @@ to_chat(user, SPAN_WARNING("There's already someone in [src].")) return - if(M.mob_size > MOB_SIZE_HUMAN) - to_chat(user, SPAN_WARNING("\The [M] is too big to fit in [src].")) + if(mob.mob_size > MOB_SIZE_HUMAN) + to_chat(user, SPAN_WARNING("\The [mob] is too big to fit in [src].")) return - if(!isxeno(user) || issynth(M)) + if(!isxeno(user) || issynth(mob)) to_chat(user, SPAN_WARNING("Gross! You're not touching that stuff.")) return - if(isyautja(M) && !force_nest) - to_chat(user, SPAN_WARNING("\The [M] seems to be wearing some kind of resin-resistant armor!")) + if(isyautja(mob) && !force_nest) + to_chat(user, SPAN_WARNING("\The [mob] seems to be wearing some kind of resin-resistant armor!")) return - if(M == user) + if(mob == user) return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(!H.lying) //Don't ask me why is has to be - to_chat(user, SPAN_WARNING("[M] is resisting, ground them.")) + var/mob/living/carbon/human/human = null + if(ishuman(mob)) + human = mob + if(!human.lying) //Don't ask me why is has to be + to_chat(user, SPAN_WARNING("[mob] is resisting, ground them.")) return var/securing_time = 15 // Don't increase the nesting time for monkeys and other species - if(ishuman_strict(M)) + if(ishuman_strict(mob)) securing_time = 75 - user.visible_message(SPAN_WARNING("[user] pins [M] into [src], preparing the securing resin."), - SPAN_WARNING("[user] pins [M] into [src], preparing the securing resin.")) - var/M_loc = M.loc - if(!do_after(user, securing_time, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + user.visible_message(SPAN_WARNING("[user] pins [mob] into [src], preparing the securing resin."), + SPAN_WARNING("[user] pins [mob] into [src], preparing the securing resin.")) + var/M_loc = mob.loc + if(!do_after(user, securing_time, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) return - if(M.loc != M_loc) + if(mob.loc != M_loc) return if(buckled_mob) //Just in case to_chat(user, SPAN_WARNING("There's already someone in [src].")) return - if(ishuman(M)) //Improperly stunned Marines won't be nested - var/mob/living/carbon/human/H = M - if(!H.lying) //Don't ask me why is has to be - to_chat(user, SPAN_WARNING("[M] is resisting, ground them.")) + if(human) //Improperly stunned Marines won't be nested + if(!human.lying) //Don't ask me why is has to be + to_chat(user, SPAN_WARNING("[mob] is resisting, ground them.")) return - do_buckle(M, user) - ADD_TRAIT(M, TRAIT_NESTED, TRAIT_SOURCE_BUCKLE) + do_buckle(mob, user) + ADD_TRAIT(mob, TRAIT_NESTED, TRAIT_SOURCE_BUCKLE) - if(!ishuman(M)) - return + if(!human) + return TRUE //Disabling motion detectors and other stuff they might be carrying - var/mob/living/carbon/human/H = M - H.start_nesting_cooldown() - H.disable_special_flags() - H.disable_lights() - H.disable_special_items() - - if(H.mind) - var/choice = alert(M, "You have no possibility of escaping unless freed by your fellow marines, do you wish to Ghost? If you are freed while ghosted, you will be given the choice to return to your body.", ,"Ghost", "Remain") - if(choice == "Ghost") - // Ask to ghostize() so they can reenter, to leave mind and such intact - ghost_of_buckled_mob = M.ghostize(can_reenter_corpse = TRUE) - ghost_of_buckled_mob?.can_reenter_corpse = FALSE // Just don't for now + human.start_nesting_cooldown() + human.disable_special_flags() + human.disable_lights() + human.disable_special_items() + + if(human.client) + human.do_ghost() + + return TRUE /obj/structure/bed/nest/send_buckling_message(mob/M, mob/user) M.visible_message(SPAN_XENONOTICE("[user] secretes a thick, vile resin, securing [M] into [src]!"), \ @@ -221,14 +269,6 @@ SPAN_NOTICE("You hear squelching.")) playsound(loc, "alien_resin_move", 50) -/obj/structure/bed/nest/afterbuckle(mob/M) - . = ..() - if(. && M.pulledby) - M.pulledby.stop_pulling() - resisting = 0 //just in case - resisting_ready = 0 - update_icon() - /obj/structure/bed/nest/unbuckle(mob/user) if(!buckled_mob) return @@ -237,21 +277,21 @@ buckled_mob.pixel_y = 0 buckled_mob.old_y = 0 REMOVE_TRAIT(buckled_mob, TRAIT_NESTED, TRAIT_SOURCE_BUCKLE) - var/mob/living/carbon/human/H = buckled_mob - - . = ..() + var/mob/living/carbon/human/buckled_human = buckled_mob var/mob/dead/observer/G = ghost_of_buckled_mob var/datum/mind/M = G?.mind ghost_of_buckled_mob = null - if(!istype(H) || !istype(G) || !istype(M) || H.undefibbable || H.mind || M.original != H || H.chestburst) + + . = ..() //Very important that this comes after, since it deletes the nest and clears ghost_of_buckled_mob + + if(!istype(buckled_human) || !istype(G) || !istype(M) || buckled_human.undefibbable || buckled_human.mind || M.original != buckled_human || buckled_human.chestburst) return // Zealous checking as most is handled by ghost code to_chat(G, FONT_SIZE_HUGE(SPAN_DANGER("You have been freed from your nest and may go back to your body! (Look for 'Re-enter Corpse' in Ghost verbs, or click here!)"))) sound_to(G, 'sound/effects/attackblob.ogg') - if(H.client?.prefs.toggles_flashing & FLASH_UNNEST) - window_flash(H.client) + if(buckled_human.client?.prefs.toggles_flashing & FLASH_UNNEST) + window_flash(buckled_human.client) G.can_reenter_corpse = TRUE - return /obj/structure/bed/nest/ex_act(power) if(power >= EXPLOSION_THRESHOLD_VLOW) @@ -262,12 +302,10 @@ if(on_fire) overlays += "alien_fire" if(buckled_mob) - overlays += image("icon_state"="nest_overlay","layer"=LYING_LIVING_MOB_LAYER + 0.1) - + overlays += image(icon_state = "nest_overlay", dir = buckled_mob.dir, layer = ABOVE_MOB_LAYER, pixel_y = 1) /obj/structure/bed/nest/proc/healthcheck() if(health <= 0) - density = FALSE deconstruct() /obj/structure/bed/nest/fire_act() @@ -311,12 +349,14 @@ name = "thick alien nest" desc = "A very thick nest, oozing with a thick sticky substance." layer = ABOVE_SPECIAL_RESIN_STRUCTURE_LAYER - + icon_state = "pred_nest" force_nest = TRUE var/obj/effect/alien/resin/special/nest/linked_structure /obj/structure/bed/nest/structure/Initialize(mapload, hive, obj/effect/alien/resin/special/nest/to_link) . = ..() + buckling_y = list("[NORTH]" = -19, "[SOUTH]" = 27, "[EAST]" = 3, "[WEST]" = 3) + buckling_x = list("[NORTH]" = 0, "[SOUTH]" = 0, "[EAST]" = -17, "[WEST]" = 18) if(to_link) linked_structure = to_link @@ -333,3 +373,15 @@ to_chat(user, SPAN_NOTICE("The sticky resin is too strong for you to do anything to this nest")) return FALSE . = ..() + +/obj/structure/bed/nest/structure/afterbuckle(mob/current_mob) + . = ..() + switch(buckled_mob.dir) + if(NORTH) + buckled_mob.dir = SOUTH + if(SOUTH) + buckled_mob.dir = NORTH + if(EAST) + buckled_mob.dir = WEST + if(WEST) + buckled_mob.dir = EAST diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 402415b0f95b..db3ce98339a3 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -326,11 +326,13 @@ /// Checks whether a table is a straight line along a given axis /obj/structure/surface/table/proc/straight_table_check(direction) var/obj/structure/surface/table/table = src - while(table) + var/obj/structure/surface/table/side_table + var/tables_count = 7 // Lazy extra safety against infinite loops. If table big, can't flip, i guess. + while(--tables_count) // Check whether there are connected tables perpendicular to the axis for(var/angle in list(-90, 90)) - table = locate() in get_step(loc, turn(direction, angle)) - if(table && !table.flipped) + side_table = locate() in get_step(table, turn(direction, angle)) + if(side_table && !side_table.flipped) return FALSE table = locate() in get_step(table, direction) if(!table || table.flipped) @@ -339,6 +341,8 @@ var/obj/structure/surface/table/reinforced/reinforced_table = table if(reinforced_table.status == RTABLE_NORMAL) return FALSE + if(!tables_count) + return FALSE return TRUE /obj/structure/surface/table/verb/do_flip() @@ -421,7 +425,7 @@ to_chat(usr, SPAN_WARNING("You have moved a table too recently.")) return FALSE - if(!skip_straight_check && (!straight_table_check(turn(direction, 90)) || !straight_table_check(turn(direction, -90)))) + if(!skip_straight_check && !(straight_table_check(turn(direction, 90)) && straight_table_check(turn(direction, -90)))) to_chat(usr, SPAN_WARNING("[src] is too wide to be flipped.")) return FALSE @@ -618,7 +622,7 @@ /obj/structure/surface/table/reinforced/cloth name = "cloth table" desc = "A fancy cloth-topped wooden table, bolted to the floor. Fit for formal occasions." - icon_state = "cloth" + icon_state = "clothtable" table_prefix = "cloth" /* diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 7457dae963e9..cccc1211bfb0 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -56,23 +56,13 @@ open = !open // Toggles open to opposite state update_icon() - if(open && (do_after(user, 1 SECONDS))) - switch(user.nutrition) - if((1 + NUTRITION_NORMAL) to NUTRITION_MAX) - to_chat(user, SPAN_NOTICE("The toilet starts flushing. You start feeling a bit more hungry.")) - user.nutrition = ((NUTRITION_LOW + NUTRITION_NORMAL) * 0.5) - if((1 + NUTRITION_LOW) to NUTRITION_NORMAL) - to_chat(user, SPAN_NOTICE("The toilet starts flushing. You could go for some food right now.")) - user.nutrition = ((NUTRITION_VERYLOW + NUTRITION_LOW) * 0.5) - if((1 + NUTRITION_VERYLOW) to NUTRITION_LOW) - to_chat(user, SPAN_NOTICE("The toilet starts flushing. Your stomach growls and you feel a little thinner.")) - user.nutrition = NUTRITION_VERYLOW * 0.5 - else - to_chat(user, SPAN_NOTICE("The toilet starts flushing. You feel starved. Go grab something to eat!")) - user.nutrition = 0 + else // open + if(user.action_busy) // Prevent spamming faster than do_after speed + return + if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC)) + return playsound(loc, 'sound/effects/toilet_flush_new.ogg', 25, 1) - flick("toilet1[cistern]_flush", src) if(dir == SOUTH) flick("cistern[cistern]_flush", cistern_overlay) @@ -131,7 +121,7 @@ cistern_overlay.icon_state = "cistern[cistern]" /obj/structure/toilet/attackby(obj/item/I, mob/living/user) - if(istype(I, /obj/item/tool/crowbar)) + if(HAS_TRAIT(I, TRAIT_TOOL_CROWBAR)) 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', 25, 1) if(do_after(user, 30, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 09086ec57fbb..090c5ad56f87 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -439,11 +439,20 @@ desc = "An ultra-reinforced window designed to keep the briefing podium a secure area." icon_state = "fwindow" basestate = "fwindow" - not_damageable = 1 - not_deconstructable = 1 + not_damageable = TRUE + not_deconstructable = TRUE unslashable = TRUE unacidable = TRUE +/obj/structure/window/reinforced/ultra/initialize_pass_flags(datum/pass_flags_container/PF) + . = ..() + if (PF) + PF.flags_can_pass_all = NONE + PF.flags_can_pass_front = NONE + PF.flags_can_pass_behind = PASS_OVER^(PASS_OVER_ACID_SPRAY) + flags_can_pass_front_temp = NONE + flags_can_pass_behind_temp = NONE + /obj/structure/window/reinforced/ultra/Initialize() . = ..() GLOB.hijack_bustable_windows += src @@ -499,8 +508,13 @@ relativewall_neighbours() /obj/structure/window/framed/Destroy() - for(var/obj/effect/alien/weeds/weedwall/window/WW in loc) - qdel(WW) + for(var/obj/effect/alien/weeds/weedwall/window/found_weedwall in get_turf(src)) + qdel(found_weedwall) + var/list/turf/cardinal_neighbors = list(get_step(src, NORTH), get_step(src, SOUTH), get_step(src, EAST), get_step(src, WEST)) + for(var/turf/cardinal_turf as anything in cardinal_neighbors) + for(var/obj/structure/bed/nest/found_nest in cardinal_turf) + if(found_nest.dir == get_dir(found_nest, src)) + qdel(found_nest) //nests are built on walls, no walls, no nest . = ..() /obj/structure/window/framed/initialize_pass_flags(datum/pass_flags_container/PF) @@ -561,8 +575,8 @@ name = "hull window" desc = "A glass window with a special rod matrix inside a wall frame. This one was made out of exotic materials to prevent hull breaches. No way to get through here." //icon_state = "rwindow0_debug" //Uncomment to check hull in the map editor - not_damageable = 1 - not_deconstructable = 1 + not_damageable = TRUE + not_deconstructable = TRUE unslashable = TRUE unacidable = TRUE health = 1000000 //Failsafe, shouldn't matter @@ -584,8 +598,8 @@ /obj/structure/window/framed/almayer/white/hull name = "hull window" desc = "An ultra-reinforced window designed to keep research a secure area. This one was made out of exotic materials to prevent hull breaches. No way to get through here." - not_damageable = 1 - not_deconstructable = 1 + not_damageable = TRUE + not_deconstructable = TRUE unslashable = TRUE unacidable = TRUE health = 1000000 //Failsafe, shouldn't matter @@ -614,8 +628,8 @@ name = "hull window" desc = "A glass window with a special rod matrix inside a wall frame. This one was made out of exotic materials to prevent hull breaches. No way to get through here." //icon_state = "rwindow0_debug" //Uncomment to check hull in the map editor - not_damageable = 1 - not_deconstructable = 1 + not_damageable = TRUE + not_deconstructable = TRUE unslashable = TRUE unacidable = TRUE health = 1000000 //Failsafe, shouldn't matter @@ -706,6 +720,16 @@ reinf = 1 window_frame = /obj/structure/window_frame/strata/reinforced +/obj/structure/window/framed/strata/hull + icon_state = "strata_window0" + basestate = "strata_window" + desc = "A glass window. Something tells you this one is somehow indestructible." + not_damageable = TRUE + not_deconstructable = TRUE + unslashable = TRUE + unacidable = TRUE + health = 1000000 + //Kutjevo Windows /obj/structure/window/framed/kutjevo @@ -729,8 +753,8 @@ /obj/structure/window/framed/kutjevo/reinforced/hull icon_state = "kutjevo_window_hull" desc = "A glass window. Something tells you this one is somehow indestructible." - not_damageable = 1 - not_deconstructable = 1 + not_damageable = TRUE + not_deconstructable = TRUE unslashable = TRUE unacidable = TRUE health = 1000000 @@ -766,8 +790,8 @@ /obj/structure/window/framed/solaris/reinforced/hull desc = "A glass window. Something tells you this one is somehow indestructible." - not_damageable = 1 - not_deconstructable = 1 + not_damageable = TRUE + not_deconstructable = TRUE unslashable = TRUE unacidable = TRUE health = 1000000 @@ -798,8 +822,8 @@ /obj/structure/window/framed/dev/reinforced/hull desc = "A glass window. Something tells you this one is somehow indestructible." - not_damageable = 1 - not_deconstructable = 1 + not_damageable = TRUE + not_deconstructable = TRUE unslashable = TRUE unacidable = TRUE health = 1000000 @@ -828,7 +852,7 @@ desc = "A glass window with a special rod matrix inside a wall frame. This one has an automatic shutter system to prevent any atmospheric breach." health = 200 //icon_state = "rwindow0_debug" //Uncomment to check hull in the map editor - var/triggered = 0 //indicates if the shutters have already been triggered + var/triggered = FALSE //indicates if the shutters have already been triggered /obj/structure/window/framed/prison/reinforced/hull/Destroy() spawn_shutters() @@ -837,8 +861,8 @@ /obj/structure/window/framed/prison/reinforced/hull/proc/spawn_shutters(from_dir = 0) if(triggered) return - else - triggered = 1 + + triggered = TRUE for(var/direction in cardinal) if(direction == from_dir) continue //doesn't check backwards for(var/obj/structure/window/framed/prison/reinforced/hull/W in get_step(src,direction) ) @@ -849,8 +873,7 @@ P.setDir(SOUTH) else P.setDir(EAST) - spawn(0) - P.close() + P.close() /obj/structure/window/framed/prison/cell name = "cell window" @@ -889,8 +912,8 @@ icon_state = "padded_cellwindow0" basestate = "padded_cellwindow" desc = "A glass window with a special rod matrix inside a wall frame. This one was made out of exotic materials to prevent hull breaches. No way to get through here." - not_damageable = 1 - not_deconstructable = 1 + not_damageable = TRUE + not_deconstructable = TRUE unacidable = TRUE health = 1000000 //Failsafe, shouldn't matter @@ -909,9 +932,15 @@ var/triggered = FALSE //indicates if the shutters have already been triggered /obj/structure/window/framed/corsat/hull/research + icon_state = "paddedresearch_rwindow0" + basestate = "paddedresearch_rwindow" + window_frame = /obj/structure/window_frame/corsat/research health = 300 /obj/structure/window/framed/corsat/hull/security + icon_state = "paddedsec_rwindow0" + basestate = "paddedsec_rwindow" + window_frame = /obj/structure/window_frame/corsat/security health = 400 /obj/structure/window/framed/corsat/hull/Destroy() @@ -938,3 +967,22 @@ P.setDir(EAST) INVOKE_ASYNC(P, TYPE_PROC_REF(/obj/structure/machinery/door, close)) + +/obj/structure/window/framed/corsat/indestructible/ + name = "hull window" + desc = "A glass window with a special rod matrix inside a wall frame. This one has been reinforced to take almost anything the universe can throw at it." + not_damageable = TRUE + not_deconstructable = TRUE + unslashable = TRUE + unacidable = TRUE + health = 1000000 + +/obj/structure/window/framed/corsat/indestructible/research + icon_state = "paddedresearch_rwindow0" + basestate = "paddedresearch_rwindow" + window_frame = /obj/structure/window_frame/corsat/research + +/obj/structure/window/framed/corsat/indestructible/security + icon_state = "paddedsec_rwindow0" + basestate = "paddedsec_rwindow" + window_frame = /obj/structure/window_frame/corsat/security diff --git a/code/game/objects/structures/window_frame.dm b/code/game/objects/structures/window_frame.dm index b883f1b9fef9..810b0560bf8b 100644 --- a/code/game/objects/structures/window_frame.dm +++ b/code/game/objects/structures/window_frame.dm @@ -207,20 +207,20 @@ reinforced = TRUE /obj/structure/window_frame/hangar - icon_state = "hngr_window0" + icon_state = "hngr_window0_frame" basestate = "hngr_window" /obj/structure/window_frame/hangar/reinforced - icon_state = "hngr_rwindow0" + icon_state = "hngr_rwindow0_frame" basestate = "hngr_rwindow" reinforced = TRUE /obj/structure/window_frame/bunker - icon_state = "bnkr_window0" + icon_state = "bnkr_window0_frame" basestate = "bnkr_window" /obj/structure/window_frame/bunker/reinforced - icon_state = "bnkr_rwindow0" + icon_state = "bnkr_rwindow0_frame" basestate = "bnkr_rwindow" reinforced = TRUE @@ -236,6 +236,12 @@ basestate = "strata_window" reinforced = TRUE +/obj/structure/window_frame/strata/hull + icon_state = "strata_window0_frame" + basestate = "strata_window" + unslashable = TRUE + unacidable = TRUE + //Kutjevo frames /obj/structure/window_frame/kutjevo diff --git a/code/game/runtimes.dm b/code/game/runtimes.dm index 6998c05c5086..1332309168a3 100644 --- a/code/game/runtimes.dm +++ b/code/game/runtimes.dm @@ -58,3 +58,5 @@ GLOBAL_REAL_VAR(total_runtimes) GLOB.STUI.processing |= STUI_LOG_RUNTIME else stui_init_runtimes.Add(text) + + log_runtime("runtime error: [E.name]\n[E.desc]") diff --git a/code/game/sim_manager/datums/simulator.dm b/code/game/sim_manager/datums/simulator.dm new file mode 100644 index 000000000000..04ddb7faa088 --- /dev/null +++ b/code/game/sim_manager/datums/simulator.dm @@ -0,0 +1,103 @@ +/datum/simulator + + // Necessary to prevent multiple users from simulating at the same time. + var/static/detonation_cooldown = 0 + var/static/sim_reboot_state = TRUE + + var/looking_at_simulation = FALSE + var/detonation_cooldown_time = 2 MINUTES + var/dummy_mode = CLF_MODE + var/obj/structure/machinery/camera/simulation/sim_camera + var/grid_clearing_size = 16 + + // garbage collection, + var/static/list/delete_targets = list() + + /* + unarmoured humans are unnencessary clutter as they tend to explode easily + and litter the sim room with body parts, best left out. + */ + var/static/list/target_types = list( + UPP_MODE = /mob/living/carbon/human, + CLF_MODE = /mob/living/carbon/human, + RUNNER_MODE = /mob/living/carbon/xenomorph/runner, + SPITTER_MODE = /mob/living/carbon/xenomorph/spitter, + DEFENDER_MODE = /mob/living/carbon/xenomorph/defender, + RAVAGER_MODE = /mob/living/carbon/xenomorph/ravager, + CRUSHER_MODE = /mob/living/carbon/xenomorph/crusher, + ) + +/datum/simulator/proc/start_watching(mob/living/user) + + if(looking_at_simulation) + to_chat(user, SPAN_WARNING("You are already looking at the simulation.")) + return + if(!sim_camera) + sim_camera = SAFEPICK(GLOB.simulator_cameras) + if(!sim_camera) + to_chat(user, SPAN_WARNING("GPU damaged! Unable to start simulation.")) + return + if(user.client.view != world_view_size) + to_chat(user, SPAN_WARNING("You're too busy looking at something else.")) + return + user.reset_view(sim_camera) + looking_at_simulation = TRUE + +/datum/simulator/proc/stop_watching(mob/living/user) + user.unset_interaction() + user.reset_view(null) + user.cameraFollow = null + looking_at_simulation = FALSE + +/datum/simulator/proc/sim_turf_garbage_collection() + + // initial grid needs an offset to the bottom left so it can get the most coverage within the users pov. + var/turf/sim_grid_start_pos = locate(sim_camera.x - 9,sim_camera.y - 9,1) + if(!sim_grid_start_pos) + sim_reboot_state = FALSE + return + + QDEL_LIST(delete_targets) + + // 16x16 grid, clears from left to right like so + // the user's pov should be near the center of the grid. + /* + y:16| x: 1 2 3 4 ... 16 + ... | ... + y:2 | x: 1 2 3 4 ... 16 + y:1 | x: 1 2 3 4 ... 16 + */ + for (var/y_pos in 1 to grid_clearing_size)// outer y + for (var/x_pos in 1 to grid_clearing_size) // inner x + var/turf/current_grid = locate(sim_grid_start_pos.x + x_pos,sim_grid_start_pos.y + y_pos,sim_grid_start_pos.z) + + current_grid.empty(/turf/open/floor/engine) + +/datum/simulator/proc/spawn_mobs(mob/living/user) + + if(!sim_reboot_state) + to_chat(user, SPAN_WARNING("GPU damaged! Unable to start simulation.")) + return + + COOLDOWN_START(src, detonation_cooldown, detonation_cooldown_time) + + var/spawn_path = target_types[dummy_mode] + for(var/spawn_loc in GLOB.simulator_targets) + if( dummy_mode == CLF_MODE || dummy_mode == UPP_MODE) + var/mob/living/carbon/human/human_dummy = new spawn_path(get_turf(spawn_loc)) + switch(dummy_mode) + if(CLF_MODE) + user.client.cmd_admin_dress_human(human_dummy, "CLF Soldier", no_logs = TRUE) + if(UPP_MODE) + user.client.cmd_admin_dress_human(human_dummy, "UPP Conscript", no_logs = TRUE) + human_dummy.name = "simulated human" + + delete_targets += human_dummy + continue + + var/mob/living/carbon/xenomorph/xeno_dummy = new spawn_path(get_turf(spawn_loc)) + xeno_dummy.hardcore = TRUE + delete_targets += xeno_dummy + + addtimer(CALLBACK(src, PROC_REF(sim_turf_garbage_collection)), 30 SECONDS, TIMER_STOPPABLE) + diff --git a/code/game/sound.dm b/code/game/sound.dm index 7dea1ec05303..6adaab109794 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -213,7 +213,7 @@ if("clan_sword_hit") S = pick('sound/weapons/clan_sword_hit_1.ogg', 'sound/weapons/clan_sword_hit_2.ogg') if("slam") - S = pick('sound/effects/slam1.ogg','sound/effects/slam2.ogg','sound/effects/slam3.ogg') + S = pick('sound/effects/slam1.ogg','sound/effects/slam2.ogg','sound/effects/slam3.ogg', 0.1;'sound/effects/slam_rare_1.ogg') if("pageturn") S = pick('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg') if("terminal_button") diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index 0c3f774a80a0..350d6047b2a4 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -191,11 +191,11 @@ var/datum/controller/supply/supply_controller = new() var/list/data = list() var/list/squad_list = list() - for(var/datum/squad/S in RoleAuthority.squads) - if(S.active && S.faction == faction && S.color) + for(var/datum/squad/current_squad in RoleAuthority.squads) + if(current_squad.active && current_squad.faction == faction && current_squad.equipment_color) squad_list += list(list( - "squad_name" = S.name, - "squad_color" = squad_colors[S.color] + "squad_name" = current_squad.name, + "squad_color" = current_squad.equipment_color )) data["can_pick_squad"] = can_pick_squad @@ -521,6 +521,7 @@ var/datum/controller/supply/supply_controller = new() qdel(C) // Sell manifests. + var/screams = FALSE for(var/atom/movable/movable_atom in area_shuttle) if(istype(movable_atom, /obj/item/paper/manifest)) var/obj/item/paper/manifest/M = movable_atom @@ -531,6 +532,7 @@ var/datum/controller/supply/supply_controller = new() if(black_market_enabled) var/points_to_add = get_black_market_value(movable_atom) if(points_to_add == KILL_MENDOZA) + screams = TRUE kill_mendoza() black_market_sold_items[movable_atom.type] += 1 black_market_points += points_to_add @@ -538,6 +540,7 @@ var/datum/controller/supply/supply_controller = new() // Don't disintegrate humans! Maul their corpse instead. >:) if(ishuman(movable_atom)) var/timer = 0.5 SECONDS + screams = TRUE for(var/index in 1 to 10) timer += 0.5 SECONDS addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(maul_human), movable_atom), timer) @@ -545,11 +548,11 @@ var/datum/controller/supply/supply_controller = new() // Delete everything else. else qdel(movable_atom) -/proc/maul_human(mob/living/carbon/human/mauled_human) - - for(var/atom/computer as anything in supply_controller.bound_supply_computer_list) - computer.balloon_alert_to_viewers("you hear horrifying noises coming from the elevator!") + if(screams) + for(var/atom/computer as anything in bound_supply_computer_list) + computer.balloon_alert_to_viewers("you hear horrifying noises coming from the elevator!") +/proc/maul_human(mob/living/carbon/human/mauled_human) mauled_human.visible_message(SPAN_HIGHDANGER("The machinery crushes [mauled_human]"), SPAN_HIGHDANGER("The elevator machinery is CRUSHING YOU!")) if(mauled_human.stat != DEAD) @@ -1012,6 +1015,7 @@ var/datum/controller/supply/supply_controller = new() to_chat(usr, SPAN_DANGER("Current retrieval load has reached maximum capacity.")) return + var/datum/ares_link/link = GLOB.ares_link for(var/i=1, i<=supply_controller.requestlist.len, i++) var/datum/supply_order/SO = supply_controller.requestlist[i] if(SO.ordernum == ordernum) @@ -1027,6 +1031,12 @@ var/datum/controller/supply/supply_controller = new() temp += "
Back Main Menu" supply_order.approvedby = usr.name msg_admin_niche("[usr] confirmed supply order of [supply_pack.name].") + var/pack_source = "Cargo Hold" + var/pack_name = supply_pack.name + if(supply_pack.dollar_cost) + pack_source = "Unknown" + pack_name = "Unknown" + link.log_ares_requisition(pack_source, pack_name, usr) else temp = "Not enough money left.
" temp += "
Back Main Menu" @@ -1169,8 +1179,6 @@ var/datum/controller/supply/supply_controller = new() /datum/controller/supply/proc/kill_mendoza() if(!mendoza_status) return //cant kill him twice - for(var/atom/computer as anything in bound_supply_computer_list) - computer.balloon_alert_to_viewers("you hear horrifying noises coming from the elevator!") mendoza_status = FALSE // he'll die soon enough, and in the meantime will be too busy to handle requests. @@ -1317,6 +1325,10 @@ var/datum/controller/supply/supply_controller = new() if(!VehicleElevatorConsole) VehicleElevatorConsole = src +/obj/structure/machinery/computer/supplycomp/vehicle/Destroy() + VehicleElevatorConsole = null + return ..() + /obj/structure/machinery/computer/supplycomp/vehicle/attack_hand(mob/living/carbon/human/H as mob) if(inoperable()) return diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index f4436e574d06..92bce17e50f6 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -1,5 +1,3 @@ - - //turfs with density = TRUE /turf/closed density = TRUE @@ -31,6 +29,7 @@ if(istype(turf_to_check,/turf/open)) turf_to_check.overlays += image('icons/turf/walls/walls.dmi', "rock_side_[direction]", 2.99) //Really high since it's an overhead turf and it shouldn't collide with anything else + //Ground map dense jungle /turf/closed/gm name = "dense jungle" @@ -61,8 +60,6 @@ icon_state = "wall2" - - //desertdam rock /turf/closed/desert_rock name = "rockwall" @@ -70,14 +67,8 @@ icon_state = "cavewall1" - - - - - - - //ICE WALLS-----------------------------------// + //Ice Wall /turf/closed/ice name = "dense ice wall" @@ -103,6 +94,27 @@ /turf/closed/ice/intersection icon_state = "Intersection" +//Ice Secret Wall +/turf/closed/ice/secret + desc = "There is something inside..." + +/turf/closed/ice/secret/single + icon_state = "Single" + +/turf/closed/ice/secret/end + icon_state = "End" + +/turf/closed/ice/secret/straight + icon_state = "Straight" + +/turf/closed/ice/secret/corner + icon_state = "Corner" + +/turf/closed/ice/secret/junction + icon_state = "T-Junction" + +/turf/closed/ice/secret/intersection + icon_state = "Intersection" //Ice Thin Wall @@ -131,12 +143,28 @@ /turf/closed/ice/thin/intersection icon_state = "Intersection" - -//Ice Secret Wall -/turf/closed/ice/secret - icon_state = "ice_wall_0" +//Thin Ice Secret Wall +/turf/closed/ice/thin/secret desc = "There is something inside..." +/turf/closed/ice/thin/secret/single + icon_state = "Single" + +/turf/closed/ice/thin/secret/end + icon_state = "End" + +/turf/closed/ice/thin/secret/straight + icon_state = "Straight" + +/turf/closed/ice/thin/secret/corner + icon_state = "Corner" + +/turf/closed/ice/thin/secret/junction + icon_state = "T-Junction" + +/turf/closed/ice/thin/secret/intersection + icon_state = "Intersection" + //ROCK WALLS------------------------------// @@ -195,11 +223,6 @@ icon_state = "corner_overlay" - - - - - //SHUTTLE 'WALLS' //not a child of turf/closed/wall because shuttle walls are magical, don't smoothes with normal walls, etc @@ -207,6 +230,10 @@ name = "wall" icon_state = "wall1" icon = 'icons/turf/shuttle.dmi' + layer = ABOVE_TURF_LAYER + +/turf/closed/shuttle/is_weedable() + return FULLY_WEEDABLE /turf/closed/shuttle/dropship icon = 'icons/turf/walls/walls.dmi' @@ -216,7 +243,6 @@ icon = 'icons/turf/ert_shuttle.dmi' icon_state = "stan4" - /turf/closed/shuttle/dropship1 name = "\improper Alamo" icon = 'icons/turf/dropship.dmi' diff --git a/code/game/turfs/floor.dm b/code/game/turfs/floor.dm index 4a600d4d033b..dc2cda0c2c2a 100644 --- a/code/game/turfs/floor.dm +++ b/code/game/turfs/floor.dm @@ -148,7 +148,7 @@ if(src.weeds) return weeds.attackby(hitting_item,user) - if(istype(hitting_item, /obj/item/tool/crowbar) && (tool_flags & (REMOVE_CROWBAR|BREAK_CROWBAR))) + if(HAS_TRAIT(hitting_item, TRAIT_TOOL_CROWBAR) && (tool_flags & (REMOVE_CROWBAR|BREAK_CROWBAR))) if(broken || burnt) to_chat(user, SPAN_WARNING("You remove the broken tiles.")) else diff --git a/code/game/turfs/floor_types.dm b/code/game/turfs/floor_types.dm index 25682f00df29..4e47fd004f74 100644 --- a/code/game/turfs/floor_types.dm +++ b/code/game/turfs/floor_types.dm @@ -272,7 +272,9 @@ /turf/open/floor/almayer/uscm/directional icon_state = "logo_directional" - +/turf/open/floor/almayer/no_build + allow_construction = FALSE + hull_floor = TRUE // RESEARCH STUFF /turf/open/floor/almayer/research/containment/entrance diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 41ada18c1552..41ac80bfdc58 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -331,6 +331,40 @@ baseturfs = /turf/open/gm/grass scorchable = "grass1" +/turf/open/gm/grass/grass1 + icon_state = "grass1" + +/turf/open/gm/grass/grass2 + icon_state = "grass2" + +/turf/open/gm/grass/grassbeach + icon_state = "grassbeach" + +/turf/open/gm/grass/grassbeach/north + +/turf/open/gm/grass/grassbeach/south + dir = 1 + +/turf/open/gm/grass/grassbeach/west + dir = 4 + +/turf/open/gm/grass/grassbeach/east + dir = 8 + +/turf/open/gm/grass/gbcorner + icon_state = "gbcorner" + +/turf/open/gm/grass/gbcorner/north_west + +/turf/open/gm/grass/gbcorner/south_east + dir = 1 + +/turf/open/gm/grass/gbcorner/south_west + dir = 4 + +/turf/open/gm/grass/gbcorner/north_east + dir = 8 + /turf/open/gm/grass/Initialize(mapload, ...) . = ..() @@ -357,6 +391,45 @@ baseturfs = /turf/open/gm/dirtgrassborder scorchable = "grass1" +/turf/open/gm/dirtgrassborder/north + +/turf/open/gm/dirtgrassborder/south + dir = 1 + +/turf/open/gm/dirtgrassborder/west + dir = 4 + +/turf/open/gm/dirtgrassborder/east + dir = 8 + +/turf/open/gm/dirtgrassborder/grassdirt_corner + icon_state = "grassdirt_corner" + +/turf/open/gm/dirtgrassborder/grassdirt_corner/north_west + +/turf/open/gm/dirtgrassborder/grassdirt_corner/north_east + dir = 1 + +/turf/open/gm/dirtgrassborder/grassdirt_corner/south_east + dir = 4 + +/turf/open/gm/dirtgrassborder/grassdirt_corner/south_west + dir = 8 + +/turf/open/gm/dirtgrassborder/grassdirt_corner2 + icon_state = "grassdirt_corner2" + +/turf/open/gm/dirtgrassborder/grassdirt_corner2/north_west + +/turf/open/gm/dirtgrassborder/grassdirt_corner2/south_east + dir = 1 + +/turf/open/gm/dirtgrassborder/grassdirt_corner2/north_east + dir = 4 + +/turf/open/gm/dirtgrassborder/grassdirt_corner2/south_west + dir = 8 + /turf/open/gm/dirtgrassborder/Initialize(mapload, ...) . = ..() @@ -444,7 +517,7 @@ var/obj/item/clothing/gloves/yautja/hunter/Y = H.gloves if(Y && istype(Y) && Y.cloaked) to_chat(H, SPAN_WARNING(" Your bracers hiss and spark as they short out!")) - Y.decloak(H, TRUE) + Y.decloak(H, TRUE, DECLOAK_SUBMERGED) else if(isxeno(C)) river_slowdown -= 0.7 @@ -527,6 +600,44 @@ baseturfs = /turf/open/gm/coast supports_surgery = FALSE +/turf/open/gm/coast/north + +/turf/open/gm/coast/south + dir = 1 + +/turf/open/gm/coast/west + dir = 4 + +/turf/open/gm/coast/east + dir = 8 + +/turf/open/gm/coast/beachcorner + icon_state = "beachcorner" + +/turf/open/gm/coast/beachcorner/north_west + +/turf/open/gm/coast/beachcorner/north_east + dir = 1 + +/turf/open/gm/coast/beachcorner/south_east + dir = 4 + +/turf/open/gm/coast/beachcorner/south_west + dir = 8 + +/turf/open/gm/coast/beachcorner2 + icon_state = "beachcorner2" + +/turf/open/gm/coast/beachcorner2/north_west + +/turf/open/gm/coast/beachcorner2/north_east + dir = 1 + +/turf/open/gm/coast/beachcorner2/south_west + dir = 4 + +/turf/open/gm/coast/beachcorner2/south_east + dir = 8 /turf/open/gm/riverdeep name = "river" diff --git a/code/game/turfs/strata.dm b/code/game/turfs/strata.dm index e48f6bf8bc40..a89f98a732ae 100644 --- a/code/game/turfs/strata.dm +++ b/code/game/turfs/strata.dm @@ -5,6 +5,13 @@ /turf/open/gm/grass/weedable/is_weedable() return FULLY_WEEDABLE +//just in case + +/turf/open/gm/grass/grass1/weedable //inherit from general turfs + +/turf/open/gm/grass/grass1/weedable/is_weedable() + return FULLY_WEEDABLE + /turf/open/gm/dirtgrassborder/weedable /turf/open/gm/dirtgrassborder/weedable/is_weedable() //Gotta have our sexy grass borders be weedable. diff --git a/code/game/turfs/transit.dm b/code/game/turfs/transit.dm index ef2d4e89b098..bae6718cfd59 100644 --- a/code/game/turfs/transit.dm +++ b/code/game/turfs/transit.dm @@ -5,6 +5,26 @@ baseturfs = /turf/open/space/transit var/auto_space_icon = TRUE +/turf/open/space/transit/Entered(atom/movable/crosser, atom/old_loc) + . = ..() + + if(isobserver(crosser) || crosser.anchored) + return + + if(!(isitem(crosser) || isliving(crosser))) + return + + var/turf/open/floor/floor = old_loc + if(istype(floor)) + var/fling_dir = get_dir(floor, crosser.loc) + + var/turf/near_turf = get_step(crosser.loc, get_step(crosser.loc, fling_dir)) + var/turf/projected = get_ranged_target_turf(near_turf, fling_dir, 50) + + INVOKE_ASYNC(crosser, TYPE_PROC_REF(/atom/movable, throw_atom), projected, 50, SPEED_FAST, null, TRUE) + + QDEL_IN(crosser, 0.5 SECONDS) + /turf/open/space/transit/south dir = SOUTH @@ -81,48 +101,48 @@ icon_state = "speedspace_ns_4" /turf/open/space/transit/north/shuttlespace_ns5 - auto_space_icon = FALSE - icon_state = "speedspace_ns_5" + auto_space_icon = FALSE + icon_state = "speedspace_ns_5" /turf/open/space/transit/north/shuttlespace_ns6 - auto_space_icon = FALSE - icon_state = "speedspace_ns_6" + auto_space_icon = FALSE + icon_state = "speedspace_ns_6" /turf/open/space/transit/north/shuttlespace_ns7 - auto_space_icon = FALSE - icon_state = "speedspace_ns_7" + auto_space_icon = FALSE + icon_state = "speedspace_ns_7" /turf/open/space/transit/north/shuttlespace_ns8 - auto_space_icon = FALSE - icon_state = "speedspace_ns_8" + auto_space_icon = FALSE + icon_state = "speedspace_ns_8" /turf/open/space/transit/north/shuttlespace_ns9 - auto_space_icon = FALSE - icon_state = "speedspace_ns_9" + auto_space_icon = FALSE + icon_state = "speedspace_ns_9" /turf/open/space/transit/north/shuttlespace_ns10 - auto_space_icon = FALSE - icon_state = "speedspace_ns_10" + auto_space_icon = FALSE + icon_state = "speedspace_ns_10" /turf/open/space/transit/north/shuttlespace_ns11 - auto_space_icon = FALSE - icon_state = "speedspace_ns_11" + auto_space_icon = FALSE + icon_state = "speedspace_ns_11" /turf/open/space/transit/north/shuttlespace_ns12 - auto_space_icon = FALSE - icon_state = "speedspace_ns_12" + auto_space_icon = FALSE + icon_state = "speedspace_ns_12" /turf/open/space/transit/north/shuttlespace_ns13 - auto_space_icon = FALSE - icon_state = "speedspace_ns_13" + auto_space_icon = FALSE + icon_state = "speedspace_ns_13" /turf/open/space/transit/north/shuttlespace_ns14 - auto_space_icon = FALSE - icon_state = "speedspace_ns_14" + auto_space_icon = FALSE + icon_state = "speedspace_ns_14" /turf/open/space/transit/north/shuttlespace_ns15 - auto_space_icon = FALSE - icon_state = "speedspace_ns_15" + auto_space_icon = FALSE + icon_state = "speedspace_ns_15" /turf/open/space/transit/east/shuttlespace_ew1 auto_space_icon = FALSE diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index e6e2adf65cdd..bc0375e0b850 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -118,6 +118,12 @@ VV_DROPDOWN_OPTION(VV_HK_EXPLODE, "Trigger Explosion") VV_DROPDOWN_OPTION(VV_HK_EMPULSE, "Trigger EM Pulse") +/turf/vv_edit_var(var_name, new_value) + var/static/list/banned_edits = list(NAMEOF_STATIC(src, x), NAMEOF_STATIC(src, y), NAMEOF_STATIC(src, z)) + if(var_name in banned_edits) + return FALSE + . = ..() + /turf/ex_act(severity) return 0 @@ -245,6 +251,7 @@ if(!istype(A)) return + SEND_SIGNAL(src, COMSIG_TURF_ENTERED, A) SEND_SIGNAL(A, COMSIG_MOVABLE_TURF_ENTERED, src) // Let explosions know that the atom entered @@ -499,7 +506,7 @@ var/area/A = get_area(src) switch(A.ceiling) if(CEILING_GLASS) - return "The ceiling above is glass. That's not going stop anything." + return "The ceiling above is glass. That's not going to stop anything." if(CEILING_METAL) return "The ceiling above is metal. You can't see through it with a camera from above, but that's not going to stop anything." if(CEILING_UNDERGROUND_ALLOW_CAS) @@ -560,10 +567,10 @@ return NOT_WEEDABLE /turf/open/auto_turf/shale/layer1/is_weedable() - return FALSE + return SEMI_WEEDABLE /turf/open/auto_turf/shale/layer2/is_weedable() - return FALSE + return SEMI_WEEDABLE /turf/closed/wall/is_weedable() return FULLY_WEEDABLE //so we can spawn weeds on the walls @@ -719,10 +726,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( /// Remove all atoms except observers, landmarks, docking ports - clearing up the turf contents /turf/proc/empty(turf_type=/turf/open/space, baseturf_type, list/ignore_typecache, flags) var/static/list/ignored_atoms = typecacheof(list(/mob/dead, /obj/effect/landmark, /obj/docking_port)) - var/list/allowed_contents = typecache_filter_list_reverse(GetAllContentsIgnoring(ignore_typecache), ignored_atoms) - allowed_contents -= src - for(var/i in 1 to allowed_contents.len) - var/thing = allowed_contents[i] + var/list/removable_contents = typecache_filter_list_reverse(GetAllContentsIgnoring(ignore_typecache), ignored_atoms) + removable_contents -= src + for(var/i in 1 to removable_contents.len) + var/thing = removable_contents[i] qdel(thing, force=TRUE) if(turf_type) diff --git a/code/game/turfs/walls/r_wall.dm b/code/game/turfs/walls/r_wall.dm index a3572138c287..8933ad31c0e8 100644 --- a/code/game/turfs/walls/r_wall.dm +++ b/code/game/turfs/walls/r_wall.dm @@ -265,7 +265,7 @@ name = "heavy reinforced wall" desc = "A huge chunk of ultra-reinforced metal used to separate rooms. Looks virtually indestructible." icon_state = "h_dome" - hull = 1 + hull = TRUE /turf/closed/wall/r_wall/biodome/biodome_unmeltable/ex_act(severity) //Should make it indestructible return diff --git a/code/game/turfs/walls/wall_types.dm b/code/game/turfs/walls/wall_types.dm index 07437f71ac8d..5338ae26c000 100644 --- a/code/game/turfs/walls/wall_types.dm +++ b/code/game/turfs/walls/wall_types.dm @@ -239,6 +239,8 @@ icon_state = "fakewindows" opacity = FALSE +INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen) + /turf/closed/wall/indestructible/splashscreen name = "Lobby Art" desc = "Assorted artworks." @@ -412,6 +414,8 @@ walltype = WALL_CULT color = "#3c3434" +/turf/closed/wall/cult/make_girder(destroyed_girder) + return /turf/closed/wall/vault icon_state = "rockvault" @@ -545,19 +549,21 @@ //SOLARIS RIDGE TILESET// /turf/closed/wall/solaris - name = "solaris ridge colony wall" + name = "colony wall" icon = 'icons/turf/walls/solaris/solaris.dmi' icon_state = "solaris_interior" desc = "Tough looking walls that have been blasted by sand since the day they were erected. A testament to human willpower." walltype = WALL_SOLARIS /turf/closed/wall/solaris/reinforced + name = "reinforced colony wall" icon_state = "solaris_interior_r" walltype = WALL_SOLARISR damage_cap = HEALTH_WALL_REINFORCED max_temperature = 28000 /turf/closed/wall/solaris/reinforced/hull + name = "heavy reinforced colony wall" icon_state = "solaris_interior_h" hull = 1 @@ -565,7 +571,7 @@ name = "Colony Windbreaker" /turf/closed/wall/solaris/rock - name = "solaris ridge rock wall" + name = "rock wall" icon_state = "solaris_rock" walltype = WALL_SOLARIS_ROCK hull = 1 @@ -700,6 +706,23 @@ var/datum/cause_data/construction_data flags_turf = TURF_ORGANIC +/turf/closed/wall/resin/Initialize(mapload) + . = ..() + + for(var/obj/effect/alien/weeds/node/weed_node in contents) + qdel(weed_node) + + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) + +/turf/closed/wall/resin/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /turf/closed/wall/resin/pillar name = "resin pillar segment" hull = TRUE @@ -1184,6 +1207,11 @@ /turf/closed/wall/resin/attack_hand(mob/user) + if(isxeno(user) && istype(user.get_active_hand(), /obj/item/grab)) + var/obj/item/grab/grab_item_dummy = user.get_active_hand() + var/mob/living/carbon/xenomorph/user_as_xenomorph = user + user_as_xenomorph.do_nesting_host(grab_item_dummy.grabbed_thing, src) + to_chat(user, SPAN_WARNING("You scrape ineffectively at \the [src].")) /turf/closed/wall/resin/attackby(obj/item/W, mob/living/user) diff --git a/code/game/turfs/walls/walls.dm b/code/game/turfs/walls/walls.dm index f6692a32148f..2387a2086192 100644 --- a/code/game/turfs/walls/walls.dm +++ b/code/game/turfs/walls/walls.dm @@ -4,6 +4,7 @@ icon = 'icons/turf/walls/walls.dmi' icon_state = "0" opacity = TRUE + layer = WALL_LAYER var/hull = 0 //1 = Can't be deconstructed by tools or thermite. Used for Sulaco walls var/walltype = WALL_METAL var/junctiontype //when walls smooth with one another, the type of junction each wall is. @@ -83,18 +84,31 @@ shroom.pixel_x = 0 shroom.pixel_y = 0 - for(var/obj/O in src) //Eject contents! - if(istype(O, /obj/structure/sign/poster)) - var/obj/structure/sign/poster/P = O - P.roll_and_drop(src) - if(istype(O, /obj/effect/alien/weeds)) - qdel(O) + for(var/obj/found_object in src) //Eject contents! + if(istype(found_object, /obj/structure/sign/poster)) + var/obj/structure/sign/poster/found_poster = found_object + found_poster.roll_and_drop(src) + if(istype(found_object, /obj/effect/alien/weeds)) + qdel(found_object) + + var/list/turf/cardinal_neighbors = list(get_step(src, NORTH), get_step(src, SOUTH), get_step(src, EAST), get_step(src, WEST)) + for(var/turf/cardinal_turf as anything in cardinal_neighbors) + for(var/obj/structure/bed/nest/found_nest in cardinal_turf) + if(found_nest.dir == get_dir(found_nest, src)) + qdel(found_nest) //nests are built on walls, no walls, no nest + +/turf/closed/wall/MouseDrop_T(mob/current_mob, mob/user) + if(!ismob(current_mob)) + return -/turf/closed/wall/MouseDrop_T(mob/M, mob/user) if(acided_hole) - if(M == user && isxeno(user)) + if(current_mob == user && isxeno(user)) acided_hole.use_wall_hole(user) return + + if(isxeno(user) && istype(user.get_active_hand(), /obj/item/grab)) + var/mob/living/carbon/xenomorph/user_as_xenomorph = user + user_as_xenomorph.do_nesting_host(current_mob, src) ..() /turf/closed/wall/attack_alien(mob/living/carbon/xenomorph/user) @@ -312,7 +326,11 @@ return -/turf/closed/wall/attackby(obj/item/W, mob/user) +/turf/closed/wall/attackby(obj/item/attacking_item, mob/user) + if(isxeno(user) && istype(attacking_item, /obj/item/grab)) + var/obj/item/grab/attacker_grab = attacking_item + var/mob/living/carbon/xenomorph/user_as_xenomorph = user + user_as_xenomorph.do_nesting_host(attacker_grab.grabbed_thing, src) if(!ishuman(user) && !isrobot(user)) to_chat(user, SPAN_WARNING("You don't have the dexterity to do this!")) @@ -320,18 +338,18 @@ //THERMITE related stuff. Calls src.thermitemelt() which handles melting simulated walls and the relevant effects if(thermite) - if(W.heat_source >= 1000) + if(attacking_item.heat_source >= 1000) if(hull) - to_chat(user, SPAN_WARNING("[src] is much too tough for you to do anything to it with [W].")) + to_chat(user, SPAN_WARNING("[src] is much too tough for you to do anything to it with [attacking_item].")) else - if(iswelder(W)) - var/obj/item/tool/weldingtool/WT = W + if(iswelder(attacking_item)) + var/obj/item/tool/weldingtool/WT = attacking_item WT.remove_fuel(0,user) thermitemelt(user) return - if(istype(W, /obj/item/weapon/twohanded/breacher)) - var/obj/item/weapon/twohanded/breacher/current_hammer = W + if(istype(attacking_item, /obj/item/weapon/twohanded/breacher)) + var/obj/item/weapon/twohanded/breacher/current_hammer = attacking_item if(user.action_busy) return if(!(HAS_TRAIT(user, TRAIT_SUPER_STRONG) || !current_hammer.really_heavy)) @@ -353,46 +371,46 @@ take_damage(damage_cap) return - if(istype(W,/obj/item/frame/apc)) - var/obj/item/frame/apc/AH = W + if(istype(attacking_item,/obj/item/frame/apc)) + var/obj/item/frame/apc/AH = attacking_item AH.try_build(src) return - if(istype(W,/obj/item/frame/air_alarm)) - var/obj/item/frame/air_alarm/AH = W + if(istype(attacking_item,/obj/item/frame/air_alarm)) + var/obj/item/frame/air_alarm/AH = attacking_item AH.try_build(src) return - if(istype(W,/obj/item/frame/fire_alarm)) - var/obj/item/frame/fire_alarm/AH = W + if(istype(attacking_item,/obj/item/frame/fire_alarm)) + var/obj/item/frame/fire_alarm/AH = attacking_item AH.try_build(src) return - if(istype(W,/obj/item/frame/light_fixture)) - var/obj/item/frame/light_fixture/AH = W + if(istype(attacking_item,/obj/item/frame/light_fixture)) + var/obj/item/frame/light_fixture/AH = attacking_item AH.try_build(src) return - if(istype(W,/obj/item/frame/light_fixture/small)) - var/obj/item/frame/light_fixture/small/AH = W + if(istype(attacking_item,/obj/item/frame/light_fixture/small)) + var/obj/item/frame/light_fixture/small/AH = attacking_item AH.try_build(src) return //Poster stuff - if(istype(W,/obj/item/poster)) - place_poster(W,user) + if(istype(attacking_item,/obj/item/poster)) + place_poster(attacking_item, user) return - if(istype(W, /obj/item/prop/torch_frame)) + if(istype(attacking_item, /obj/item/prop/torch_frame)) to_chat(user, SPAN_NOTICE("You place the torch down on the wall.")) - new /obj/structure/prop/brazier/torch/frame(src) - qdel(W) + new /obj/structure/prop/brazier/frame/full/torch(src) + qdel(attacking_item) if(hull) - to_chat(user, SPAN_WARNING("[src] is much too tough for you to do anything to it with [W].")) + to_chat(user, SPAN_WARNING("[src] is much too tough for you to do anything to it with [attacking_item].")) return - if(try_weldingtool_usage(W, user) || try_nailgun_usage(W, user)) + if(try_weldingtool_usage(attacking_item, user) || try_nailgun_usage(attacking_item, user)) return if(!istype(src, /turf/closed/wall)) @@ -401,15 +419,15 @@ //DECONSTRUCTION switch(d_state) if(WALL_STATE_WELD) - if(iswelder(W)) - if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH)) + if(iswelder(attacking_item)) + if(!HAS_TRAIT(attacking_item, TRAIT_TOOL_BLOWTORCH)) to_chat(user, SPAN_WARNING("You need a stronger blowtorch!")) return - var/obj/item/tool/weldingtool/WT = W + var/obj/item/tool/weldingtool/WT = attacking_item try_weldingtool_deconstruction(WT, user) if(WALL_STATE_SCREW) - if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER)) user.visible_message(SPAN_NOTICE("[user] begins removing the support lines."), SPAN_NOTICE("You begin removing the support lines.")) playsound(src, 'sound/items/Screwdriver.ogg', 25, 1) @@ -420,7 +438,7 @@ return if(WALL_STATE_WIRECUTTER) - if(HAS_TRAIT(W, TRAIT_TOOL_WIRECUTTERS)) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_WIRECUTTERS)) user.visible_message(SPAN_NOTICE("[user] begins uncrimping the hydraulic lines."), SPAN_NOTICE("You begin uncrimping the hydraulic lines.")) playsound(src, 'sound/items/Wirecutter.ogg', 25, 1) @@ -431,7 +449,7 @@ return if(WALL_STATE_WRENCH) - if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_WRENCH)) user.visible_message(SPAN_NOTICE("[user] starts loosening the anchoring bolts securing the support rods."), SPAN_NOTICE("You start loosening the anchoring bolts securing the support rods.")) playsound(src, 'sound/items/Ratchet.ogg', 25, 1) @@ -442,7 +460,7 @@ return if(WALL_STATE_CROWBAR) - if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_CROWBAR)) user.visible_message(SPAN_NOTICE("[user] struggles to pry apart the connecting rods."), SPAN_NOTICE("You struggle to pry apart the connecting rods.")) playsound(src, 'sound/items/Crowbar.ogg', 25, 1) diff --git a/code/game/verbs/discord.dm b/code/game/verbs/discord.dm new file mode 100644 index 000000000000..210038084caa --- /dev/null +++ b/code/game/verbs/discord.dm @@ -0,0 +1,43 @@ +/client/verb/discord_connect() + set name = "Discord Certify" + set category = "OOC" + + var/total_playtime = get_total_xeno_playtime(skip_cache = TRUE) + get_total_human_playtime(skip_cache = TRUE) + + if(total_playtime < CONFIG_GET(number/certification_minutes)) + to_chat(src, SPAN_ALERTWARNING("You don't have enough minutes - [CONFIG_GET(number/certification_minutes) - total_playtime] remaining.")) + return + + if(!player_data) + load_player_data() + + if(player_data.discord_link) + to_chat(src, SPAN_ALERTWARNING("You already have a linked Discord. Ask an Admin to remove it.")) + return + + var/datum/view_record/discord_identifier/ident = locate() in DB_VIEW(/datum/view_record/discord_identifier, DB_AND( + DB_COMP("playerid", DB_EQUALS, player_data.id), + DB_COMP("realtime", DB_GREATER, world.realtime - 4 HOURS), + DB_COMP("used", DB_EQUALS, FALSE) + )) + + if(ident) + to_chat(src, SPAN_ALERTWARNING("Existing verification within expiry. Opening pop-up.")) + show_browser(src, "Your one time password is [ident.identifier]. Please use [CONFIG_GET(string/bot_prefix)][CONFIG_GET(string/bot_command)] [ident.identifier] to certify.", "One Time Password", "one-time-pass") + return + + var/datum/entity/discord_identifier/new_identifier = DB_ENTITY(/datum/entity/discord_identifier) + + var/not_unique = TRUE + var/long_list = operation_postfixes + operation_prefixes + operation_titles + var/token + + while(not_unique) + token = replacetext(trim("[pick(long_list)]-[pick(long_list)]-[pick(long_list)]-[pick(long_list)]-[pick(long_list)]-[pick(long_list)]"), " ", "") + not_unique = locate(/datum/view_record/discord_identifier) in DB_VIEW(/datum/view_record/discord_identifier, DB_COMP("identifier", DB_EQUALS, token)) + + new_identifier.identifier = token + new_identifier.playerid = player_data.id + new_identifier.save() + + show_browser(src, "Your one time password is [token]. Please use [CONFIG_GET(string/bot_prefix)][CONFIG_GET(string/bot_command)] [token] to certify.", "One Time Password", "one-time-pass") diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index 321ff015f7bc..3c964cf4011b 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -57,24 +57,38 @@ display_colour = CONFIG_GET(string/ooc_color_default) msg = process_chat_markup(msg, list("*")) - + var/ooc_prefix = handle_ooc_prefix() for(var/client/C in GLOB.clients) if(C.prefs.toggles_chat & CHAT_OOC) var/display_name = src.key - if(prefs.unlock_content) - if(prefs.toggle_prefs & TOGGLE_MEMBER_PUBLIC) - var/byond = icon('icons/effects/effects.dmi', "byondlogo") - display_name = "[icon2html(byond, GLOB.clients)][display_name]" - if(CONFIG_GET(flag/ooc_country_flags)) - if(prefs.toggle_prefs & TOGGLE_OOC_FLAG) - display_name = "[country2chaticon(src.country, GLOB.clients)][display_name]" - to_chat(C, "[src.donator ? "\[D\] " : ""]OOC: [display_name]: [msg]") + to_chat(C, "[ooc_prefix]OOC: [display_name]: [msg]") + /client/proc/set_ooc_color_global(newColor as color) set name = "OOC Text Color - Global" set desc = "Set to yellow for eye burning goodness." set category = "OOC.OOC" GLOB.ooc_color_override = newColor +///Used by OOC chat to generate icons for player prefix. Intended to make it easy to see at a glance if someone is staff, WL Council or Mentor. +/client/proc/handle_ooc_prefix() + var/prefix = "" + if(prefs.unlock_content && (prefs.toggle_prefs & TOGGLE_MEMBER_PUBLIC)) + var/byond = icon('icons/effects/effects.dmi', "byondlogo") + prefix += "[icon2html(byond, GLOB.clients)]" + if(CONFIG_GET(flag/ooc_country_flags) && (prefs.toggle_prefs & TOGGLE_OOC_FLAG)) + prefix += "[country2chaticon(src.country, GLOB.clients)]" + if(donator) + prefix += "[icon2html('icons/ooc.dmi', GLOB.clients, "Donator")]" + if(isCouncil(src)) + prefix += "[icon2html('icons/ooc.dmi', GLOB.clients, "WhitelistCouncil")]" + if(admin_holder) + var/list/rank_icons = icon_states('icons/ooc.dmi') + var/rankname = admin_holder.rank + if(rankname in rank_icons) + prefix += "[icon2html('icons/ooc.dmi', GLOB.clients, admin_holder.rank)]" + if(prefix) + prefix = "[prefix] " + return prefix /client/verb/looc(msg as text) set name = "LOOC" //Gave this shit a shorter name so you only have to time out "ooc" rather than "ooc message" to use it --NeoFite @@ -190,17 +204,30 @@ var/view_size = getviewsize(view) var/aspect_ratio = view_size[1] / view_size[2] - // Calculate desired pixel width using window size and aspect ratio - var/sizes = params2list(winget(src, "mainwindow.split;mapwindow", "size")) + var/desired_width = 0 + var/sizes = params2list(winget(src, "mainwindow.split;mapwindow;mainwindow", "size")) var/map_size = splittext(sizes["mapwindow.size"], "x") - var/height = text2num(map_size[2]) - var/desired_width = round(height * aspect_ratio) - if (text2num(map_size[1]) == desired_width) - // Nothing to do - return + + if(prefs.adaptive_zoom) + // If using adaptive zoom, we directly use the intended horizontal map size to be pixel perfect + var/zoom_factor = get_adaptive_zoom_factor() + if(zoom_factor) + desired_width = view_size[1] * world.icon_size * zoom_factor + 4 // 4 pixels margin + + if(!desired_width) + // Calculate desired pixel width using window size and aspect ratio + var/height = text2num(map_size[2]) + desired_width = round(height * aspect_ratio) var/split_size = splittext(sizes["mainwindow.split.size"], "x") var/split_width = text2num(split_size[1]) + // Always leave at least 240px of verb panel for the poor sod to switch back if they made a mistake + if(split_width - desired_width < 240) + desired_width = split_width - 240 + + if (text2num(map_size[1]) == desired_width) + // Nothing to do + return // Calculate and apply a best estimate // +4 pixels are for the width of the splitter's handle diff --git a/code/game/verbs/records.dm b/code/game/verbs/records.dm index 56a440e3558c..f09de72da2e6 100644 --- a/code/game/verbs/records.dm +++ b/code/game/verbs/records.dm @@ -53,7 +53,7 @@ if(NOTE_YAUTJA) color = "#114e11" - dat += "[N.text] by [admin_ckey] ([N.admin_rank]) on [N.date] " + dat += "[N.text] by [admin_ckey] ([N.admin_rank]) on [N.date] [NOTE_ROUND_ID(N)] " dat += "

" dat += "
" @@ -168,7 +168,7 @@ continue var/admin_ckey = N.admin_ckey - dat += "[N.text] by [admin_ckey] ([N.admin_rank]) on [N.date] " + dat += "[N.text] by [admin_ckey] ([N.admin_rank]) on [N.date] [NOTE_ROUND_ID(N)] " ///Can remove notes from anyone other than yourself, unless you're the host. So long as you have deletion access anyway. if((can_del && target != get_player_from_key(key)) || ishost(usr)) dat += "Remove" diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index bb0e53a012cb..8a249d297cbe 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -158,7 +158,7 @@ var/dat = "" var/list/mappings if(CONFIG_GET(flag/show_manager)) - LAZYSET(mappings, "Management", R_HOST) + LAZYSET(mappings, "Management", R_PERMISSIONS) if(CONFIG_GET(flag/show_devs)) LAZYSET(mappings, "Maintainers", R_PROFILER) LAZYSET(mappings, "Admins", R_ADMIN) diff --git a/code/game/world.dm b/code/game/world.dm index 58de4b84b6ae..cff799800a49 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -26,32 +26,19 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt") prof_init() #endif - //logs - var/date_string = time2text(world.realtime, "YYYY/MM-Month/DD-Day") - var/year_string = time2text(world.realtime, "YYYY") - href_logfile = file("data/logs/[date_string] hrefs.htm") - diary = file("data/logs/[date_string].log") - tgui_diary = file("data/logs/[date_string]_tgui.log") - diary << "[log_end]\n[log_end]\nStarting up. [time2text(world.timeofday, "hh:mm.ss")][log_end]\n---------------------[log_end]" - round_stats = file("data/logs/[year_string]/round_stats.log") - round_stats << "[log_end]\nStarting up - [time2text(world.realtime,"YYYY-MM-DD (hh:mm:ss)")][log_end]\n---------------------[log_end]" - round_scheduler_stats = file("data/logs/[year_string]/round_scheduler_stats.log") - round_scheduler_stats << "[log_end]\nStarting up - [time2text(world.realtime,"YYYY-MM-DD (hh:mm:ss)")][log_end]\n---------------------[log_end]" - mutator_logs = file("data/logs/[year_string]/mutator_logs.log") - mutator_logs << "[log_end]\nStarting up - [time2text(world.realtime,"YYYY-MM-DD (hh:mm:ss)")][log_end]\n---------------------[log_end]" + GLOB.config_error_log = GLOB.world_attack_log = GLOB.world_href_log = GLOB.world_attack_log = "data/logs/config_error.[GUID()].log" + + config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER]) + + SSdatabase.start_up() + + SSentity_manager.start_up() + SSentity_manager.setup_round_id() + var/latest_changelog = file("[global.config.directory]/../html/changelogs/archive/" + time2text(world.timeofday, "YYYY-MM") + ".yml") GLOB.changelog_hash = fexists(latest_changelog) ? md5(latest_changelog) : 0 //for telling if the changelog has changed recently - GLOB.revdata = new initialize_tgs() - initialize_marine_armor() - - config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER]) - - runtime_logging_ready = TRUE // Setting up logging now, so disabling early logging - if(CONFIG_GET(flag/log_runtime)) - log = file("data/logs/runtime/[time2text(world.realtime,"YYYY-MM-DD-(hh-mm-ss)")]-runtime.log") - backfill_runtime_log() #ifdef UNIT_TESTS GLOB.test_log = "data/logs/tests.log" @@ -74,7 +61,7 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt") var/testing_locally = (world.params && world.params["local_test"]) var/running_tests = (world.params && world.params["run_tests"]) - #ifdef UNIT_TESTS + #if defined(AUTOWIKI) || defined(UNIT_TESTS) running_tests = TRUE #endif // Only do offline sleeping when the server isn't running unit tests or hosting a local dev test @@ -97,6 +84,10 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt") HandleTestRun() #endif + #ifdef AUTOWIKI + setup_autowiki() + #endif + update_status() //Scramble the coords obsfucator @@ -110,7 +101,7 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt") // If the server's configured for local testing, get everything set up ASAP. // Shamelessly stolen from the test manager's host_tests() proc if(testing_locally) - master_mode = "extended" + master_mode = "Extended" // Wait for the game ticker to initialize while(!SSticker.initialized) @@ -123,6 +114,51 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt") var/world_topic_spam_protect_ip = "0.0.0.0" var/world_topic_spam_protect_time = world.timeofday +/proc/start_logging() + GLOB.round_id = SSentity_manager.round.id + + GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM-Month/DD-Day")]/round-" + + if(GLOB.round_id) + GLOB.log_directory += GLOB.round_id + else + GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]" + + runtime_logging_ready = TRUE // Setting up logging now, so disabling early logging + #ifndef UNIT_TESTS + world.log = file("[GLOB.log_directory]/dd.log") + #endif + backfill_runtime_log() + + GLOB.logger.init_logging() + + GLOB.tgui_log = "[GLOB.log_directory]/tgui.log" + GLOB.world_href_log = "[GLOB.log_directory]/hrefs.log" + GLOB.world_game_log = "[GLOB.log_directory]/game.log" + GLOB.world_attack_log = "[GLOB.log_directory]/attack.log" + GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log" + GLOB.round_stats = "[GLOB.log_directory]/round_stats.log" + GLOB.scheduler_stats = "[GLOB.log_directory]/round_scheduler_stats.log" + GLOB.mutator_logs = "[GLOB.log_directory]/mutator_logs.log" + + start_log(GLOB.tgui_log) + start_log(GLOB.world_href_log) + start_log(GLOB.world_game_log) + start_log(GLOB.world_attack_log) + start_log(GLOB.world_runtime_log) + start_log(GLOB.round_stats) + start_log(GLOB.scheduler_stats) + start_log(GLOB.mutator_logs) + + if(fexists(GLOB.config_error_log)) + fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log") + fdel(GLOB.config_error_log) + + if(GLOB.round_id) + log_game("Round ID: [GLOB.round_id]") + + log_runtime(GLOB.revdata.get_log_message()) + /world/proc/initialize_tgs() TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_TRUSTED) GLOB.revdata.load_tgs_info() @@ -130,73 +166,74 @@ var/world_topic_spam_protect_time = world.timeofday /world/Topic(T, addr, master, key) TGS_TOPIC - if (T == "ping") - var/x = 1 - for (var/client/C) - x++ - return x - - else if(T == "players") - return length(GLOB.clients) - - else if (T == "status") - var/list/s = list() - s["version"] = game_version - s["mode"] = master_mode - s["respawn"] = CONFIG_GET(flag/respawn) - s["enter"] = enter_allowed - s["vote"] = CONFIG_GET(flag/allow_vote_mode) - s["ai"] = CONFIG_GET(flag/allow_ai) - s["host"] = host ? host : null - s["players"] = list() - s["stationtime"] = duration2text() - var/n = 0 - var/admins = 0 - - for(var/client/C in GLOB.clients) - if(C.admin_holder) - if(C.admin_holder.fakekey) - continue //so stealthmins aren't revealed by the hub - admins++ - s["player[n]"] = C.key - n++ - s["players"] = n - - s["admins"] = admins - - return list2params(s) - - // Used in external requests for player data. - else if (T == "pinfo") - var/retdata = "" - if(addr != "127.0.0.1") - return "Nah ah ah, you didn't say the magic word" - for(var/client/C in GLOB.clients) - retdata += C.key+","+C.address+","+C.computer_id+"|" - - return retdata - - else if(copytext(T,1,6) == "notes") - if(addr != "127.0.0.1") - return "Nah ah ah, you didn't say the magic word" - if(!SSdatabase.connection.connection_ready()) - return "Database is not yet ready. Please wait." - var/input[] = params2list(T) - var/ckey = trim(input["ckey"]) - var/dat = "Notes for [ckey]:

" - var/datum/entity/player/P = get_player_from_key(ckey) - if(!P) - return "" - P.load_refs() - if(!P.notes || !P.notes.len) - return dat + "No information found on the given key." - - for(var/datum/entity/player_note/N in P.notes) - var/admin_name = (N.admin && N.admin.ckey) ? "[N.admin.ckey]" : "-LOADING-" - var/ban_text = N.ban_time ? "Banned for [N.ban_time] minutes | " : "" - var/confidential_text = N.is_confidential ? " \[CONFIDENTIALLY\]" : "" - dat += "[ban_text][N.text]
by [admin_name] ([N.admin_rank])[confidential_text] on [N.date]

" - return dat + + var/list/response = list() + + if(length(T) > CONFIG_GET(number/topic_max_size)) + response["statuscode"] = 413 + response["response"] = "Payload too large" + return json_encode(response) + + if(SSfail_to_topic?.IsRateLimited(addr)) + response["statuscode"] = 429 + response["response"] = "Rate limited" + return json_encode(response) + + var/logging = CONFIG_GET(flag/log_world_topic) + var/topic_decoded = rustg_url_decode(T) + if(!rustg_json_is_valid(topic_decoded)) + if(logging) + log_topic("(NON-JSON) \"[topic_decoded]\", from:[addr], master:[master], key:[key]") + // Fallback check for spacestation13.com requests + if(topic_decoded == "ping") + return length(GLOB.clients) + response["statuscode"] = 400 + response["response"] = "Bad Request - Invalid JSON format" + return json_encode(response) + + var/list/params = json_decode(topic_decoded) + params["addr"] = addr + var/query = params["query"] + var/auth = params["auth"] + var/source = params["source"] + + if(logging) + var/list/censored_params = params.Copy() + censored_params["auth"] = "***[copytext(params["auth"], -4)]" + log_topic("\"[json_encode(censored_params)]\", from:[addr], master:[master], auth:[censored_params["auth"]], key:[key], source:[source]") + + if(!source) + response["statuscode"] = 400 + response["response"] = "Bad Request - No source specified" + return json_encode(response) + + if(!query) + response["statuscode"] = 400 + response["response"] = "Bad Request - No endpoint specified" + return json_encode(response) + + if(!LAZYACCESS(GLOB.topic_tokens["[auth]"], "[query]")) + response["statuscode"] = 401 + response["response"] = "Unauthorized - Bad auth" + return json_encode(response) + + var/datum/world_topic/command = GLOB.topic_commands["[query]"] + if(!command) + response["statuscode"] = 501 + response["response"] = "Not Implemented" + return json_encode(response) + + if(command.CheckParams(params)) + response["statuscode"] = command.statuscode + response["response"] = command.response + response["data"] = command.data + return json_encode(response) + else + command.Run(params) + response["statuscode"] = command.statuscode + response["response"] = command.response + response["data"] = command.data + return json_encode(response) /world/Reboot(reason) Master.Shutdown() @@ -215,9 +252,10 @@ var/world_topic_spam_protect_time = world.timeofday return #endif + shutdown_logging() + if(TgsAvailable()) send_tgs_restart() - TgsReboot() TgsEndProcess() else @@ -226,7 +264,7 @@ var/world_topic_spam_protect_time = world.timeofday /world/proc/send_tgs_restart() if(CONFIG_GET(string/new_round_alert_channel) && CONFIG_GET(string/new_round_alert_role_id)) if(round_statistics) - send2chat("[round_statistics.round_name] completed!", CONFIG_GET(string/new_round_alert_channel)) + send2chat("[round_statistics.round_name][GLOB.round_id ? " (Round [GLOB.round_id])" : ""] completed!", CONFIG_GET(string/new_round_alert_channel)) if(SSmapping.next_map_configs) var/datum/map_config/next_map = SSmapping.next_map_configs[GROUND_MAP] if(next_map) @@ -358,8 +396,11 @@ var/datum/BSQL_Connection/connection CRASH("[lib] init error: [init]") /world/proc/HandleTestRun() - //trigger things to run the whole process + // Wait for the game ticker to initialize Master.sleep_offline_after_initializations = FALSE + UNTIL(SSticker.initialized) + + //trigger things to run the whole process SSticker.request_start() CONFIG_SET(number/round_end_countdown, 0) var/datum/callback/cb @@ -389,7 +430,7 @@ var/datum/BSQL_Connection/connection qdel(src) //shut it down -/world/proc/backfill_runtime_log() +/proc/backfill_runtime_log() if(length(full_init_runtimes)) world.log << "========= EARLY RUNTIME ERRORS ========" for(var/line in full_init_runtimes) diff --git a/code/global.dm b/code/global.dm index 642ecb2c13c6..bdde529a9af8 100644 --- a/code/global.dm +++ b/code/global.dm @@ -12,26 +12,27 @@ #define R_POSSESS (1<<5) #define R_PERMISSIONS (1<<6) #define R_STEALTH (1<<7) -#define R_REJUVINATE (1<<8) -#define R_COLOR (1<<9) -#define R_VAREDIT (1<<10) -#define R_SOUNDS (1<<11) -#define R_SPAWN (1<<12) -#define R_MOD (1<<13) -#define R_MENTOR (1<<14) -#define R_HOST (1<<15) -#define R_PROFILER (1<<16) -#define R_NOLOCK (1<<17) -#define R_EVENT (1<<18) - -/// The sum of all other rank permissions. -#define R_EVERYTHING ((1<<19)-1) - +#define R_COLOR (1<<8) +#define R_VAREDIT (1<<9) +#define R_SOUNDS (1<<10) +#define R_SPAWN (1<<11) +#define R_MOD (1<<12) +#define R_MENTOR (1<<13) +#define R_HOST (1<<14) +#define R_PROFILER (1<<15) +#define R_NOLOCK (1<<16) +#define R_EVENT (1<<17) + +/// The sum of all other rank permissions, other than host or profiler. +#define RL_EVERYTHING (R_BUILDMODE|R_ADMIN|R_BAN|R_SERVER|R_DEBUG|R_PERMISSIONS|R_POSSESS|R_STEALTH|R_COLOR|R_VAREDIT|R_EVENT|R_SOUNDS|R_NOLOCK|R_SPAWN|R_MOD|R_MENTOR) +/// Truely everything +#define RL_HOST (RL_EVERYTHING|R_HOST|R_PROFILER) // 512.1430 increases maximum bit flags from 16 to 24, so the following flags should be available for future changes: //================================================= #define CLIENT_HAS_RIGHTS(cli, flags) ((cli?.admin_holder?.rights & flags) == flags) #define CLIENT_IS_STAFF(cli) (cli?.admin_holder?.rights & (R_MOD|R_ADMIN)) +#define CLIENT_IS_MENTOR(cli) CLIENT_HAS_RIGHTS(cli, R_MENTOR) #define AHOLD_IS_MOD(ahold) (ahold && (ahold.rights & R_MOD)) #define AHOLD_IS_ADMIN(ahold) (ahold && (ahold.rights & R_ADMIN)) @@ -45,12 +46,6 @@ var/list/paper_tag_whitelist = list("center","p","div","span","h1","h2","h3","h4 /////////////// -var/diary = null -var/tgui_diary = null -var/round_stats = null -var/round_scheduler_stats = null -var/mutator_logs = null -var/href_logfile = null var/command_name = "Central Command" var/station_name = "[MAIN_SHIP_NAME]" var/game_version = "Colonial Marines" diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 36e70d311ac0..bf6d8e261ab3 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -12,7 +12,7 @@ return //don't recheck connected clients. //Guest Checking - if(IsGuestKey(key)) + if(!real_bans_only && CONFIG_GET(flag/guest_ban) && IsGuestKey(key)) log_access("Failed Login: [key] - Guests not allowed") message_admins("Failed Login: [key] - Guests not allowed") return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.") diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm index 96dcba2ff33c..b64b1e4682fd 100644 --- a/code/modules/admin/NewBan.dm +++ b/code/modules/admin/NewBan.dm @@ -170,9 +170,9 @@ var/savefile/Banlist /datum/admins/proc/unbanpanel() var/dat - var/list/datum/view_record/player_ban_view/PBV = DB_VIEW(/datum/view_record/player_ban_view) // no filter + var/list/datum/view_record/players/PBV = DB_VIEW(/datum/view_record/players, DB_OR(DB_COMP("is_permabanned", DB_EQUALS, 1), DB_COMP("is_time_banned", DB_EQUALS, 1))) // a filter - for(var/datum/view_record/player_ban_view/ban in PBV) + for(var/datum/view_record/players/ban in PBV) var/expiry if(!ban.is_permabanned) expiry = GetExp(ban.expiration) @@ -226,6 +226,9 @@ var/savefile/Banlist RemoveBan(A) /client/proc/cmd_admin_do_ban(mob/M) + if(IsAdminAdvancedProcCall()) + alert_proccall("cmd_admin_do_ban") + return PROC_BLOCKED if(!check_rights(R_BAN|R_MOD)) return if(!ismob(M)) return diff --git a/code/modules/admin/STUI.dm b/code/modules/admin/STUI.dm index df4794d03a45..87a2ca2cf11a 100644 --- a/code/modules/admin/STUI.dm +++ b/code/modules/admin/STUI.dm @@ -88,17 +88,16 @@ GLOBAL_DATUM_INIT(STUI, /datum/STUI, new) if(attack.len > stui_length+1) attack.Cut(,attack.len-stui_length) .["logs"][STUI_TEXT_ATTACK] = attack - if(ooc.len > stui_length+1) - ooc.Cut(,ooc.len-stui_length) - .["logs"][STUI_TEXT_OOC] = ooc - if(user.client.admin_holder.rights & R_ADMIN) if(admin.len > stui_length+1) admin.Cut(,admin.len-stui_length) .["logs"][STUI_TEXT_STAFF] = admin if(staff.len > stui_length+1) staff.Cut(,staff.len-stui_length) .["logs"][STUI_TEXT_STAFF_CHAT] = staff - if((user.client.admin_holder.rights & R_ADMIN) || (user.client.admin_holder.rights & R_DEBUG)) + if(ooc.len > stui_length+1) + ooc.Cut(,ooc.len-stui_length) + .["logs"][STUI_TEXT_OOC] = ooc + if((user.client.admin_holder.rights & R_MOD) || (user.client.admin_holder.rights & R_DEBUG)) if(game.len > stui_length+1) game.Cut(,game.len-stui_length) .["logs"][STUI_TEXT_GAME] = game diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 5f24f71c8a50..2c749df71bb7 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -89,7 +89,7 @@ if(N.is_ban) var/time_d = N.ban_time ? "Banned for [N.ban_time] minutes | " : "" color = "#880000" //Removed confidential check because we can't make confidential bans - dat += "[time_d][N.text] by [admin_ckey] ([N.admin_rank])[confidential_text] on [N.date] " + dat += "[time_d][N.text] by [admin_ckey] ([N.admin_rank])[confidential_text] on [N.date] [NOTE_ROUND_ID(N)] " else if(N.is_confidential) color = "#AA0055" @@ -102,7 +102,7 @@ else if(N.note_category == NOTE_YAUTJA) color = "#114e11" - dat += "[N.text] by [admin_ckey] ([N.admin_rank])[confidential_text] on [N.date] " + dat += "[N.text] by [admin_ckey] ([N.admin_rank])[confidential_text] on [N.date] [NOTE_ROUND_ID(N)] " if(admin_ckey == usr.ckey || admin_ckey == "Adminbot" || ishost(usr)) dat += "Remove" diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index dd67a963047e..cbeb1169c807 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -34,17 +34,17 @@ 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("color") rights |= R_COLOR if("varedit") rights |= R_VAREDIT if("event") rights |= R_EVENT - if("everything","host","all") rights |= (R_HOST|R_BUILDMODE|R_ADMIN|R_BAN|R_SERVER|R_DEBUG|R_PERMISSIONS|R_POSSESS|R_STEALTH|R_REJUVINATE|R_COLOR|R_VAREDIT|R_EVENT|R_SOUNDS|R_NOLOCK|R_SPAWN|R_MOD|R_MENTOR) if("sound","sounds") rights |= R_SOUNDS if("nolock") rights |= R_NOLOCK if("spawn","create") rights |= R_SPAWN if("mod") rights |= R_MOD if("mentor") rights |= R_MENTOR if("profiler") rights |= R_PROFILER + if("host") rights |= RL_HOST + if("everything") rights |= RL_EVERYTHING admin_ranks[rank] = rights previous_rights = rights diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 00f874f27b31..14375288b28d 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -27,7 +27,6 @@ var/list/admin_verbs_default = list( /client/proc/invismin, /client/proc/set_explosive_antigrief, /client/proc/check_explosive_antigrief, - /client/proc/cmd_mod_say, /client/proc/dsay, /client/proc/chem_panel, /*chem panel, allows viewing, editing and creation of reagent and chemical_reaction datums*/ /client/proc/player_panel_new, /*shows an interface for all players, with links to various panels*/ @@ -49,6 +48,7 @@ var/list/admin_verbs_default = list( /client/proc/vehicle_panel, /client/proc/in_view_panel, /*allows application of aheal/sleep in an AOE*/ /client/proc/toggle_lz_resin, + /client/proc/strip_all_in_view, /client/proc/rejuvenate_all_in_view, /client/proc/rejuvenate_all_humans_in_view, /client/proc/rejuvenate_all_revivable_humans_in_view, @@ -66,19 +66,21 @@ var/list/admin_verbs_default = list( /datum/admins/proc/subtlemessageall, /datum/admins/proc/alertall, /datum/admins/proc/imaginary_friend, + /client/proc/toggle_ares_ping, + /client/proc/cmd_admin_say, /*staff-only ooc chat*/ + /client/proc/cmd_mod_say, /* alternate way of typing asay, no different than cmd_admin_say */ ) var/list/admin_verbs_admin = list( /datum/admins/proc/togglejoin, /*toggles whether people can join the current game*/ /datum/admins/proc/announce, /*priority announce something to all clients.*/ - /datum/admins/proc/view_txt_log, /*shows the server log (diary) for today*/ + /datum/admins/proc/view_game_log, /*shows the server game log (diary) for this round*/ + /datum/admins/proc/view_attack_log, /*shows the server attack log for this round*/ + /client/proc/giveruntimelog, /*allows us to give access to all runtime logs to somebody*/ /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ - /client/proc/giveruntimelog, /*allows us to give access to runtime logs to somebody*/ - /client/proc/getserverlog, /*allows us to fetch server logs (diary) for other days*/ /client/proc/toggleprayers, /*toggles prayers on/off*/ /client/proc/toggle_hear_radio, /*toggles whether we hear the radio*/ /client/proc/event_panel, - /client/proc/cmd_admin_say, /*admin-only ooc chat*/ /client/proc/free_slot, /*frees slot for chosen job*/ /client/proc/modify_slot, /client/proc/cmd_admin_rejuvenate, @@ -90,10 +92,12 @@ var/list/admin_verbs_admin = list( /client/proc/matrix_editor, /datum/admins/proc/open_shuttlepanel ) + var/list/admin_verbs_ban = list( /client/proc/unban_panel // /client/proc/jobbans // Disabled temporarily due to 15-30 second lag spikes. Don't forget the comma in the line above when uncommenting this! ) + var/list/admin_verbs_sounds = list( /client/proc/play_web_sound, /client/proc/play_sound, @@ -101,11 +105,12 @@ var/list/admin_verbs_sounds = list( /client/proc/stop_sound, /client/proc/cmd_admin_vox_panel ) + var/list/admin_verbs_minor_event = list( /client/proc/cmd_admin_change_custom_event, /datum/admins/proc/admin_force_distress, /datum/admins/proc/admin_force_ERT_shuttle, - /client/proc/force_shuttle, + /client/proc/force_hijack, /datum/admins/proc/force_predator_round, //Force spawns a predator round. /client/proc/adjust_predator_round, /client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/ @@ -116,6 +121,7 @@ var/list/admin_verbs_minor_event = list( /client/proc/toggle_sniper_upgrade, /client/proc/toggle_attack_dead, /client/proc/toggle_strip_drag, + /client/proc/toggle_disposal_mobs, /client/proc/toggle_uniform_strip, /client/proc/toggle_strong_defibs, /client/proc/toggle_blood_optimization, @@ -127,7 +133,12 @@ var/list/admin_verbs_minor_event = list( /client/proc/toggle_shipside_sd, /datum/admins/proc/round_traits_panel, /client/proc/shakeshipverb, + /client/proc/shakeshipverb, + /client/proc/adminpanelweapons, + /client/proc/adminpanelgq, + /client/proc/toggle_hardcore_perma ) + var/list/admin_verbs_major_event = list( /client/proc/enable_event_mob_verbs, /client/proc/cmd_admin_dress_all, @@ -145,14 +156,17 @@ var/list/admin_verbs_major_event = list( /client/proc/map_template_upload, /client/proc/enable_podlauncher, /client/proc/change_taskbar_icon, - /client/proc/change_weather + /client/proc/change_weather, + /client/proc/admin_blurb ) + var/list/admin_verbs_spawn = list( /datum/admins/proc/spawn_atom, /client/proc/game_panel, /client/proc/create_humans, /client/proc/create_xenos ) + var/list/admin_verbs_server = list( /datum/admins/proc/startnow, /datum/admins/proc/restart, @@ -162,13 +176,14 @@ var/list/admin_verbs_server = list( /datum/admins/proc/change_ground_map, /datum/admins/proc/change_ship_map, /datum/admins/proc/vote_ground_map, + /datum/admins/proc/override_ground_map, /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_debug_del_all, /datum/admins/proc/togglejoin, - /datum/admins/proc/view_txt_log + /client/proc/toggle_cdn, ) + var/list/admin_verbs_debug = list( - /client/proc/getruntimelog, /*allows us to access runtime logs to somebody*/ /client/proc/debug_role_authority, /client/proc/cmd_debug_make_powernets, /client/proc/cmd_debug_list_processing_items, @@ -179,6 +194,7 @@ var/list/admin_verbs_debug = list( /client/proc/restart_controller, /client/proc/debug_controller, /client/proc/cmd_debug_toggle_should_check_for_win, + /client/proc/cmd_debug_mass_screenshot, /client/proc/enable_debug_verbs, /client/proc/toggledebuglogs, /client/proc/togglenichelogs, @@ -192,6 +208,13 @@ var/list/admin_verbs_debug = list( /client/proc/enter_tree, /client/proc/set_tree_points, /client/proc/purge_data_tab, + /client/proc/getserverlog, /*allows us to fetch any server logs (diary) for other days*/ + /client/proc/getruntimelog, /*allows us to access any runtime logs (can be granted by giveruntimelog)*/ + /datum/admins/proc/view_game_log, /*shows the server game log (diary) for this round*/ + /datum/admins/proc/view_runtime_log, /*shows the server runtime log for this round*/ + /datum/admins/proc/view_href_log, /*shows the server HREF log for this round*/ + /datum/admins/proc/view_tgui_log, /*shows the server TGUI log for this round*/ + /client/proc/admin_blurb, ) var/list/admin_verbs_debug_advanced = list( @@ -219,9 +242,11 @@ var/list/admin_verbs_possess = list( /client/proc/possess, /client/proc/release ) + var/list/admin_verbs_permissions = list( /client/proc/ToRban ) + var/list/admin_verbs_color = list( /client/proc/set_ooc_color_self ) @@ -321,7 +346,7 @@ var/list/roundstart_mod_verbs = list( add_verb(src, clan_verbs) /client/proc/add_admin_whitelists() - if(CLIENT_HAS_RIGHTS(src, R_MENTOR)) + if(CLIENT_IS_MENTOR(src)) RoleAuthority.roles_whitelist[ckey] |= WHITELIST_MENTOR if(CLIENT_IS_STAFF(src)) RoleAuthority.roles_whitelist[ckey] |= WHITELIST_JOE @@ -554,9 +579,23 @@ var/list/roundstart_mod_verbs = list( set desc = "Tells everyone about a random statistic in the round." set category = "OOC" + var/prompt = tgui_alert(usr, "Are you sure you want to do this?", "Announce Random Fact", list("No", "Yes")) + if(prompt != "Yes") + return + message_admins("[key_name(usr)] announced a random fact.") SSticker.mode?.declare_fun_facts() +/client/proc/toggle_ares_ping() + set name = "Toggle ARES notification sound" + set category = "Preferences.Logs" + + prefs.toggles_sound ^= SOUND_ARES_MESSAGE + if (prefs.toggles_sound & SOUND_ARES_MESSAGE) + to_chat(usr, SPAN_BOLDNOTICE("You will now hear a ping for ARES messages.")) + else + to_chat(usr, SPAN_BOLDNOTICE("You will no longer hear a ping for ARES messages.")) + #undef MAX_WARNS #undef AUTOBANTIME diff --git a/code/modules/admin/autoreply.dm b/code/modules/admin/autoreply.dm index c83f4c6f4d14..a90e21b7f311 100644 --- a/code/modules/admin/autoreply.dm +++ b/code/modules/admin/autoreply.dm @@ -37,3 +37,12 @@ GLOBAL_REFERENCE_LIST_INDEXED(adminreplies, /datum/autoreply/admin, title) /datum/autoreply/admin/intended title = "Intended" message = "This is an intended feature and therefore does not need admin intervention." + +/datum/autoreply/admin/event + title = "Event" + message = "There is currently a special event running and many things may be changed or different, however normal rules still apply unless you have been specifically instructed otherwise by a staff member." + +/datum/autoreply/admin/whitelist + title = "Whitelist Issue" + message = "Staff are unable to handle most whitelist rulebreaks in-game, please make a player report on the forums, here." + diff --git a/code/modules/admin/callproc.dm b/code/modules/admin/callproc.dm index f84121785360..1af1f5aa9fa3 100644 --- a/code/modules/admin/callproc.dm +++ b/code/modules/admin/callproc.dm @@ -72,7 +72,8 @@ GLOBAL_PROTECT(LastAdminCalledProc) */ /proc/HandleUserlessProcCall(user, datum/target, procname, list/arguments) if(IsAdminAdvancedProcCall()) - return + alert_proccall("HandleUserlessProcCall") + return PROC_BLOCKED var/mob/proccall_handler/handler = GLOB.AdminProcCallHandler handler.add_caller(user) var/lastusr = usr @@ -90,7 +91,8 @@ GLOBAL_PROTECT(LastAdminCalledProc) */ /proc/HandleUserlessSDQL(user, query_text) if(IsAdminAdvancedProcCall()) - return + alert_proccall("HandleUserlessSDQL") + return PROC_BLOCKED var/mob/proccall_handler/handler = GLOB.AdminProcCallHandler handler.add_caller(user) @@ -224,6 +226,10 @@ GLOBAL_PROTECT(LastAdminCalledProc) /proc/IsAdminAdvancedProcCall() return (GLOB.AdminProcCaller && GLOB.AdminProcCaller == usr?.client?.ckey) || (GLOB.AdminProcCallHandler && usr == GLOB.AdminProcCallHandler) +/proc/alert_proccall(procname = "Unknown") + to_chat(usr, SPAN_BOLDWARNING("Warning: Force attempt has been logged.")) + message_admins("[key_name(usr)] has attempted to execute a restricted proc. ([procname])") + /client/proc/callproc_datum(datum/called_datum as null|area|mob|obj|turf) set category = "Debug" set name = "Datum ProcCall" diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index a119d4c0519f..e7559f3aa4fd 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -129,15 +129,18 @@ you will have to do something like if(client.admin_holder.rights & R_ADMIN) your return 0 /client/proc/deadmin() + if(IsAdminAdvancedProcCall()) + alert_proccall("deadmin") + return PROC_BLOCKED if(admin_holder) admin_holder.disassociate() QDEL_NULL(admin_holder) - return 1 + return TRUE /client/proc/readmin() if(admin_datums[ckey]) admin_datums[ckey].associate(src) - return 1 + return TRUE /datum/admins/proc/check_for_rights(rights_required) if(rights_required && !(rights_required & rights)) diff --git a/code/modules/admin/medal_panel/medals_panel_tgui.dm b/code/modules/admin/medal_panel/medals_panel_tgui.dm index ee8728670544..49c4bb5f96ad 100644 --- a/code/modules/admin/medal_panel/medals_panel_tgui.dm +++ b/code/modules/admin/medal_panel/medals_panel_tgui.dm @@ -19,22 +19,22 @@ GLOBAL_DATUM_INIT(medals_panel, /datum/medals_panel_tgui, new) var/list/xeno_awards = list() var/list/uscm_award_ckeys = list() var/list/xeno_award_ckeys = list() - + // Break the medals up by recipient and then pack each medal into a string for(var/recipient_name as anything in GLOB.medal_awards) var/datum/recipient_awards/recipient_award = GLOB.medal_awards[recipient_name] uscm_awards[recipient_name] = list() uscm_award_ckeys[recipient_name] = recipient_award.recipient_ckey ? " ([recipient_award.recipient_ckey])" : "" for(var/i in 1 to recipient_award.medal_names.len) // We're assuming everything is same length - uscm_awards[recipient_name] += "[recipient_award.medal_names[i]]: \'[recipient_award.medal_citations[i]]\' by [recipient_award.giver_rank[i]] [recipient_award.giver_name[i]]." - + uscm_awards[recipient_name] += "[recipient_award.medal_names[i]]: \'[recipient_award.medal_citations[i]]\' by [recipient_award.giver_rank[i] ? "[recipient_award.giver_rank[i]] " : ""][recipient_award.giver_name[i] ? "[recipient_award.giver_name[i]] " : ""]([recipient_award.giver_ckey[i]])." + for(var/recipient_name as anything in GLOB.jelly_awards) var/datum/recipient_awards/recipient_award = GLOB.jelly_awards[recipient_name] xeno_awards[recipient_name] = list() xeno_award_ckeys[recipient_name] = recipient_award.recipient_ckey ? " ([recipient_award.recipient_ckey])" : "" for(var/i in 1 to recipient_award.medal_names.len) // We're assuming everything is same length - xeno_awards[recipient_name] += "[recipient_award.medal_names[i]]: \'[recipient_award.medal_citations[i]]\'[recipient_award.giver_rank[i] ? " by [recipient_award.giver_rank[i]]" : ""][recipient_award.giver_name[i] ? " ([recipient_award.giver_name[i]])" : ""]." - + xeno_awards[recipient_name] += "[recipient_award.medal_names[i]]: \'[recipient_award.medal_citations[i]]\' by [recipient_award.giver_rank[i] ? "[recipient_award.giver_rank[i]] " : ""][recipient_award.giver_name[i] ? "[recipient_award.giver_name[i]] " : ""]([recipient_award.giver_ckey[i]])." + data["uscm_awards"] = uscm_awards data["xeno_awards"] = xeno_awards data["uscm_award_ckeys"] = uscm_award_ckeys @@ -61,8 +61,8 @@ GLOBAL_DATUM_INIT(medals_panel, /datum/medals_panel_tgui, new) if("delete_medal") remove_award(params["recipient"], TRUE, params["index"] + 1) // Why is byond not 0 indexed? return TRUE - + if("delete_jelly") - remove_award(params["recipient"], FALSE, params["index"] + 1) // Why is byond not 0 indexed? + remove_award(params["recipient"], FALSE, params["index"] + 1) // Why is byond not 0 indexed? return TRUE - + diff --git a/code/modules/admin/player_panel/actions/physical.dm b/code/modules/admin/player_panel/actions/physical.dm index e1dd680c43c8..a48f39e81a5e 100644 --- a/code/modules/admin/player_panel/actions/physical.dm +++ b/code/modules/admin/player_panel/actions/physical.dm @@ -180,11 +180,15 @@ permissions_required = R_SPAWN /datum/player_action/strip_equipment/act(client/user, mob/target, list/params) - for (var/obj/item/I in target) + for (var/obj/item/current_item in target) + if(istype(current_item, /obj/item/card/id)) + continue + if(params["drop_items"]) - target.drop_inv_item_to_loc(I, target.loc, FALSE, TRUE) - else - qdel(I) + target.drop_inv_item_to_loc(current_item, target.loc, FALSE, TRUE) + continue + + qdel(current_item) message_admins("[key_name_admin(user)] stripped [target] of their items.") return TRUE diff --git a/code/modules/admin/player_panel/actions/transform.dm b/code/modules/admin/player_panel/actions/transform.dm index 11dd7525bb07..91a62b1a1d02 100644 --- a/code/modules/admin/player_panel/actions/transform.dm +++ b/code/modules/admin/player_panel/actions/transform.dm @@ -38,6 +38,11 @@ GLOBAL_LIST_INIT(pp_transformables, list( name = "Facehugger", key = /mob/living/carbon/xenomorph/facehugger, color = "purple" + ), + list( + name = "Lesser Drone", + key = /mob/living/carbon/xenomorph/lesser_drone, + color = "purple" ) ), @@ -122,7 +127,7 @@ GLOBAL_LIST_INIT(pp_transformables, list( "Alien Tier 4" = list( list( - name = XENO_CASTE_QUEEN+" (Young)", + name = XENO_CASTE_QUEEN+" (Immature)", key = /mob/living/carbon/xenomorph/queen, color = "purple" ), diff --git a/code/modules/admin/server_verbs.dm b/code/modules/admin/server_verbs.dm index 0d35bd084196..47a60c043741 100644 --- a/code/modules/admin/server_verbs.dm +++ b/code/modules/admin/server_verbs.dm @@ -50,6 +50,42 @@ log_admin("[key_name(usr)] started a groundmap vote.") message_admins("[key_name_admin(usr)] started a groundmap vote.") +/datum/admins/proc/override_ground_map() + set category = "Server" + set name = "M: Override Next Map" + + if(!check_rights(R_SERVER)) + return + + var/map_type = tgui_alert(usr, "Override Ship or Ground Map?", "Map selection", list(GROUND_MAP, SHIP_MAP, "Cancel")) + if(map_type == "Cancel") + return + + var/map = input(usr, "Choose a custom map to run for next round","Upload Map") as null|file + if(!map) + return + if(copytext("[map]", -4) != ".dmm")//4 == length(".dmm") + to_chat(usr, SPAN_WARNING("Filename must end in '.dmm': [map]"), confidential = TRUE) + return + + message_admins(SPAN_ADMINNOTICE("[key_name_admin(usr)] is overriding the next '[map_type]' map with a custom one.")) + fcopy(map, "data/[OVERRIDE_MAPS_TO_FILENAME[map_type]]") + if(tgui_alert(usr, "Do you want to upload a custom map config or use defaults? Config controls things like survivors and monkey types, camouflages, lore messages, map items, nightmare, special environmental features...", "Map Config Flavor", list("Default", "Override")) == "Override") + tgui_alert(usr, "Choose the custom map configuration for next round. Make sure it's VALID. It MUST have \"override_map\":true !", "Warning", list("OK!")) + var/map_config = input(usr, "Choose custom map configuration to upload", "Upload Map Config") as null|file + if(map_config) + var/parse_check = json_decode(file2text(map_config)) + if(parse_check && parse_check["override_map"]) + fcopy(map_config, MAP_TO_FILENAME[map_type]) + tgui_alert(usr, "Done, using uploaded map_config. ALWAYS check at start of round that the map loaded correctly when using this. Passing a map vote or changing it with verb vote will revert these changes. Good luck!", "One little thing...", list("OK")) + message_admins(SPAN_ADMINNOTICE("[key_name_admin(usr)] overrode next '[map_type]' map with '[map]' and '[map_config]' for settings.")) + return + to_chat(usr, SPAN_ADMINNOTICE("Couldn't retrieve map_config file or it was invalid, using default config.")) + + fcopy(OVERRIDE_DEFAULT_MAP_CONFIG[map_type], MAP_TO_FILENAME[map_type]) + tgui_alert(usr, "Done, using default map_config ('Unknown' map). ALWAYS check at start of round that the map loaded correctly when using this. Passing a map vote or changing it with verb vote will revert these changes. Good luck!", "One little thing...", list("OK")) + message_admins(SPAN_ADMINNOTICE("[key_name_admin(usr)] overrode next '[map_type]' map with '[map]' and default settings.")) + /datum/admins/proc/change_ship_map() set category = "Server" set name = "M: Change Ship Map" diff --git a/code/modules/admin/tabs/admin_tab.dm b/code/modules/admin/tabs/admin_tab.dm index 697208064c15..1298d6150036 100644 --- a/code/modules/admin/tabs/admin_tab.dm +++ b/code/modules/admin/tabs/admin_tab.dm @@ -169,12 +169,12 @@ if(N.is_ban) var/ban_text = N.ban_time ? "Banned for [N.ban_time] | " : "" color = "#880000" - dat += "[ban_text][N.text] by [admin_ckey] ([N.admin_rank])[confidential_text] on [N.date] " + dat += "[ban_text][N.text] by [admin_ckey] ([N.admin_rank])[confidential_text] on [N.date] [NOTE_ROUND_ID(N)] " else if(N.is_confidential) color = "#AA0055" - dat += "[N.text] by [admin_ckey] ([N.admin_rank])[confidential_text] on [N.date] " + dat += "[N.text] by [admin_ckey] ([N.admin_rank])[confidential_text] on [N.date] [NOTE_ROUND_ID(N)] " dat += "

" dat += "
" @@ -218,29 +218,52 @@ message_admins("[key_name(usr)] used Toggle Wake In View.") +/client/proc/cmd_mod_say(msg as text) + set name = "Msay" // This exists for ease of admins who were used to using msay instead of asay + set category = "Admin" + set hidden = TRUE + + cmd_admin_say(msg) + /client/proc/cmd_admin_say(msg as text) set name = "Asay" //Gave this shit a shorter name so you only have to time out "asay" rather than "admin say" to use it --NeoFite set category = "Admin" set hidden = TRUE - if(!check_rights(R_ADMIN)) + if(!check_rights(R_ADMIN|R_MOD)) return msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN) - if(!msg) + + if (!msg) return - log_adminpm("ADMIN : [key_name(src)] : [msg]") + REDIS_PUBLISH("byond.asay", "author" = src.key, "message" = strip_html(msg), "admin" = CLIENT_HAS_RIGHTS(src, R_ADMIN), "rank" = admin_holder.rank) - var/color = "adminsay" - if(ishost(usr)) - color = "headminsay" + if(findtext(msg, "@") || findtext(msg, "#")) + var/list/link_results = check_asay_links(msg) + if(length(link_results)) + msg = link_results[ASAY_LINK_NEW_MESSAGE_INDEX] + link_results[ASAY_LINK_NEW_MESSAGE_INDEX] = null + var/list/pinged_admin_clients = link_results[ASAY_LINK_PINGED_ADMINS_INDEX] + for(var/iter_ckey in pinged_admin_clients) + var/client/iter_admin_client = pinged_admin_clients[iter_ckey] + if(!iter_admin_client?.admin_holder) + continue + window_flash(iter_admin_client) + SEND_SOUND(iter_admin_client.mob, sound('sound/misc/asay_ping.ogg')) + + log_adminpm("ADMIN: [key_name(src)] : [msg]") - if(check_rights(R_ADMIN,0)) - msg = "ADMIN: [key_name(usr, 1)] (JMP): [msg]" - for(var/client/C in GLOB.admins) - if(R_ADMIN & C.admin_holder.rights) - to_chat(C, msg) + var/color = "mod" + if(check_rights(R_PERMISSIONS, show_msg = FALSE)) + color = "adminmod" + + var/channel = "ADMIN:" + channel = "[admin_holder.rank]:" + for(var/client/client as anything in GLOB.admins) + if((R_ADMIN|R_MOD) & client.admin_holder.rights) + to_chat(client, "[channel] [key_name(src,1)] [ADMIN_JMP_USER(mob)]: [msg]") /datum/admins/proc/alertall() set name = "Alert All" @@ -316,7 +339,7 @@ else if(mob.get_type_in_ears(/obj/item/device/radio/headset)) to_chat(mob, message) - message_admins("[key_name(usr)] used Subtle Message All In View from [message_option], saying \"[input]\".") + message_admins(SPAN_STAFF_IC("[key_name(usr)] used Subtle Message All In View from [message_option], saying \"[input]\".")) #undef SUBTLE_MESSAGE_IN_HEAD #undef SUBTLE_MESSAGE_WEYLAND @@ -327,48 +350,6 @@ var/msg = input(src, null, "asay \"text\"") as text|null cmd_admin_say(msg) -/client/proc/cmd_mod_say(msg as text) - set name = "Msay" - set category = "Admin" - set hidden = TRUE - - if(!check_rights(R_ADMIN|R_MOD)) - return - - msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN) - - if (!msg) - return - - if(findtext(msg, "@") || findtext(msg, "#")) - var/list/link_results = check_asay_links(msg) - if(length(link_results)) - msg = link_results[ASAY_LINK_NEW_MESSAGE_INDEX] - link_results[ASAY_LINK_NEW_MESSAGE_INDEX] = null - var/list/pinged_admin_clients = link_results[ASAY_LINK_PINGED_ADMINS_INDEX] - for(var/iter_ckey in pinged_admin_clients) - var/client/iter_admin_client = pinged_admin_clients[iter_ckey] - if(!iter_admin_client?.admin_holder) - continue - window_flash(iter_admin_client) - SEND_SOUND(iter_admin_client.mob, sound('sound/misc/asay_ping.ogg')) - - log_adminpm("MOD: [key_name(src)] : [msg]") - - var/color = "mod" - if (check_rights(R_ADMIN,0)) - color = "adminmod" - - var/channel = "MOD:" - channel = "[admin_holder.rank]:" - for(var/client/C in GLOB.admins) - if((R_ADMIN|R_MOD) & C.admin_holder.rights) - to_chat(C, "[channel] [key_name(src,1)] (JMP): [msg]") - -/client/proc/get_mod_say() - var/msg = input(src, null, "msay \"text\"") as text|null - cmd_mod_say(msg) - /client/proc/cmd_mentor_say(msg as text) set name = "MentorSay" set category = "OOC" @@ -418,6 +399,33 @@ remove_verb(src, admin_verbs_hideable) add_verb(src, /client/proc/enable_admin_verbs) +/client/proc/strip_all_in_view() + set name = "Strip All" + set category = "Admin.InView" + set hidden = TRUE + + if(!admin_holder || !(admin_holder.rights & R_MOD)) + to_chat(src, "Only administrators may use this command.") + return + + if(tgui_alert(src, "This will strip ALL mobs within your view range. Are you sure?", "Confirmation", list("Yes", "Cancel")) != "Yes") + return + + var/strip_self = FALSE + if(tgui_alert(src, "Do you want to strip yourself as well?", "Confirmation", list("Yes", "No")) == "Yes") + strip_self = TRUE + + for(var/mob/living/current_mob in view()) + if(!strip_self && usr == current_mob) + continue + for (var/obj/item/current_item in current_mob) + //no more deletion of ID cards + if(istype(current_item, /obj/item/card/id)) + continue + qdel(current_item) + + message_admins(WRAP_STAFF_LOG(usr, "stripped everyone in [get_area(usr)] ([usr.x],[usr.y],[usr.z])."), usr.x, usr.y, usr.z) + /client/proc/rejuvenate_all_in_view() set name = "Rejuvenate All" set category = "Admin.InView" @@ -572,6 +580,8 @@ Alert Message In View
Subtle Message In View

+ Strip All Mobs In View
+
"} show_browser(usr, dat, "In View Panel", "inviews") @@ -648,10 +658,14 @@ /proc/set_lz_resin_allowed(allowed = TRUE) if(allowed) for(var/area/A in all_areas) + if(A.flags_area & AREA_UNWEEDABLE) + continue A.is_resin_allowed = TRUE msg_admin_niche("Areas close to landing zones are now weedable.") else for(var/area/A in all_areas) + if(A.flags_area & AREA_UNWEEDABLE) + continue A.is_resin_allowed = initial(A.is_resin_allowed) msg_admin_niche("Areas close to landing zones cannot be weeded now.") GLOB.resin_lz_allowed = allowed @@ -694,6 +708,20 @@ SSticker.mode.toggleable_flags ^= MODE_NO_ATTACK_DEAD message_admins("[src] has [MODE_HAS_TOGGLEABLE_FLAG(MODE_NO_ATTACK_DEAD) ? "prevented dead mobs from being" : "allowed dead mobs to be"] attacked.") +/client/proc/toggle_disposal_mobs() + set name = "Toggle Disposable Mobs" + set category = "Admin.Flags" + + if(!admin_holder || !check_rights(R_EVENT, FALSE)) + return + + if(!SSticker.mode) + to_chat(usr, SPAN_WARNING("A mode hasn't been selected yet!")) + return + + SSticker.mode.toggleable_flags ^= MODE_DISPOSABLE_MOBS + message_admins("[src] has [MODE_HAS_TOGGLEABLE_FLAG(MODE_DISPOSABLE_MOBS) ? "allowed mobs to fit" : "prevented mobs fitting"] inside disposals.") + /client/proc/toggle_strip_drag() set name = "Toggle Strip/Drag Dead" set category = "Admin.Flags" @@ -793,3 +821,21 @@ SSticker.mode.toggleable_flags ^= MODE_SHIPSIDE_SD message_admins("[src] has [MODE_HAS_TOGGLEABLE_FLAG(MODE_SHIPSIDE_SD) ? "toggled SD protection off, Yautja can now big self destruct anywhere" : "toggled SD protection on, Yautja can now only big self destruct on the hunting grounds"].") + +/client/proc/toggle_hardcore_perma() + set name = "Toggle Hardcore" + set category = "Admin.Flags" + + if(!admin_holder || !check_rights(R_MOD, FALSE)) + return + + if(!SSticker.mode) + to_chat(usr, SPAN_WARNING("A mode hasn't been selected yet!")) + return + + if(!MODE_HAS_TOGGLEABLE_FLAG(MODE_HARDCORE_PERMA) && tgui_alert(usr, "Are you sure you want to toggle Hardcore mode on? This will cause all humans to instantly go perma on death.", "Confirmation", list("Yes", "Cancel")) != "Yes") + return + + SSticker.mode.toggleable_flags ^= MODE_HARDCORE_PERMA + message_admins("[src] has toggled Hardcore [MODE_HAS_TOGGLEABLE_FLAG(MODE_HARDCORE_PERMA) ? "on, causing all humans to instantly go perma on death" : "off, causing all humans to die like normal"].") + diff --git a/code/modules/admin/tabs/event_tab.dm b/code/modules/admin/tabs/event_tab.dm index 3d0c8eaf9748..32eaeb674b8d 100644 --- a/code/modules/admin/tabs/event_tab.dm +++ b/code/modules/admin/tabs/event_tab.dm @@ -218,21 +218,22 @@ if(!istype(chosen_ert)) return - var/is_announcing = TRUE - switch(alert(src, "Would you like to announce the distress beacon to the server population? This will reveal the distress beacon to all players.", "Announce distress beacon?", "Yes", "No", "Cancel")) - if("Cancel") - qdel(chosen_ert) - return - if("No") - is_announcing = FALSE + var/is_announcing = tgui_alert(usr, "Would you like to announce the distress beacon to the server population? This will reveal the distress beacon to all players.", "Announce distress beacon?", list("Yes", "No"), 20 SECONDS) + if(!is_announcing) + qdel(chosen_ert) + return + if(is_announcing == "No") + is_announcing = FALSE + if (is_announcing == "Yes") + is_announcing = TRUE var/turf/override_spawn_loc - switch(alert(usr, "Spawn at their assigned spawnpoints, or at your location?", "Spawnpoint Selection", "Assigned Spawnpoint", "Current Location", "Cancel")) - if("Cancel") - qdel(chosen_ert) - return - if("Current Location") - override_spawn_loc = get_turf(usr) + var/prompt = tgui_alert(usr, "Spawn at their assigned spawn, or at your location?", "Spawnpoint Selection", list("Spawn", "Current Location"), 0) + if(!prompt) + qdel(chosen_ert) + return + if(prompt == "Current Location") + override_spawn_loc = get_turf(usr) chosen_ert.activate(is_announcing, override_spawn_loc) @@ -349,7 +350,7 @@ if("CMB") var/body = "" - + for(var/text in GLOB.CMBFaxes) body += text body += "

" @@ -386,7 +387,7 @@ var/datum/hive_status/hive for(var/hivenumber in GLOB.hive_datum) hive = GLOB.hive_datum[hivenumber] - if(hive.totalXenos.len > 0 || hive.totalDeadXenos.len > 0) + if(hive.totalXenos.len > 0 || hive.total_dead_xenos.len > 0) hives += list("[hive.name]" = hive.hivenumber) last_hive_checked = hive @@ -402,6 +403,29 @@ give_jelly_award(last_hive_checked, as_admin=TRUE) +/client/proc/give_nuke() + if(!check_rights(R_ADMIN)) + return + var/nuketype = "Decrypted Operational Nuke" + var/encrypt = tgui_alert(src, "Do you want the nuke to be already decrypted?", "Nuke Type", list("Encrypted", "Decrypted"), 20 SECONDS) + if(encrypt == "Encrypted") + nuketype = "Encrypted Operational Nuke" + var/prompt = tgui_alert(src, "THIS CAN BE USED TO END THE ROUND. Are you sure you want to spawn a nuke? The nuke will be put onto the ASRS Lift.", "DEFCON 1", list("No", "Yes"), 30 SECONDS) + if(prompt != "Yes") + return + + var/datum/supply_order/new_order = new() + new_order.ordernum = supply_controller.ordernum + supply_controller.ordernum++ + new_order.object = supply_controller.supply_packs[nuketype] + new_order.orderedby = MAIN_AI_SYSTEM + new_order.approvedby = MAIN_AI_SYSTEM + supply_controller.shoppinglist += new_order + + marine_announcement("A nuclear device has been supplied and will be delivered to requisitions via ASRS.", "NUCLEAR ARSENAL ACQUIRED", 'sound/misc/notice2.ogg') + message_admins("[key_name_admin(usr)] admin-spawned a [encrypt] nuke.") + log_game("[key_name_admin(usr)] admin-spawned a [encrypt] nuke.") + /client/proc/turn_everyone_into_primitives() var/random_names = FALSE if (alert(src, "Do you want to give everyone random numbered names?", "Confirmation", "Yes", "No") == "Yes") @@ -423,32 +447,28 @@ message_admins("Admin [key_name(usr)] has turned everyone into a primitive") -/client/proc/force_shuttle() - set name = "Force Dropship" - set desc = "Force a dropship to launch" +/client/proc/force_hijack() + set name = "Force Hijack" + set desc = "Force a dropship to be hijacked" set category = "Admin.Shuttles" var/list/shuttles = list(DROPSHIP_ALAMO, DROPSHIP_NORMANDY) - var/tag = tgui_input_list(usr, "Which dropship should be force launched?", "Select a dropship:", shuttles) + var/tag = tgui_input_list(usr, "Which dropship should be force hijacked?", "Select a dropship:", shuttles) if(!tag) return - var/crash = 0 - switch(tgui_input_list(usr, "Would you like to force a crash?", "Force crash", list("Yes", "No"))) - if("Yes") crash = 1 - if("No") crash = 0 - else return var/obj/docking_port/mobile/marine_dropship/dropship = SSshuttle.getShuttle(tag) if(!dropship) - to_chat(src, SPAN_DANGER("Error: Attempted to force a dropship launch but the shuttle datum was null. Code: MSD_FSV_DIN")) - log_admin("Error: Attempted to force a dropship launch but the shuttle datum was null. Code: MSD_FSV_DIN") + to_chat(src, SPAN_DANGER("Error: Attempted to force a dropship hijack but the shuttle datum was null. Code: MSD_FSV_DIN")) + log_admin("Error: Attempted to force a dropship hijack but the shuttle datum was null. Code: MSD_FSV_DIN") return - if(crash) - var/obj/structure/machinery/computer/shuttle/dropship/flight/computer = dropship.getControlConsole() - computer.hijack(usr) - else - to_chat(usr, SPAN_WARNING("Use the shuttle manipulator to normally move a shuttle")) + var/confirm = tgui_alert(usr, "Are you sure you want to hijack [dropship]?", "Force hijack", list("Yes", "No")) == "Yes" + if(!confirm) + return + + var/obj/structure/machinery/computer/shuttle/dropship/flight/computer = dropship.getControlConsole() + computer.hijack(usr, force = TRUE) /client/proc/cmd_admin_create_centcom_report() set name = "Report: Faction" @@ -472,10 +492,10 @@ for(var/obj/structure/machinery/computer/almayer_control/C in machines) if(!(C.inoperable())) var/obj/item/paper/P = new /obj/item/paper( C.loc ) - P.name = "'[command_name] Update.'" + P.name = "'[customname].'" P.info = input P.update_icon() - C.messagetitle.Add("[command_name] Update") + C.messagetitle.Add("[customname]") C.messagetext.Add(P.info) if(alert("Press \"Yes\" if you want to announce it to ship crew and marines. Press \"No\" to keep it only as printed report on communication console.",,"Yes","No") == "Yes") @@ -539,19 +559,16 @@ if(!input) return FALSE - for(var/obj/structure/machinery/computer/almayer_control/C in machines) - if(!(C.inoperable())) -// var/obj/item/paper/P = new /obj/item/paper(C.loc)//Don't need a printed copy currently. -// P.name = "'[MAIN_AI_SYSTEM] Update.'" -// P.info = input -// P.update_icon() - C.messagetitle.Add("[MAIN_AI_SYSTEM] Update") - C.messagetext.Add(input) - ai_announcement(input) - message_admins("[key_name_admin(src)] has created an AI comms report") - log_admin("AI comms report: [input]") - else - to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It may be offline or destroyed.")) + if(!ares_can_interface()) + var/prompt = tgui_alert(src, "ARES interface processor is offline or destroyed, send the message anyways?", "Choose.", list("Yes", "No"), 20 SECONDS) + if(prompt == "No") + to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It's interface processor may be offline or destroyed.")) + return + + ai_announcement(input) + message_admins("[key_name_admin(src)] has created an AI comms report") + log_admin("AI comms report: [input]") + /client/proc/cmd_admin_create_AI_apollo_report() set name = "Report: ARES Apollo" @@ -564,19 +581,16 @@ if(!input) return FALSE - for(var/obj/structure/machinery/computer/almayer_control/console in machines) - if(console.inoperable()) - to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It may be offline or destroyed.")) - return - else - var/datum/language/apollo = GLOB.all_languages[LANGUAGE_APOLLO] - for(var/mob/living/silicon/decoy/ship_ai/AI in ai_mob_list) - apollo.broadcast(AI, input) - for(var/mob/listener in (GLOB.human_mob_list + GLOB.dead_mob_list)) - if(listener.hear_apollo())//Only plays sound to mobs and not observers, to reduce spam. - playsound_client(listener.client, sound('sound/misc/interference.ogg'), listener, vol = 45) - message_admins("[key_name_admin(src)] has created an AI Apollo report") - log_admin("AI Apollo report: [input]") + var/datum/ares_link/link = GLOB.ares_link + if(link.p_apollo.inoperable()) + var/prompt = tgui_alert(src, "ARES APOLLO processor is offline or destroyed, send the message anyways?", "Choose.", list("Yes", "No"), 20 SECONDS) + if(prompt == "No") + to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It's APOLLO processor may be offline or destroyed.")) + return FALSE + + ares_apollo_talk(input) + message_admins("[key_name_admin(src)] has created an AI APOLLO report") + log_admin("AI APOLLO report: [input]") /client/proc/cmd_admin_create_AI_shipwide_report() set name = "Report: ARES Shipwide" @@ -588,15 +602,11 @@ var/input = input(usr, "This is an announcement type message from the ship's AI. This will be announced to every conscious human on Almayer z-level. Be aware, this will work even if ARES unpowered/destroyed. Check with online staff before you send this.", "What?", "") as message|null if(!input) return FALSE - - for(var/obj/structure/machinery/computer/almayer_control/C in machines) - if(!(C.inoperable())) -// var/obj/item/paper/P = new /obj/item/paper(C.loc)//Don't need a printed copy currently. -// P.name = "'[MAIN_AI_SYSTEM] Update.'" -// P.info = input -// P.update_icon() - C.messagetitle.Add("[MAIN_AI_SYSTEM] Shipwide Update") - C.messagetext.Add(input) + if(!ares_can_interface()) + var/prompt = tgui_alert(src, "ARES interface processor is offline or destroyed, send the message anyways?", "Choose.", list("Yes", "No"), 20 SECONDS) + if(prompt == "No") + to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It's interface processor may be offline or destroyed.")) + return shipwide_ai_announcement(input) message_admins("[key_name_admin(src)] has created an AI shipwide report") @@ -698,6 +708,7 @@ Misc
Award a medal
Award a royal jelly
+ Spawn a nuke
Toggle PMC gun restrictions
Turn everyone into monkies

@@ -757,7 +768,7 @@ create_humans_html = replacetext(create_humans_html, "null /* object types */", "\"[equipment_presets]\"") create_humans_html = replacetext(create_humans_html, "/* href token */", RawHrefToken(forceGlobal = TRUE)) - show_browser(user, replacetext(create_humans_html, "/* ref src */", "\ref[src]"), "Create Humans", "create_humans", "size=450x630") + show_browser(user, replacetext(create_humans_html, "/* ref src */", "\ref[src]"), "Create Humans", "create_humans", "size=450x720") /client/proc/create_humans() set name = "Create Humans" @@ -843,7 +854,6 @@ if(isnull(OBShell.double_explosion_delay)) return statsmessage = "Custom HE OB ([OBShell.name]) Stats from [key_name(usr)]: Clear Power: [OBShell.clear_power], Clear Falloff: [OBShell.clear_falloff], Clear Delay: [OBShell.clear_delay], Blast Power: [OBShell.standard_power], Blast Falloff: [OBShell.standard_falloff], Blast Delay: [OBShell.double_explosion_delay]." warhead = OBShell - qdel(OBShell) if("Custom Cluster") var/obj/structure/ob_ammo/warhead/cluster/OBShell = new OBShell.name = input("What name should the warhead have?", "Set name", "Cluster orbital warhead") @@ -860,7 +870,6 @@ if(isnull(OBShell.explosion_falloff)) return statsmessage = "Custom Cluster OB ([OBShell.name]) Stats from [key_name(usr)]: Salvos: [OBShell.total_amount], Shot per Salvo: [OBShell.instant_amount], Explosion Power: [OBShell.explosion_power], Explosion Falloff: [OBShell.explosion_falloff]." warhead = OBShell - qdel(OBShell) if("Custom Incendiary") var/obj/structure/ob_ammo/warhead/incendiary/OBShell = new OBShell.name = input("What name should the warhead have?", "Set name", "Incendiary orbital warhead") @@ -889,19 +898,28 @@ if(isnull(OBShell.fire_color)) return statsmessage = "Custom Incendiary OB ([OBShell.name]) Stats from [key_name(usr)]: Clear Power: [OBShell.clear_power], Clear Falloff: [OBShell.clear_falloff], Clear Delay: [OBShell.clear_delay], Fire Distance: [OBShell.distance], Fire Duration: [OBShell.fire_level], Fire Strength: [OBShell.burn_level]." warhead = OBShell - qdel(OBShell) if(custom) - if(alert(usr, statsmessage, "Confirm Stats", "Yes", "No") != "Yes") return + if(alert(usr, statsmessage, "Confirm Stats", "Yes", "No") != "Yes") + qdel(warhead) + return message_admins(statsmessage) var/turf/target = get_turf(usr.loc) if(alert(usr, "Fire or Spawn Warhead?", "Mode", "Fire", "Spawn") == "Fire") - if(alert("Are you SURE you want to do this? It will create an OB explosion!",, "Yes", "No") != "Yes") return + if(alert("Are you SURE you want to do this? It will create an OB explosion!",, "Yes", "No") != "Yes") + qdel(warhead) + return + message_admins("[key_name(usr)] has fired \an [warhead.name] at ([target.x],[target.y],[target.z]).") warhead.warhead_impact(target) - QDEL_IN(warhead, OB_CRASHING_DOWN) + + if(istype(warhead, /obj/structure/ob_ammo/warhead/cluster)) + // so the user's screen can shake for the duration of the cluster, otherwise we get a runtime. + QDEL_IN(warhead, OB_CLUSTER_DURATION) + else + QDEL_IN(warhead, OB_CRASHING_DOWN) else warhead.loc = target @@ -971,11 +989,33 @@ else var/faction = tgui_input_list(usr, "What faction do you wish to provide a bioscan for?", "Bioscan Faction", list("Xeno","Marine","Yautja"), 20 SECONDS) var/variance = tgui_input_number(usr, "How variable do you want the scan to be? (+ or - an amount from truth)", "Variance", 2, 10, 0, 20 SECONDS) + message_admins("BIOSCAN: [key_name(usr)] admin-triggered a bioscan for [faction].") GLOB.bioscan_data.get_scan_data() switch(faction) if("Xeno") GLOB.bioscan_data.qm_bioscan(variance) if("Marine") - GLOB.bioscan_data.ares_bioscan(FALSE, variance) + var/force_check = tgui_alert(usr, "Do you wish to force ARES to display the bioscan?", "Display force", list("Yes", "No"), 20 SECONDS) + var/force_status = FALSE + if(force_check == "Yes") + force_status = TRUE + GLOB.bioscan_data.ares_bioscan(force_status, variance) if("Yautja") GLOB.bioscan_data.yautja_bioscan() + +/client/proc/admin_blurb() + set name = "Global Blurb Message" + set category = "Admin.Events" + + if(!check_rights(R_ADMIN|R_DEBUG)) + return FALSE + var/duration = 5 SECONDS + var/message = "ADMIN TEST" + var/text_input = tgui_input_text(usr, "Announcement message", "Message Contents", message, timeout = 5 MINUTES) + message = text_input + duration = tgui_input_number(usr, "Set the duration of the alert in deci-seconds.", "Duration", 5 SECONDS, 5 MINUTES, 5 SECONDS, 20 SECONDS) + var/confirm = tgui_alert(usr, "Are you sure you wish to send '[message]' to all players for [(duration / 10)] seconds?", "Confirm", list("Yes", "No"), 20 SECONDS) + if(confirm != "Yes") + return FALSE + show_blurb(GLOB.player_list, duration, message, TRUE, "center", "center", "#bd2020", "ADMIN") + message_admins("[key_name(usr)] sent an admin blurb alert to all players. Alert reads: '[message]' and lasts [(duration / 10)] seconds.") diff --git a/code/modules/admin/tabs/round_tab.dm b/code/modules/admin/tabs/round_tab.dm index e9cf67b0f6d8..deb27e73f7dc 100644 --- a/code/modules/admin/tabs/round_tab.dm +++ b/code/modules/admin/tabs/round_tab.dm @@ -46,6 +46,7 @@ predator_round.flags_round_type &= ~MODE_PREDATOR message_admins("[key_name_admin(usr)] has [(predator_round.flags_round_type & MODE_PREDATOR) ? "allowed predators to spawn" : "prevented predators from spawning"].") + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PREDATOR_ROUND_TOGGLED) /client/proc/free_slot() set name = "Free Job Slots" @@ -80,7 +81,7 @@ var/active_role_names = GLOB.gamemode_roles[GLOB.master_mode] if(!active_role_names) - active_role_names = ROLES_REGULAR_ALL + active_role_names = ROLES_DISTRESS_SIGNAL for(var/role_name as anything in active_role_names) var/datum/job/job = RoleAuthority.roles_by_name[role_name] @@ -165,12 +166,13 @@ set name = "Start Round" set desc = "Start the round RIGHT NOW" set category = "Server.Round" - - if (!SSticker) - alert("Unable to start the game as it is not set up.") - return if (alert("Are you sure you want to start the round early?",,"Yes","No") != "Yes") return + if (SSticker.current_state == GAME_STATE_STARTUP) + message_admins("Game is setting up and will launch as soon as it is ready.") + message_admins(SPAN_ADMINNOTICE("[usr.key] has started the process to start the game when loading is finished.")) + while (SSticker.current_state == GAME_STATE_STARTUP) + sleep(50) // it patiently waits for the game to be ready here before moving on. if (SSticker.current_state == GAME_STATE_PREGAME) SSticker.request_start() message_admins(SPAN_BLUE("[usr.key] has started the game.")) @@ -179,3 +181,34 @@ else to_chat(usr, "Error: Start Now: Game has already started.") return FALSE + +/client/proc/toggle_cdn() + set name = "Toggle CDN" + set category = "Server" + var/static/admin_disabled_cdn_transport = null + if(alert(usr, "Are you sure you want to toggle CDN asset transport?", "Confirm", "Yes", "No") != "Yes") + return + + var/current_transport = CONFIG_GET(string/asset_transport) + if(!current_transport || current_transport == "simple") + if(admin_disabled_cdn_transport) + CONFIG_SET(string/asset_transport, admin_disabled_cdn_transport) + admin_disabled_cdn_transport = null + SSassets.OnConfigLoad() + message_admins("[key_name_admin(usr)] re-enabled the CDN asset transport") + log_admin("[key_name(usr)] re-enabled the CDN asset transport") + return + + to_chat(usr, SPAN_ADMINNOTICE("The CDN is not enabled!")) + if(alert(usr, "CDN asset transport is not enabled! If you're having issues with assets, you can also try disabling filename mutations.", "CDN asset transport is not enabled!", "Try disabling filename mutations", "Nevermind") == "Try disabling filename mutations") + SSassets.transport.dont_mutate_filenames = !SSassets.transport.dont_mutate_filenames + message_admins("[key_name_admin(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms.") + log_admin("[key_name(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms.") + return + + admin_disabled_cdn_transport = current_transport + CONFIG_SET(string/asset_transport, "simple") + SSassets.OnConfigLoad() + SSassets.transport.dont_mutate_filenames = TRUE + message_admins("[key_name_admin(usr)] disabled CDN asset transport") + log_admin("[key_name(usr)] disabled CDN asset transport") diff --git a/code/modules/admin/topic/topic.dm b/code/modules/admin/topic/topic.dm index 318ce9b44264..a76be10e9c26 100644 --- a/code/modules/admin/topic/topic.dm +++ b/code/modules/admin/topic/topic.dm @@ -982,7 +982,8 @@ 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_MOD)) + return var/mob/living/L = locate(href_list["revive"]) if(!istype(L)) @@ -1241,7 +1242,7 @@ log_admin("[src.owner] replied to [key_name(H)]'s USCM message with the message [input].") for(var/client/X in GLOB.admins) if((R_ADMIN|R_MOD) & X.admin_holder.rights) - to_chat(X, "ADMINS/MODS: \red [src.owner] replied to [key_name(H)]'s USCM message with: \blue \")[input]\"") + to_chat(X, SPAN_STAFF_IC("ADMINS/MODS: \red [src.owner] replied to [key_name(H)]'s USCM message with: \blue \")[input]\"")) to_chat(H, SPAN_DANGER("You hear something crackle in your headset before a voice speaks, please stand by for a message from USCM:\" \blue \"[input]\"")) else if(href_list["SyndicateReply"]) @@ -1270,14 +1271,15 @@ var/obj/structure/machinery/faxmachine/fax = locate(href_list["originfax"]) var/template_choice = tgui_input_list(usr, "Use which template or roll your own?", "Fax Templates", list("Template", "Custom")) - var/fax_message = "" + if(!template_choice) return + var/datum/fax/fax_message var/organization_type = "" switch(template_choice) if("Custom") var/input = input(src.owner, "Please enter a message to reply to [key_name(H)] via secure connection. NOTE: BBCode does not work, but HTML tags do! Use
for line breaks.", "Outgoing message from Press", "") as message|null if(!input) return - fax_message = "[input]" + fax_message = new(input) if("Template") var/subject = input(src.owner, "Enter subject line", "Outgoing message from Press", "") as message|null if(!subject) @@ -1302,10 +1304,10 @@ if(!organization_type) return - fax_message = generate_templated_fax(0, organization_type, subject, addressed_to, message_body, sent_by, "Editor in Chief", organization_type) - show_browser(usr, "[fax_message]", "pressfaxpreview", "size=500x400") + fax_message = new(generate_templated_fax(0, organization_type, subject, addressed_to, message_body, sent_by, "Editor in Chief", organization_type)) + show_browser(usr, "[fax_message.data]", "pressfaxpreview", "size=500x400") var/send_choice = tgui_input_list(usr, "Send this fax?", "Fax Template", list("Send", "Cancel")) - if(send_choice == "Cancel") + if(send_choice != "Send") return GLOB.fax_contents += fax_message // save a copy @@ -1329,7 +1331,7 @@ spawn(20) var/obj/item/paper/P = new /obj/item/paper( F.loc ) P.name = "[organization_type] - [customname]" - P.info = fax_message + P.info = fax_message.data P.update_icon() playsound(F.loc, "sound/machines/fax.ogg", 15) @@ -1344,7 +1346,7 @@ P.stamps += "
This paper has been stamped by the Free Press Quantum Relay." to_chat(src.owner, "Message reply to transmitted successfully.") - message_admins("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]", 1) + message_admins(SPAN_STAFF_IC("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]"), 1) return to_chat(src.owner, "/red Unable to locate fax!") else if(href_list["USCMFaxReply"]) @@ -1352,13 +1354,14 @@ var/obj/structure/machinery/faxmachine/fax = locate(href_list["originfax"]) var/template_choice = tgui_input_list(usr, "Use which template or roll your own?", "Fax Templates", list("USCM High Command", "USCM Provost General", "Custom")) - var/fax_message = "" + if(!template_choice) return + var/datum/fax/fax_message switch(template_choice) if("Custom") var/input = input(src.owner, "Please enter a message to reply to [key_name(H)] via secure connection. NOTE: BBCode does not work, but HTML tags do! Use
for line breaks.", "Outgoing message from USCM", "") as message|null if(!input) return - fax_message = "[input]" + fax_message = new(input) if("USCM High Command", "USCM Provost General") var/subject = input(src.owner, "Enter subject line", "Outgoing message from USCM", "") as message|null if(!subject) @@ -1383,10 +1386,10 @@ if(template_choice == "USCM High Command") sent_title = "USCM High Command" - fax_message = generate_templated_fax(0, "USCM CENTRAL COMMAND", subject,addressed_to, message_body,sent_by, sent_title, "United States Colonial Marine Corps") - show_browser(usr, "[fax_message]", "uscmfaxpreview", "size=500x400") + fax_message = new(generate_templated_fax(0, "USCM CENTRAL COMMAND", subject,addressed_to, message_body,sent_by, sent_title, "United States Colonial Marine Corps")) + show_browser(usr, "[fax_message.data]", "uscmfaxpreview", "size=500x400") var/send_choice = tgui_input_list(usr, "Send this fax?", "Fax Template", list("Send", "Cancel")) - if(send_choice == "Cancel") + if(send_choice != "Send") return GLOB.fax_contents += fax_message // save a copy @@ -1410,7 +1413,7 @@ spawn(20) var/obj/item/paper/P = new /obj/item/paper( F.loc ) P.name = "USCM High Command - [customname]" - P.info = fax_message + P.info = fax_message.data P.update_icon() playsound(F.loc, "sound/machines/fax.ogg", 15) @@ -1425,7 +1428,7 @@ P.stamps += "
This paper has been stamped by the USCM High Command Quantum Relay." to_chat(src.owner, "Message reply to transmitted successfully.") - message_admins("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]", 1) + message_admins(SPAN_STAFF_IC("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]"), 1) return to_chat(src.owner, "/red Unable to locate fax!") @@ -1434,13 +1437,14 @@ var/obj/structure/machinery/faxmachine/fax = locate(href_list["originfax"]) var/template_choice = tgui_input_list(usr, "Use the template or roll your own?", "Fax Template", list("Template", "Custom")) - var/fax_message = "" + if(!template_choice) return + var/datum/fax/fax_message switch(template_choice) if("Custom") var/input = input(src.owner, "Please enter a message to reply to [key_name(H)] via secure connection. NOTE: BBCode does not work, but HTML tags do! Use
for line breaks.", "Outgoing message from Weyland-Yutani", "") as message|null if(!input) return - fax_message = "[input]" + fax_message = new(input) if("Template") var/subject = input(src.owner, "Enter subject line", "Outgoing message from Weyland-Yutani", "") as message|null if(!subject) @@ -1461,10 +1465,10 @@ var/sent_by = input(src.owner, "Enter JUST the name you are sending this from", "Outgoing message from Weyland-Yutani", "") as message|null if(!sent_by) return - fax_message = generate_templated_fax(1, "WEYLAND-YUTANI CORPORATE AFFAIRS - [MAIN_SHIP_NAME]", subject, addressed_to, message_body, sent_by, "Corporate Affairs Director", "Weyland-Yutani") - show_browser(usr, "[fax_message]", "clfaxpreview", "size=500x400") + fax_message = new(generate_templated_fax(1, "WEYLAND-YUTANI CORPORATE AFFAIRS - [MAIN_SHIP_NAME]", subject, addressed_to, message_body, sent_by, "Corporate Affairs Director", "Weyland-Yutani")) + show_browser(usr, "[fax_message.data]", "clfaxpreview", "size=500x400") var/send_choice = tgui_input_list(usr, "Send this fax?", "Fax Confirmation", list("Send", "Cancel")) - if(send_choice == "Cancel") + if(send_choice != "Send") return GLOB.fax_contents += fax_message // save a copy @@ -1491,7 +1495,7 @@ spawn(20) var/obj/item/paper/P = new /obj/item/paper( F.loc ) P.name = "Weyland-Yutani - [customname]" - P.info = fax_message + P.info = fax_message.data P.update_icon() playsound(F.loc, "sound/machines/fax.ogg", 15) @@ -1506,7 +1510,7 @@ P.stamps += "
This paper has been stamped and encrypted by the Weyland-Yutani Quantum Relay (tm)." to_chat(src.owner, "Message reply to transmitted successfully.") - message_admins("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]", 1) + message_admins(SPAN_STAFF_IC("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]"), 1) return to_chat(src.owner, "/red Unable to locate fax!") @@ -1515,13 +1519,14 @@ var/obj/structure/machinery/faxmachine/fax = locate(href_list["originfax"]) var/template_choice = tgui_input_list(usr, "Use the template or roll your own?", "Fax Template", list("Anchorpoint", "Custom")) - var/fax_message = "" + if(!template_choice) return + var/datum/fax/fax_message switch(template_choice) if("Custom") var/input = input(src.owner, "Please enter a message to reply to [key_name(H)] via secure connection. NOTE: BBCode does not work, but HTML tags do! Use
for line breaks.", "Outgoing message from The Colonial Marshal Bureau", "") as message|null if(!input) return - fax_message = "[input]" + fax_message = new(input) if("Anchorpoint") var/subject = input(src.owner, "Enter subject line", "Outgoing message from The Colonial Marshal Bureau, Anchorpoint Station", "") as message|null if(!subject) @@ -1542,10 +1547,10 @@ var/sent_by = input(src.owner, "Enter JUST the name you are sending this from", "Outgoing message from The Colonial Marshal Bureau", "") as message|null if(!sent_by) return - fax_message = generate_templated_fax(0, "COLONIAL MARSHAL BUREAU INCIDENT COMMAND CENTER - ANCHORPOINT STATION", subject, addressed_to, message_body, sent_by, "Supervisory Deputy Marshal", "Colonial Marshal Bureau") - show_browser(usr, "[fax_message]", "PREVIEW OF CMB FAX", "size=500x400") + fax_message = new(generate_templated_fax(0, "COLONIAL MARSHAL BUREAU INCIDENT COMMAND CENTER - ANCHORPOINT STATION", subject, addressed_to, message_body, sent_by, "Supervisory Deputy Marshal", "Colonial Marshal Bureau")) + show_browser(usr, "[fax_message.data]", "PREVIEW OF CMB FAX", "size=500x400") var/send_choice = tgui_input_list(usr, "Send this fax?", "Fax Confirmation", list("Send", "Cancel")) - if(send_choice == "Cancel") + if(send_choice != "Send") return GLOB.fax_contents += fax_message // save a copy @@ -1572,7 +1577,7 @@ spawn(20) var/obj/item/paper/P = new /obj/item/paper( F.loc ) P.name = "Colonial Marshal Bureau - [customname]" - P.info = fax_message + P.info = fax_message.data P.update_icon() playsound(F.loc, "sound/machines/fax.ogg", 15) @@ -1587,7 +1592,7 @@ P.stamps += "
This paper has been stamped by The Office of Colonial Marshals." to_chat(src.owner, "Message reply to transmitted successfully.") - message_admins("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]", 1) + message_admins(SPAN_STAFF_IC("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]"), 1) return to_chat(src.owner, "/red Unable to locate fax!") @@ -1878,7 +1883,7 @@ if(href_list["ccdeny"]) // CentComm-deny. The distress call is denied, without any further conditions var/mob/ref_person = locate(href_list["ccdeny"]) - marine_announcement("The distress signal has not received a response, the launch tubes are now recalibrating.", "Distress Beacon") + marine_announcement("The distress signal has not received a response, the launch tubes are now recalibrating.", "Distress Beacon", logging = ARES_LOG_SECURITY) log_game("[key_name_admin(usr)] has denied a distress beacon, requested by [key_name_admin(ref_person)]") message_admins("[key_name_admin(usr)] has denied a distress beacon, requested by [key_name_admin(ref_person)]", 1) @@ -1899,6 +1904,17 @@ addtimer(CALLBACK(src, PROC_REF(accept_ert), usr, locate(href_list["distress"])), 10 SECONDS) //unanswered_distress -= ref_person + if(href_list["distress_pmc"]) //Wey-Yu specific PMC distress signal for chem retrieval ERT + distress_cancel = FALSE + message_admins("[key_name_admin(usr)] has opted to SEND the distress beacon! Launching in 10 seconds... (CANCEL)") + addtimer(CALLBACK(src, PROC_REF(accept_pmc_ert), usr, locate(href_list["distress"])), 10 SECONDS) + + if(href_list["ccdeny_pmc"]) // CentComm-deny. The distress call is denied, without any further conditions + var/mob/ref_person = locate(href_list["ccdeny_pmc"]) + to_chat(ref_person, "The distress signal has not received a response.") + log_game("[key_name_admin(usr)] has denied a distress beacon, requested by [key_name_admin(ref_person)]") + message_admins("[key_name_admin(usr)] has denied a distress beacon, requested by [key_name_admin(ref_person)]", 1) + if(href_list["destroyship"]) //Distress Beacon, sends a random distress beacon when pressed destroy_cancel = FALSE message_admins("[key_name_admin(usr)] has opted to GRANT the self-destruct! Starting in 10 seconds... (CANCEL)") @@ -1910,9 +1926,45 @@ log_game("[key_name_admin(usr)] has granted self-destruct, requested by [key_name_admin(ref_person)]") message_admins("[key_name_admin(usr)] has granted self-destruct, requested by [key_name_admin(ref_person)]", 1) + if(href_list["nukeapprove"]) + var/mob/ref_person = locate(href_list["nukeapprove"]) + if(!istype(ref_person)) + return FALSE + var/nuketype = "Encrypted Operational Nuke" + var/prompt = tgui_alert(usr, "Do you want the nuke to be Encrypted?", "Nuke Type", list("Encrypted", "Decrypted"), 20 SECONDS) + if(prompt == "Decrypted") + nuketype = "Decrypted Operational Nuke" + prompt = tgui_alert(usr, "Are you sure you want to authorize a [nuketype] to the marines? This will greatly affect the round!", "DEFCON 1", list("No", "Yes")) + if(prompt != "Yes") + return + + //make ASRS order for nuke + var/datum/supply_order/new_order = new() + new_order.ordernum = supply_controller.ordernum + supply_controller.ordernum++ + new_order.object = supply_controller.supply_packs[nuketype] + new_order.orderedby = ref_person + new_order.approvedby = "USCM High Command" + supply_controller.shoppinglist += new_order + + //Can no longer request a nuke + GLOB.ares_link.interface.nuke_available = FALSE + + marine_announcement("A nuclear device has been authorized by High Command and will be delivered to requisitions via ASRS.", "NUCLEAR ORDNANCE AUTHORIZED", 'sound/misc/notice2.ogg', logging = ARES_LOG_MAIN) + log_game("[key_name_admin(usr)] has authorized a [nuketype], requested by [key_name_admin(ref_person)]") + message_admins("[key_name_admin(usr)] has authorized a [nuketype], requested by [key_name_admin(ref_person)]") + + if(href_list["nukedeny"]) + var/mob/ref_person = locate(href_list["nukedeny"]) + if(!istype(ref_person)) + return FALSE + marine_announcement("Your request for nuclear ordnance deployment has been reviewed and denied by USCM High Command for operational security and colonial preservation reasons. Have a good day.", "NUCLEAR ORDNANCE DENIED", 'sound/misc/notice2.ogg', logging = ARES_LOG_MAIN) + log_game("[key_name_admin(usr)] has denied nuclear ordnance, requested by [key_name_admin(ref_person)]") + message_admins("[key_name_admin(usr)] has dnied nuclear ordnance, requested by [key_name_admin(ref_person)]") + if(href_list["sddeny"]) // CentComm-deny. The self-destruct is denied, without any further conditions var/mob/ref_person = locate(href_list["sddeny"]) - marine_announcement("The self-destruct request has not received a response, ARES is now recalculating statistics.", "Self-Destruct System") + marine_announcement("The self-destruct request has not received a response, ARES is now recalculating statistics.", "Self-Destruct System", logging = ARES_LOG_SECURITY) log_game("[key_name_admin(usr)] has denied self-destruct, requested by [key_name_admin(ref_person)]") message_admins("[key_name_admin(usr)] has denied self-destruct, requested by [key_name_admin(ref_person)]", 1) @@ -1991,6 +2043,45 @@ player_notes_all(checking.key) + if(href_list["AresReply"]) + var/mob/living/carbon/human/speaker = locate(href_list["AresReply"]) + + if(!istype(speaker)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return FALSE + + if((!GLOB.ares_link.interface) || (GLOB.ares_link.interface.inoperable())) + to_chat(usr, "ARES Interface offline.") + return FALSE + + var/input = input(src.owner, "Please enter a message from ARES to reply to [key_name(speaker)].","Outgoing message from ARES", "") + if(!input) + return FALSE + + to_chat(src.owner, "You sent [input] to [speaker] via ARES Interface.") + log_admin("[src.owner] replied to [key_name(speaker)]'s ARES message with the message [input].") + for(var/client/staff in GLOB.admins) + if((R_ADMIN|R_MOD) & staff.admin_holder.rights) + to_chat(staff, SPAN_STAFF_IC("ADMINS/MODS: [SPAN_RED("[src.owner] replied to [key_name(speaker)]'s ARES message")] with: [SPAN_BLUE(input)] ")) + GLOB.ares_link.interface.response_from_ares(input, href_list["AresRef"]) + + if(href_list["AresMark"]) + var/mob/living/carbon/human/speaker = locate(href_list["AresMark"]) + + if(!istype(speaker)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return FALSE + + if((!GLOB.ares_link.interface) || (GLOB.ares_link.interface.inoperable())) + to_chat(usr, "ARES Interface offline.") + return FALSE + + to_chat(src.owner, "You marked [speaker]'s ARES message for response.") + log_admin("[src.owner] marked [key_name(speaker)]'s ARES message. [src.owner] will be responding.") + for(var/client/staff in GLOB.admins) + if((R_ADMIN|R_MOD) & staff.admin_holder.rights) + to_chat(staff, SPAN_STAFF_IC("ADMINS/MODS: [SPAN_RED("[src.owner] marked [key_name(speaker)]'s ARES message for response.")]")) + return /datum/admins/proc/accept_ert(mob/approver, mob/ref_person) @@ -2001,6 +2092,14 @@ log_game("[key_name_admin(approver)] has sent a randomized distress beacon, requested by [key_name_admin(ref_person)]") message_admins("[key_name_admin(approver)] has sent a randomized distress beacon, requested by [key_name_admin(ref_person)]") +/datum/admins/proc/accept_pmc_ert(mob/approver, mob/ref_person) + if(distress_cancel) + return + distress_cancel = TRUE + SSticker.mode.get_specific_call("Weyland-Yutani PMC (Chemical Investigation Squad)", FALSE, FALSE) + log_game("[key_name_admin(approver)] has sent a PMC distress beacon, requested by [key_name_admin(ref_person)]") + message_admins("[key_name_admin(approver)] has sent a PMC distress beacon, requested by [key_name_admin(ref_person)]") + /datum/admins/proc/generate_job_ban_list(mob/M, datum/entity/player/P, list/roles, department, color = "ccccff") var/counter = 0 diff --git a/code/modules/admin/topic/topic_events.dm b/code/modules/admin/topic/topic_events.dm index c95b6d33648d..3240bf947938 100644 --- a/code/modules/admin/topic/topic_events.dm +++ b/code/modules/admin/topic/topic_events.dm @@ -22,6 +22,8 @@ owner.award_medal() if("jelly") owner.award_jelly() + if("nuke") + owner.give_nuke() if("pmcguns") owner.toggle_gun_restrictions() if("monkify") @@ -115,16 +117,25 @@ else if(href_list["spawn_as"] == "ert") offer_as_ert = TRUE + var/strip_the_humans = FALSE + var/strip_weapons = FALSE + if(href_list["equip_with"] == "no_weapons") + strip_weapons = TRUE + + if(href_list["equip_with"] == "no_equipment") + strip_the_humans = TRUE + if(humans_to_spawn) var/list/turfs = list() if(isnull(range_to_spawn_on)) range_to_spawn_on = 0 + var/turf/spawn_turf if(range_to_spawn_on) - for(var/turf/T in range(initial_turf, range_to_spawn_on)) - if(!T || istype(T, /turf/closed)) + for(spawn_turf in range(initial_turf, range_to_spawn_on)) + if(!spawn_turf || istype(spawn_turf, /turf/closed)) continue - turfs += T + turfs += spawn_turf else turfs = list(initial_turf) @@ -132,20 +143,58 @@ return var/list/humans = list() - var/mob/living/carbon/human/H + var/mob/living/carbon/human/spawned_human for(var/i = 0 to humans_to_spawn-1) - var/turf/to_spawn_at = pick(turfs) - H = new(to_spawn_at) + spawn_turf = pick(turfs) + spawned_human = new(spawn_turf) - if(!H.hud_used) - H.create_hud() - - arm_equipment(H, job_name, TRUE, FALSE) + if(!spawned_human.hud_used) + spawned_human.create_hud() if(free_the_humans) - owner.free_for_ghosts(H) + owner.free_for_ghosts(spawned_human) + + arm_equipment(spawned_human, job_name, TRUE, FALSE) + + humans += spawned_human + + if(strip_the_humans) + for(var/obj/item/current_item in spawned_human) + //no more deletion of ID cards + if(istype(current_item, /obj/item/card/id/)) + continue + qdel(current_item) + continue + + if(strip_weapons) + var/obj/item_storage + for(var/obj/item/current_item in spawned_human.GetAllContents(3)) + if(istype(current_item, /obj/item/ammo_magazine)) + + item_storage = current_item.loc + qdel(current_item) + + if(istype(item_storage, /obj/item/storage)) + item_storage.update_icon() + + continue + + if(istype(current_item, /obj/item/weapon)) + qdel(current_item) + continue + + if(istype(current_item, /obj/item/explosive)) + qdel(current_item) + + for(var/obj/item/hand_item in spawned_human.hands) + if(istype(hand_item, /obj/item/weapon)) + qdel(hand_item) + continue + + if(istype(hand_item, /obj/item/explosive)) + qdel(hand_item) + - humans += H if (offer_as_ert) var/datum/emergency_call/custom/em_call = new() @@ -197,11 +246,12 @@ if(isnull(range_to_spawn_on)) range_to_spawn_on = 0 + var/turf/spawn_turf if(range_to_spawn_on) - for(var/turf/T in range(initial_turf, range_to_spawn_on)) - if(!T || istype(T, /turf/closed)) + for(spawn_turf in range(initial_turf, range_to_spawn_on)) + if(!spawn_turf || istype(spawn_turf, /turf/closed)) continue - turfs += T + turfs += spawn_turf else turfs = list(initial_turf) @@ -213,8 +263,8 @@ var/list/xenos = list() var/mob/living/carbon/xenomorph/X for(var/i = 0 to xenos_to_spawn - 1) - var/turf/to_spawn_at = pick(turfs) - X = new caste_type(to_spawn_at, null, xeno_hive) + spawn_turf = pick(turfs) + X = new caste_type(spawn_turf, null, xeno_hive) if(!X.hud_used) X.create_hud() diff --git a/code/modules/admin/topic/topic_inview.dm b/code/modules/admin/topic/topic_inview.dm index 38214af9587b..7535767af3a8 100644 --- a/code/modules/admin/topic/topic_inview.dm +++ b/code/modules/admin/topic/topic_inview.dm @@ -18,3 +18,5 @@ subtlemessageall() if("alertall") alertall() + if("stripall") + owner.strip_all_in_view() diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 52aae50a966a..05da6d3c8672 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -203,6 +203,9 @@ message_admins(SPAN_DANGER("ERROR: Non-admin [key_name(usr)] attempted to execute a SDQL query!")) log_admin("non-admin attempted to execute a SDQL query!") return FALSE + var/prompt = tgui_alert(usr, "Run SDQL2 Query?", "SDQL2", list("Yes", "Cancel")) + if (prompt != "Yes") + return var/list/results = world.SDQL2_query(query_text, key_name_admin(usr), "[key_name(usr)]") if(length(results) == 3) for(var/I in 1 to 3) @@ -342,7 +345,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/sdql2_vv_all, new(null /datum/sdql2_query/New(list/tree, SU = FALSE, admin_interact = TRUE, _options = SDQL2_OPTIONS_DEFAULT, finished_qdel = FALSE) if(IsAdminAdvancedProcCall() || !LAZYLEN(tree)) qdel(src) - return + return PROC_BLOCKED LAZYADD(GLOB.sdql2_queries, src) superuser = SU allow_admin_interact = admin_interact @@ -599,7 +602,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/sdql2_vv_all, new(null var/text = "[key_name(usr)] attempted to grab world with a procedure call to a SDQL datum." message_admins(text) log_admin(text) - return + return PROC_BLOCKED if("world" in tree) return world return SDQL_expression(world, tree) diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 215fecd24858..3d50b50e414c 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -203,6 +203,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) var/marked_admin /// Has the player replied to this ticket yet? var/player_replied = FALSE + /// What was the first message sent by the player? + var/initial_message /** * Call this on its own to create a ticket, don't manually assign current_ticket @@ -222,6 +224,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) opened_at = world.time name = copytext_char(msg, 1, 100) + initial_message = msg initiator = C initiator_ckey = initiator.ckey @@ -275,7 +278,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) "CKEY" = initiator_ckey, "PLAYERS" = player_count, "ROUND STATE" = round_state, - "ROUND ID" = SSperf_logging.round?.id, + "ROUND ID" = GLOB.round_id, "ROUND TIME" = duration2text(), "MESSAGE" = message, "ADMINS" = admin_text, @@ -363,11 +366,16 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) /datum/admin_help/proc/FullMonty(ref_src) if(!ref_src) ref_src = "[REF(src)]" - . = ADMIN_FULLMONTY_NONAME(initiator.mob) + . = "
Ticket Actions: " if(state == AHELP_ACTIVE) + if(initial_message) + . += " (DEFER)" if (CONFIG_GET(flag/popup_admin_pm)) . += " (POPUP)" . += ClosureLinks(ref_src) + . += "
Player Actions: " + . += ADMIN_FULLMONTY_NONAME(initiator.mob) + . += "" //private /datum/admin_help/proc/ClosureLinks(ref_src) @@ -397,7 +405,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) var/ref_src = "[REF(src)]" //Message to be sent to all admins - var/admin_msg = SPAN_ADMINSAY(SPAN_ADMINHELP("Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]: [msg]")) + var/admin_msg = SPAN_ADMINSAY(SPAN_ADMINHELP("Ticket [TicketHref("#[id]", ref_src)]: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]
[msg]")) AddInteraction("[LinkedReplyName(ref_src)]: [msg]", player_message = "[LinkedReplyName(ref_src)]: [msg]") log_admin_private("Ticket #[id]: [key_name(initiator)]: [msg]") @@ -489,6 +497,32 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) log_ahelp(id, "Resolved", "Resolved by [usr.key]", null, usr.ckey) log_admin_private(msg) +/datum/admin_help/proc/defer_to_mentors() + if(state != AHELP_ACTIVE || !initial_message) + return + + if(!initiator.current_mhelp) + initiator.current_mhelp = new(initiator) + + var/options = tgui_alert(usr, "Use the first message in this ticket, or a custom option?", "Defer to Mentors", list("First Message", "Custom")) + if(!options) + return + + switch(options) + if("First Message") + initiator.current_mhelp.broadcast_unhandled(initial_message, initiator) + if("Custom") + var/message = tgui_input_text(usr, "Text to Send to Mentors", "Defer to Mentors") + if(!message) + return + initiator.current_mhelp.broadcast_unhandled(message, initiator) + + AddInteraction("Deferred to Mentors by [key_name_admin(usr)].", player_message = "Deferred to Mentors.") + to_chat(initiator, SPAN_ADMINHELP("Your ticket has been deferred to Mentors.")) + log_admin_private("Ticket [TicketHref("#[id]")] deferred to mentors by [usr.key].") + log_ahelp(id, "Defer", "Deferred to mentors by [usr.key]", null, usr.ckey) + Close(silent = TRUE) + /datum/admin_help/proc/mark_ticket() if(marked_admin) if(marked_admin == usr.key) @@ -580,9 +614,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) dat += "

Opened at: [gameTimestamp(wtime = opened_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)" if(closed_at) dat += "
Closed at: [gameTimestamp(wtime = closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)" - dat += "

" + dat += "
" if(initiator) - dat += "Actions: [FullMonty(ref_src)]
" + dat += "[FullMonty(ref_src)]
" //All the action buttons for tickets/ahelps else dat += "DISCONNECTED[FOURSPACES][ClosureLinks(ref_src)]
" dat += "
Log:

" @@ -659,6 +693,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) Resolve() if("reopen") Reopen() + if("defer") + defer_to_mentors() /datum/admin_help/proc/player_ticket_panel() var/list/dat = list("Player Ticket") diff --git a/code/modules/admin/verbs/adminpanelgq.dm b/code/modules/admin/verbs/adminpanelgq.dm new file mode 100644 index 000000000000..13b6e329aa69 --- /dev/null +++ b/code/modules/admin/verbs/adminpanelgq.dm @@ -0,0 +1,22 @@ +/client/proc/adminpanelgq() + set name = "Call General Quarters" + set category = "Admin.Ship" + + if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA) + tgui_alert(src, "Security is already red or above, General Quarters cannot be called.", "Acknowledge!", list("ok."), 10 SECONDS) + else + var/whattoannounce = "ATTENTION! GENERAL QUARTERS. ALL HANDS, MAN YOUR BATTLESTATIONS." + var/prompt = tgui_alert(src, "Do you want to leave the announcement as the default one?", "Choose.", list("Yes", "No"), 20 SECONDS) + if(prompt == "No") + whattoannounce = tgui_input_text(src, "Please enter announcement text.", "what?") + prompt = tgui_alert(src, "Are you sure you want to send General Quarters? This will force red alert.", "Choose.", list("Yes", "No"), 20 SECONDS) + if(prompt == "Yes") + set_security_level(2, no_sound=1, announce=0) + shipwide_ai_announcement(whattoannounce, MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg') + message_admins("[key_name_admin(src)] Sent General Quarters with a custom announcement!") + else + prompt = tgui_alert(src, "Are you sure you want to send General Quarters? This will force red alert.", "Choose.", list("Yes", "No"), 20 SECONDS) + if(prompt == "Yes") + set_security_level(2, no_sound=1, announce=0) + shipwide_ai_announcement(whattoannounce, MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg') + message_admins("[key_name_admin(src)] Sent General Quarters!") diff --git a/code/modules/admin/verbs/adminpanelweapons.dm b/code/modules/admin/verbs/adminpanelweapons.dm new file mode 100644 index 000000000000..9fde4e96ebee --- /dev/null +++ b/code/modules/admin/verbs/adminpanelweapons.dm @@ -0,0 +1,121 @@ +/client/proc/adminpanelweapons() + set name = "Weapons" + set category = "Admin.Ship" + + var/weapontype = tgui_alert(src, "What weapon?", "Choose wisely!", list("Missile", "Railgun"), 20 SECONDS) + if(!weapontype) + return + var/hiteta = tgui_input_number(src, "Give an ETA for the weapon to hit.", "Don't make them wait too long!", 10, 120, 10, 20 SECONDS) + if(!hiteta) + return + var/point_defense = tgui_alert(src, "Allow Point Defence of the ship to intercept, or for the weapon to miss?", "standard PD/miss chance is 30%.", list("Yes", "No"), 20 SECONDS) + if(!point_defense) + return + point_defense = point_defense == "Yes" + var/exactplace = tgui_alert(src, "Shoot it at random places, or where you're at?", "Choose wisely!", list("Random", "Where I am"), 20 SECONDS) + if(!exactplace) + return + exactplace = exactplace == "Where I am" + + var/salvo + var/quantity + if(exactplace == FALSE) + salvo = tgui_alert(src, "Make it a salvo or a single fire?", "Choose wisely!", list("Salvo", "Single"), 20 SECONDS) + if(!salvo) + return + salvo = salvo == "Salvo" + if(salvo == TRUE) + quantity = tgui_input_number(src, "How many?", "Don't go overboard. Please.", 2, 10, 2, 20 SECONDS) + + var/prompt = tgui_alert(src, "Are you sure you want to open fire at the USS Almayer with those parameters?", "Choose wisely!", list("Yes", "No"), 20 SECONDS) + if(prompt != "Yes") + return + var/atom/picked_atom + var/list/targets = list() + switch(weapontype) + + if("Missile") + if(exactplace == TRUE) + shipwide_ai_announcement("DANGER: MISSILE WARNING. LAUNCH DETECTED, BRACE, BRACE, BRACE. ESTIMATED TIME: [hiteta] SECONDS.", MAIN_AI_SYSTEM, 'sound/effects/missile_warning.ogg') + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(weaponhits), 1, mob.loc, point_defense), hiteta SECONDS) + message_admins("[key_name_admin(src)] Fired a Single Missile at the Almayer at their own location, [mob.loc], with point defense as [point_defense]") + if(point_defense == TRUE) + var/spoolup = hiteta - 4 + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(shipwide_ai_announcement), "ATTENTION: TRACKING TARGET, SPOOLING UP POINT DEFENSE. ATTEMPTING TO INTERCEPT." , MAIN_AI_SYSTEM, 'sound/effects/supercapacitors_charging.ogg'), spoolup SECONDS) + + if(exactplace == FALSE) + if(salvo == TRUE) + shipwide_ai_announcement("DANGER: MISSILE SALVO DETECTED, BRACE, BRACE, BRACE. SALVO SIZE: [quantity], ESTIMATED TIME: [hiteta] SECONDS." , MAIN_AI_SYSTEM, 'sound/effects/missile_warning.ogg') + targets = shipside_random_turf_picker(quantity) + if(targets == null) + tgui_alert(src, "Uh oh! Something broke at this point! Contact the coders!", "Acknowledge!", list("ok."), 10 SECONDS) + return + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(weaponhits), 1, targets, point_defense, salvo), hiteta SECONDS) + message_admins("[key_name_admin(src)] Fired a salvo of [quantity] Missiles at the Almayer at random places, with point defense as [point_defense]") + if(point_defense == TRUE) + var/spoolup = hiteta - 4 + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(shipwide_ai_announcement), "ATTENTION: TRACKING TARGETS, SPOOLING UP POINT DEFENSE. ATTEMPTING TO INTERCEPT." , MAIN_AI_SYSTEM, 'sound/effects/supercapacitors_charging.ogg'), spoolup SECONDS) + else + shipwide_ai_announcement("DANGER: MISSILE WARNING. LAUNCH DETECTED, BRACE, BRACE, BRACE. ESTIMATED TIME: [hiteta] SECONDS.", MAIN_AI_SYSTEM, 'sound/effects/missile_warning.ogg') + picked_atom = shipside_random_turf_picker(1) + if(picked_atom == null) + tgui_alert(src, "Uh oh! Something broke at this point! Contact the coders!", "Acknowledge!", list("ok."), 10 SECONDS) + return + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(weaponhits), 1, picked_atom, point_defense), hiteta SECONDS) + message_admins("[key_name_admin(src)] Fired a Single Missile at the Almayer at a random place, [picked_atom], with point defense as [point_defense]") + if(point_defense == TRUE) + var/spoolup = hiteta - 4 + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(shipwide_ai_announcement), "ATTENTION: TRACKING TARGET, SPOOLING UP POINT DEFENSE. ATTEMPTING TO INTERCEPT." , MAIN_AI_SYSTEM, 'sound/effects/supercapacitors_charging.ogg'), spoolup SECONDS) + + if("Railgun") + if(exactplace == TRUE) + shipwide_ai_announcement("DANGER: RAILGUN EMISSIONS DETECTED, INCOMING SHOT. BRACE, BRACE, BRACE. ESTIMATED TIME: [hiteta] SECONDS." , MAIN_AI_SYSTEM, 'sound/effects/missile_warning.ogg') + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(weaponhits), 2, mob.loc, point_defense), hiteta SECONDS) + message_admins("[key_name_admin(src)] Fired a single Railgun Slug at the Almayer at their location, [mob.loc], with the possibility of missing as [point_defense]") + + + if(exactplace == FALSE) + if(salvo == TRUE) + shipwide_ai_announcement("DANGER: RAILGUN EMISSIONS DETECTED, SALVO INCOMING. BRACE, BRACE, BRACE. SALVO SIZE: [quantity], ESTIMATED TIME: [hiteta] SECONDS." , MAIN_AI_SYSTEM, 'sound/effects/missile_warning.ogg') + targets = shipside_random_turf_picker(quantity) + if(targets == null) + tgui_alert(src, "Uh oh! Something broke at this point! Contact the coders!", "Acknowledge!", list("ok."), 10 SECONDS) + return + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(weaponhits), 2, targets, point_defense, salvo), hiteta SECONDS) + message_admins("[key_name_admin(src)] Fired a salvo of Railgun Slugs at the Almayer at random places, with the possibility of missing [point_defense]") + picked_atom = null + targets = null + + if(salvo == FALSE) + prompt = tgui_alert(src, "Are you sure you want to shoot a railgun slug at the USS Almayer at a random place?", "Choose wisely!", list("Yes", "No"), 20 SECONDS) + if(prompt == "Yes") + shipwide_ai_announcement("DANGER: RAILGUN EMISSIONS DETECTED, INCOMING SHOT. BRACE, BRACE, BRACE. ESTIMATED TIME: [hiteta] SECONDS." , MAIN_AI_SYSTEM, 'sound/effects/missile_warning.ogg') + picked_atom = shipside_random_turf_picker(1) + if(picked_atom == null) + tgui_alert(src, "Uh oh! Something broke at this point! Contact the coders!", "Acknowledge!", list("ok."), 10 SECONDS) + return + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(weaponhits), 2, picked_atom, point_defense), hiteta SECONDS) + message_admins("[key_name_admin(src)] Fired a single Railgun Slug at the Almayer at a random location, [picked_atom], with the possibility of missing as [point_defense]") + +/proc/shipside_random_turf_picker(turfquantity) + + var/picked_atom + var/picked_area + var/list/targets = list() + var/list/turfs_of_area = list() + for(var/currentturf in 1 to turfquantity) + for(var/limiter in 1 to 120) + picked_area = pick(GLOB.ship_areas) + for(var/turf/my_turf in picked_area) + turfs_of_area += my_turf + if(turfs_of_area.len > 0) + picked_atom = pick(turfs_of_area) + if (picked_atom != null) + targets += picked_atom + break + + if(targets.len < turfquantity) + return null + else + return targets + diff --git a/code/modules/admin/verbs/custom_paper.dm b/code/modules/admin/verbs/custom_paper.dm index 2c29d2fc3cab..d63d37a84f21 100644 --- a/code/modules/admin/verbs/custom_paper.dm +++ b/code/modules/admin/verbs/custom_paper.dm @@ -19,7 +19,7 @@ if(new_sheet) qdel(sheet) return - show_browser(usr, "[new_text]", "Custom paper preview", "custom_paper_preview", "size=500x400") + show_browser(usr, "[new_text]", "Custom paper preview", "custom_paper_preview", "size=650x700") if(alert(usr, "Make this new content?", "Customising [new_name]", "OK", "Cancel") == "Cancel") close_browser(usr, "custom_paper_preview") if(new_sheet) diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index be8a5693df6e..700d42808a07 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -23,7 +23,7 @@ stafftype = "[admin_holder.rank]" msg = strip_html(msg) - log_admin("[key_name(src)] : [msg]") + log_admin("DEAD: [key_name(src)] : [msg]") if (!msg) return diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 3b3240405e89..0297145c7e8d 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -92,7 +92,74 @@ else message_admins("[key_name(src)] disabled checking for round-end.") +/client/proc/cmd_debug_mass_screenshot() + set category = "Debug" + set name = "Mass Screenshot" + set background = TRUE + set waitfor = FALSE + + if(!check_rights(R_MOD)) + return + if(tgui_alert(usr, "Are you sure you want to mass screenshot this z-level? Ensure your visual settings are correct first (other ghost visibility, zoom level, etc.) and you have emptied your BYOND/screenshots folder.", "Mass Screenshot", list("Yes", "No")) != "Yes") + return + + var/sleep_duration = tgui_input_number(usr, "Enter a delay in deciseconds between screenshots to allow the client to render changes.", "Screenshot delay", 2, 10, 1, 0, TRUE) + if(!sleep_duration) + return + + if(!mob) + return + + if(!isobserver(mob)) + admin_ghost() + + mob.alpha = 0 + if(mob.hud_used) + mob.hud_used.show_hud(HUD_STYLE_NOHUD) + mob.animate_movement = NO_STEPS + + message_admins(WRAP_STAFF_LOG(usr, "started a mass screenshot operation.")) + + var/half_chunk_size = view + 1 + var/chunk_size = half_chunk_size * 2 - 1 + var/cur_x = half_chunk_size + var/cur_y = half_chunk_size + var/cur_z = mob.z + var/width + var/height + if(istype(SSmapping.z_list[cur_z], /datum/space_level)) + var/datum/space_level/cur_level = SSmapping.z_list[cur_z] + width = cur_level.x_bounds - half_chunk_size + 2 + height = cur_level.y_bounds - half_chunk_size + 2 + else + width = world.maxx - half_chunk_size + 2 + height = world.maxy - half_chunk_size + 2 + var/width_inside = width - 1 + var/height_inside = height - 1 + + while(cur_y < height) + while(cur_x < width) + mob.on_mob_jump() + mob.forceMove(locate(cur_x, cur_y, cur_z)) + sleep(sleep_duration) + winset(src, null, "command='.screenshot auto'") + if(cur_x == width_inside) + break + cur_x += chunk_size + cur_x = min(cur_x, width_inside) + if(cur_y == height_inside) + break + cur_x = half_chunk_size + cur_y += chunk_size + cur_y = min(cur_y, height_inside) + + mob.alpha = initial(mob.alpha) + if(mob.hud_used) + mob.hud_used.show_hud(HUD_STYLE_STANDARD) + mob.animate_movement = SLIDE_STEPS // Initial is incorrect + + to_chat(usr, "Provide these values when asked for the MapTileImageTool: [width] [height] [half_chunk_size] [world.icon_size]") //TODO: merge the vievars version into this or something maybe mayhaps /client/proc/cmd_debug_del_all() @@ -136,7 +203,7 @@ /client/proc/cmd_admin_grantfullaccess(mob/M in GLOB.mob_list) set category = null - set name = "Grant Full Access" + set name = "Grant Global Access" if(!check_rights(R_DEBUG|R_ADMIN)) return @@ -149,11 +216,11 @@ if (H.wear_id) var/obj/item/card/id/id = H.wear_id id.icon_state = "gold" - id:access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access() + id:access = get_access(ACCESS_LIST_GLOBAL) else var/obj/item/card/id/id = new/obj/item/card/id(M); id.icon_state = "gold" - id:access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access() + id:access = get_access(ACCESS_LIST_GLOBAL) id.registered_name = H.real_name id.registered_ref = WEAKREF(H) id.assignment = "Captain" @@ -163,7 +230,7 @@ else alert("Invalid mob") - message_admins("[key_name_admin(usr)] has granted [M.key] full access.") + message_admins("[key_name_admin(usr)] has granted [M.key] global access.") /client/proc/cmd_admin_grantallskills(mob/M in GLOB.mob_list) set category = null diff --git a/code/modules/admin/verbs/freeforghosts.dm b/code/modules/admin/verbs/freeforghosts.dm index 7d3ad324f0cf..a2f3912030e5 100644 --- a/code/modules/admin/verbs/freeforghosts.dm +++ b/code/modules/admin/verbs/freeforghosts.dm @@ -20,7 +20,7 @@ if(mind || client) ghostize(FALSE) - GLOB.freed_mob_list |= src + GLOB.freed_mob_list |= WEAKREF(src) /client/proc/free_all_mobs_in_view() set name = "Free All Mobs" diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index 8843b2bcb5f0..37bf4f1c9d85 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -13,7 +13,6 @@ codebase for the entire /TG/station commuity a TONNE easier :3 Thanks for your help! */ - //This proc allows Game Masters to grant a client access to the .getruntimelog verb //Permissions expire at the end of each round. //Runtimes can be used to meta or spot game-crashing exploits so it's advised to only grant coders that @@ -23,25 +22,24 @@ set desc = "Give somebody access to any session logfiles saved to the /log/runtime/ folder." set category = null - if(!src.admin_holder || !(admin_holder.rights & R_MOD)) - to_chat(src, "Only Admins may use this command.") + if(!src.admin_holder || !(admin_holder.rights & R_MOD) || !(admin_holder.rights & R_DEBUG)) + to_chat(src, "Access denied.") return var/client/target = tgui_input_list(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions", GLOB.clients) - if(!istype(target,/client)) + if(!istype(target, /client)) to_chat(src, "Error: giveruntimelog(): Client not found.") return + message_admins("[key_name_admin(src)] granted [key_name_admin(target)] access to runtime logs this round.") target.verbs |= /client/proc/getruntimelog to_chat(target, "You have been granted access to runtime logs. Please use them responsibly or risk being banned.") - return - //This proc allows download of runtime logs saved within the data/logs/ folder by dreamdeamon. //It works similarly to show-server-log. /client/proc/getruntimelog() set name = ".getruntimelog" - set desc = "Retrieve any session logfiles saved by dreamdeamon." + set desc = "Pick a logfile from data/logs/runtime to view." set category = null var/path = browse_files("data/logs/runtime/") @@ -52,18 +50,20 @@ return message_admins("[key_name_admin(src)] accessed file: [path]") - src << run( file(path) ) to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") - return - + src << ftp(file(path)) //This proc allows download of past server logs saved within the data/logs/ folder. //It works similarly to show-server-log. /client/proc/getserverlog() set name = ".getserverlog" - set desc = "Fetch logfiles from data/logs" + set desc = "Pick a logfile from data/logs to view." set category = null + if(!src.admin_holder || !(admin_holder.rights & (R_MOD) || !(admin_holder.rights & R_DEBUG))) + to_chat(src, "Access denied.") + return + var/path = browse_files("data/logs/") if(!path) return @@ -72,44 +72,112 @@ return message_admins("[key_name_admin(src)] accessed file: [path]") - src << run( file(path) ) to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") - return - + src << ftp(file(path)) //Other log stuff put here for the sake of organisation -//Shows today's server log -/datum/admins/proc/view_txt_log() - set name = "Show Server Log" - set desc = "Shows today's server log." +/**Shows this round's server log*/ +/datum/admins/proc/view_game_log() + set name = "Show Server Game Log" + set desc = "Shows this round's server game log." set category = "Server" - var/path = "data/logs/[time2text(world.realtime,"YYYY/MM-Month/DD-Day")].log" - if( fexists(path) ) - src << run( file(path) ) - else - var/pathyesteday = "data/logs/[time2text(world.realtime-400000,"YYYY/MM-Month/DD-Day")].log" // roughly 12 hours before this, should cover for most issues - if( fexists(pathyesteday) ) - src << run( file(pathyesteday) ) - else - to_chat(src, "Error: view_txt_log(): File not found/Invalid path([path]) or path([pathyesteday]).") - return - - return - -//Shows today's attack log -/datum/admins/proc/view_atk_log() - set category = "Admin" + if(!check_rights(R_MOD|R_DEBUG)) + return + + var/path = GLOB.world_game_log + if(!fexists(path)) + to_chat(src, "Error: view_log(): File not found/Invalid path([path]).") + return + + if(usr.client.file_spam_check()) + return + + message_admins("[key_name_admin(src)] accessed file: [path]") + to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") + src << ftp(file(path)) + +/**Shows this round's attack log*/ +/datum/admins/proc/view_attack_log() set name = "Show Server Attack Log" - set desc = "Shows today's server attack log." + set desc = "Shows this round's server attack log." + set category = "Server" + + if(!check_rights(R_MOD)) + return + + var/path = GLOB.world_attack_log + if(!fexists(path)) + to_chat(src, "Error: view_log(): File not found/Invalid path([path]).") + return + + if(usr.client.file_spam_check()) + return + + message_admins("[key_name_admin(src)] accessed file: [path]") + to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") + src << ftp(file(path)) - var/path = "data/logs/[time2text(world.realtime,"YYYY/MM-Month/DD-Day")] Attack.log" - if( fexists(path) ) - src << run( file(path) ) - else - to_chat(src, "Error: view_atk_log(): File not found/Invalid path([path]).") +/**Shows this round's runtime log*/ +/datum/admins/proc/view_runtime_log() + set name = "Show Server Runtime Log" + set desc = "Shows this round's server runtime log." + set category = "Server" + + if(!check_rights(R_DEBUG)) return - usr << run( file(path) ) - return + var/path = GLOB.world_runtime_log + if(!fexists(path)) + to_chat(src, "Error: view_log(): File not found/Invalid path([path]).") + return + + if(usr.client.file_spam_check()) + return + + message_admins("[key_name_admin(src)] accessed file: [path]") + to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") + src << ftp(file(path)) + +/**Shows this round's href log*/ +/datum/admins/proc/view_href_log() + set name = "Show Server HREF Log" + set desc = "Shows this round's server HREF log." + set category = "Server" + + if(!check_rights(R_DEBUG)) + return + + var/path = GLOB.world_href_log + if(!fexists(path)) + to_chat(src, "Error: view_log(): File not found/Invalid path([path]).") + return + + if(usr.client.file_spam_check()) + return + + message_admins("[key_name_admin(src)] accessed file: [path]") + to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") + src << ftp(file(path)) + +/**Shows this round's tgui log*/ +/datum/admins/proc/view_tgui_log() + set name = "Show Server TGUI Log" + set desc = "Shows this round's server TGUI log." + set category = "Server" + + if(!check_rights(R_DEBUG)) + return + + var/path = GLOB.tgui_log + if(!fexists(path)) + to_chat(src, "Error: view_log(): File not found/Invalid path([path]).") + return + + if(usr.client.file_spam_check()) + return + + message_admins("[key_name_admin(src)] accessed file: [path]") + to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") + src << ftp(file(path)) diff --git a/code/modules/admin/verbs/mob_verbs.dm b/code/modules/admin/verbs/mob_verbs.dm index 3aed46d5434e..376115c0d630 100644 --- a/code/modules/admin/verbs/mob_verbs.dm +++ b/code/modules/admin/verbs/mob_verbs.dm @@ -166,7 +166,7 @@ return to_chat(H, SPAN_DANGER("Message received through headset. [message_option] Transmission \"[msg]\"")) - var/message = WRAP_STAFF_LOG(usr, "subtle messaged [key_name(M)] as [message_option], saying \"[msg]\" in [get_area(M)] ([M.x],[M.y],[M.z]).") + var/message = WRAP_STAFF_LOG(usr, SPAN_STAFF_IC("subtle messaged [key_name(M)] as [message_option], saying \"[msg]\" in [get_area(M)] ([M.x],[M.y],[M.z]).")) message_admins(message, M.x, M.y, M.z) admin_ticket_log(M, message) diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index c1aa0c2359f3..e0210e4577a0 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -17,9 +17,9 @@ liaison = 1 if(liaison) - msg = SPAN_NOTICE("LIAISON: [key_name(src, 1)] (Mark) (?) (PP) (VV) (SM) (JMP) (SC): [msg]") + msg = SPAN_STAFF_IC("LIAISON: [key_name(src, 1)] [CC_MARK(src)] [ADMIN_PP(src)] [ADMIN_VV(src)] [ADMIN_SM(src)] [ADMIN_JMP_USER(src)] [ADMIN_SC(src)]: [msg]") else - msg = SPAN_NOTICE("PRAY: [key_name(src, 1)] (Mark) (?) (PP) (VV) (SM) (JMP) (SC): [msg]") + msg = SPAN_STAFF_IC("PRAY: [key_name(src, 1)] [CC_MARK(src)] [ADMIN_PP(src)] [ADMIN_VV(src)] [ADMIN_SM(src)] [ADMIN_JMP_USER(src)] [ADMIN_SC(src)]: [msg]") log_admin(msg) for(var/client/C in GLOB.admins) if(AHOLD_IS_MOD(C.admin_holder) && C.prefs.toggles_chat & CHAT_PRAYER) @@ -31,7 +31,7 @@ /proc/high_command_announce(text , mob/Sender , iamessage) var/msg = copytext(sanitize(text), 1, MAX_MESSAGE_LEN) - msg = "[SPAN_NOTICE("USCM[iamessage ? "IA" : ""]:")][key_name(Sender, 1)] (Mark) (PP) (VV) (SM) (JMP) (RPLY): [msg]" + msg = "[SPAN_STAFF_IC("USCM[iamessage ? "IA" : ""]:")][key_name(Sender, 1)] [CC_MARK(Sender)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] [ADMIN_JMP_USER(Sender)] [CC_REPLY(Sender)]: [msg]" log_admin(msg) for(var/client/C in GLOB.admins) if((R_ADMIN|R_MOD) & C.admin_holder.rights) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index d73a69f3eb95..4a4f6fa830a9 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -12,7 +12,7 @@ return if(!CLIENT_IS_STAFF(src)) - if(!CLIENT_HAS_RIGHTS(src, R_MENTOR)) + if(!CLIENT_IS_MENTOR(src)) to_chat(src, "Only staff members have permission to use this.") return if(!CONFIG_GET(flag/mentor_tools)) diff --git a/code/modules/admin/verbs/shakeshipverb.dm b/code/modules/admin/verbs/shakeshipverb.dm index 06b5cbabcd90..0434b70a17ac 100644 --- a/code/modules/admin/verbs/shakeshipverb.dm +++ b/code/modules/admin/verbs/shakeshipverb.dm @@ -1,6 +1,6 @@ /client/proc/shakeshipverb() set name = "Shake Shipmap" - set category = "Admin.Events" + set category = "Admin.Ship" var/drop = FALSE var/delayt @@ -10,7 +10,7 @@ if(!sstrength) return var/stime = tgui_input_number(src, "Time Between Shakes?", "Don't make it too long", 0, 30) - if(!sstrength) + if(!stime) return var/prompt = tgui_alert(src, "Drop people?", "Confirmation", list("Yes", "No"), 20 SECONDS) @@ -39,7 +39,6 @@ if(prompt != "Yes") return else - log_admin("[key_name_admin(src)] rocked the ship! with the strength of [sstrength], and duration of [stime]") message_admins("[key_name_admin(src)] rocked the ship! with the strength of [sstrength], and duration of [stime]") if(delayed) if(announce) diff --git a/code/modules/admin/view_variables/get_variables.dm b/code/modules/admin/view_variables/get_variables.dm index eadf2615c8bb..a2b87b0909d0 100644 --- a/code/modules/admin/view_variables/get_variables.dm +++ b/code/modules/admin/view_variables/get_variables.dm @@ -121,12 +121,12 @@ switch(.["class"]) if(VV_TEXT) - .["value"] = tgui_input_text(usr, "Enter new text:", "Text", current_value) + .["value"] = tgui_input_text(usr, "Enter new text:", "Text", current_value, encode = FALSE) if(.["value"] == null) .["class"] = null return if(VV_MESSAGE) - .["value"] = tgui_input_text(usr, "Enter new text:", "Text", current_value) + .["value"] = tgui_input_text(usr, "Enter new text:", "Text", current_value, encode = FALSE) if(.["value"] == null) .["class"] = null return diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm index a5b2af68c772..f6f2b86f31d7 100644 --- a/code/modules/admin/view_variables/reference_tracking.dm +++ b/code/modules/admin/view_variables/reference_tracking.dm @@ -12,9 +12,11 @@ SSgarbage.update_nextfire(reset_time = TRUE) return +#if !defined(UNIT_TESTS) && !defined(SPACEMAN_DMM) // Without this we just get thousands of warnings about sleeps in qdel if(!skip_alert && tgui_alert(usr,"Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", list("Yes", "No")) != "Yes") running_find_references = null return +#endif //this keeps the garbage collector from failing to collect objects being searched for in here SSgarbage.can_fire = FALSE @@ -22,7 +24,7 @@ if(usr?.client) usr.client.running_find_references = type - log_reftracker("Beginning search for references to a [type].") + log_reftracker("Beginning search for references to '[src]' a [type].") var/starting_time = world.time @@ -58,7 +60,7 @@ log_reftracker("Finished searching clients") #endif - log_reftracker("Completed search for references to a [type].") + log_reftracker("Completed search for references to '[src]' a [type].") if(usr?.client) usr.client.running_find_references = null @@ -129,6 +131,11 @@ continue //End early, don't want these logging #endif log_reftracker("Found [type] [text_ref(src)] in list [container_name].") + var/msg + for(var/i in 1 to min(10, potential_cache.len)) + msg += "[potential_cache[i]]," + if(msg) + log_reftracker("List contents: [msg]") continue var/assoc_val = null @@ -142,6 +149,11 @@ continue //End early, don't want these logging #endif log_reftracker("Found [type] [text_ref(src)] in list [container_name]\[[element_in_list]\]") + var/msg + for(var/i in 1 to min(10, potential_cache.len)) + msg += "[potential_cache[i]]," + if(msg) + log_reftracker("List contents: [msg]") continue //We need to run both of these checks, since our object could be hiding in either of them //Check normal sublists diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index d9d697f9c6f3..3d623a3c85e3 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -62,7 +62,7 @@ var/Text = href_list["adjustDamage"] - var/amount = tgui_input_number(usr, "Deal how much damage to mob? (Negative values here heal)", "Adjust [Text]loss", 0) + var/amount = tgui_input_number(usr, "Deal how much damage to mob? (Negative values here heal)", "Adjust [Text]loss", 0, 10000, -10000) if (isnull(amount)) return diff --git a/code/modules/almayer/machinery.dm b/code/modules/almayer/machinery.dm index 9116d616162c..6ea547be5f45 100644 --- a/code/modules/almayer/machinery.dm +++ b/code/modules/almayer/machinery.dm @@ -1,70 +1,12 @@ //-----USS Almayer Machinery file -----// // Put any new machines in here before map is released and everything moved to their proper positions. - - -//-----USS Almayer Props -----// -//Put any props that don't function properly, they could function in the future but for now are for looks. This system could be expanded for other maps too. ~Art - -/obj/item/prop/almayer - name = "GENERIC USS ALMAYER PROP" - desc = "THIS SHOULDN'T BE VISIBLE, AHELP 'ART-P03' IF SEEN IN ROUND WITH LOCATION" - icon = 'icons/obj/structures/props/almayer_props.dmi' - icon_state = "hangarbox" - -/obj/item/prop/almayer/box - name = "metal crate" - desc = "A metal crate used often for storing small electronics that go into dropships" - icon_state = "hangarbox" - w_class = SIZE_LARGE - -/obj/item/prop/almayer/flight_recorder - name = "\improper FR-112 flight recorder" - desc = "A small red box that contains flight data from a dropship while it's on mission. Usually referred to as the black box, although this one comes in bloody red." - icon_state = "flight_recorder" - w_class = SIZE_LARGE - -/obj/item/prop/almayer/flight_recorder/colony - name = "\improper CIR-60 colony information recorder" - desc = "A small red box that records colony announcements, colonist flatlines and other key readouts. Usually refered to the black box, although this one comes in bloody red." - icon_state = "flight_recorder" - w_class = SIZE_LARGE - -/obj/item/prop/almayer/flare_launcher - name = "\improper MJU-77/C case" - desc = "A flare launcher that usually gets mounted onto dropships to help survivability against infrared tracking missiles." - icon_state = "flare_launcher" - w_class = SIZE_SMALL - -/obj/item/prop/almayer/chaff_launcher - name = "\improper RR-247 Chaff case" - desc = "A chaff launcher that usually gets mounted onto dropships to help survivability against radar tracking missiles." - icon_state = "chaff_launcher" - w_class = SIZE_MEDIUM - -/obj/item/prop/almayer/handheld1 - name = "small handheld" - desc = "A small piece of electronic doodads" - icon_state = "handheld1" - w_class = SIZE_SMALL - -/obj/item/prop/almayer/comp_closed - name = "dropship maintenance computer" - desc = "A closed dropship maintenance computer that technicians and pilots use to find out what's wrong with a dropship. It has various outlets for different systems." - icon_state = "hangar_comp" - w_class = SIZE_LARGE - -/obj/item/prop/almayer/comp_open - name = "dropship maintenance computer" - desc = "An opened dropship maintenance computer, it seems to be off however. It's used by technicians and pilots to find damaged or broken systems on a dropship. It has various outlets for different systems." - icon_state = "hangar_comp_open" - w_class = SIZE_LARGE - /obj/structure/machinery/prop/almayer name = "GENERIC USS ALMAYER PROP" desc = "THIS SHOULDN'T BE VISIBLE, AHELP 'ART-P01' IF SEEN IN ROUND WITH LOCATION" /obj/structure/machinery/prop/almayer/hangar/dropship_part_fabricator + /obj/structure/machinery/prop/almayer/computer/PC name = "personal desktop" desc = "A small computer hooked up into the ship's computer network." diff --git a/code/modules/almayer/weaponhits.dm b/code/modules/almayer/weaponhits.dm new file mode 100644 index 000000000000..1f3a566ebbda --- /dev/null +++ b/code/modules/almayer/weaponhits.dm @@ -0,0 +1,123 @@ +#define WEAPON_MISSILE 1 +#define WEAPON_RAILGUN 2 +#define HIT_CHANCE_CHEAT 100 +#define HIT_CHANCE_STANDARD 70 +/** + * Proc called to hit the ship with weapons + * + * Hits the ship with the weapon of choice + * Calling Shakeship acoording to the weapon used + * All sounds that should happen when they hit are in here already. + * Probably doesn't work in other shipmaps. + * Arguments: + * * weaponused - chooses the weapon through a switchcase. 1 for missiles, 2 for railguns, 3 for particle cannons. + * * location - location in the ship where the explosion will be created. + * * point_defense - If you want the Almayer to attempt taking down the incoming fire + * * salvo - identifies it as a salvo or not. + */ +/proc/weaponhits(weaponused, location, point_defense = FALSE, salvo = FALSE) + + + switch(weaponused) + + if(WEAPON_MISSILE) + var/datum/cause_data/ashm_cause_data = create_cause_data("Anti-Ship missile") + if(point_defense == FALSE) + if(salvo == TRUE) + var/shotspacing + for(var/turf/picked_atom in location) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), picked_atom, 400, 10, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, ashm_cause_data), shotspacing SECONDS) + shotspacing += 1 + shakeship(10, 10, TRUE, FALSE) + weaponhits_effects(WEAPON_MISSILE) + else + cell_explosion(location, 350, 1, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, ashm_cause_data) + shakeship(10, 10, TRUE, FALSE) + weaponhits_effects(WEAPON_MISSILE) + if(point_defense == TRUE) + var/hitchance = HIT_CHANCE_STANDARD + if(salvo == TRUE) + var/confirmedhit + var/shotspacing + for(var/turf/picked_atom in location) + if(prob(hitchance)) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), picked_atom, 400, 10, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, ashm_cause_data), shotspacing SECONDS) + shakeship(10, 10, TRUE, FALSE) + confirmedhit += 1 + else + weaponhits_effects(WEAPON_MISSILE, TRUE, shotspacing) + + shotspacing += 1 + if(confirmedhit > 0) + weaponhits_effects(WEAPON_MISSILE, FALSE) + confirmedhit = 0 + else + if(prob(hitchance)) + cell_explosion(location, 400, 10, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, ashm_cause_data) + shakeship(10, 10, TRUE, FALSE) + weaponhits_effects(WEAPON_MISSILE, FALSE) + else + weaponhits_effects(WEAPON_MISSILE, TRUE) + + if(WEAPON_RAILGUN) + var/datum/cause_data/antishiprailgun_cause_data = create_cause_data("Railgun shot") + var/hitchance = HIT_CHANCE_CHEAT + if(point_defense == TRUE) + hitchance = HIT_CHANCE_STANDARD + if(salvo == TRUE) + var/confirmedhit + for(var/turf/picked_atom in location) + if(prob(hitchance)) + cell_explosion(picked_atom, 600, 600, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, antishiprailgun_cause_data) + shakeship(5, 5, FALSE, FALSE) + confirmedhit += 1 + if(confirmedhit > 0) + weaponhits_effects(WEAPON_RAILGUN) + if(confirmedhit < 1) + weaponhits_effects(WEAPON_RAILGUN, TRUE) + + else if(salvo == FALSE) + if(prob(hitchance)) + cell_explosion(location, 600, 600, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, antishiprailgun_cause_data) + shakeship(5, 5, FALSE, FALSE) + weaponhits_effects(WEAPON_RAILGUN) + else + weaponhits_effects(WEAPON_RAILGUN, TRUE) + +/proc/weaponhits_effects(weaponused, weaponmiss = FALSE, shotspacing = 0) + switch(weaponused) + if(WEAPON_MISSILE) + if(!weaponmiss) + for(var/mob/living/carbon/current_mob in GLOB.living_mob_list) + if(!is_mainship_level(current_mob.z)) + continue + playsound_client(current_mob.client, 'sound/effects/metal_crash.ogg', 100 ) + playsound_client(current_mob.client, 'sound/effects/bigboom3.ogg', 100) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound_client), current_mob.client, 'sound/effects/pry2.ogg', 20), 1 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound_client), current_mob.client, 'sound/effects/double_klaxon.ogg'), 2 SECONDS) + else + for(var/mob/living/carbon/current_mob in GLOB.living_mob_list) + if(!is_mainship_level(current_mob.z)) + continue + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound_client), current_mob.client, 'sound/effects/laser_point_defence_success.ogg', 100), shotspacing SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), current_mob.client, SPAN_DANGER("You hear the Point Defense systems shooting down a missile!")), shotspacing SECONDS) + + if(WEAPON_RAILGUN) + if(!weaponmiss) + for(var/mob/living/carbon/current_mob in GLOB.living_mob_list) + if(!is_mainship_level(current_mob.z)) + continue + playsound_client(current_mob.client, 'sound/effects/bigboom3.ogg', 50) + playsound_client(current_mob.client, 'sound/effects/railgunhit.ogg', 50) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound_client), current_mob.client, 'sound/effects/double_klaxon.ogg'), 2 SECONDS) + else + for(var/mob/living/carbon/current_mob in GLOB.living_mob_list) + if(!is_mainship_level(current_mob.z)) + continue + playsound_client (current_mob.client, 'sound/effects/railgun_miss.ogg', 60) + to_chat(current_mob.client, SPAN_DANGER("You hear railgun shots barely missing the hull!")) +//REMOVE THIS WHEN WE USE THESE DEFS SOMEWHERE ELSE OR ELSE IT STRAIGHT UP WON'T WORK. +#undef WEAPON_MISSILE +#undef WEAPON_RAILGUN +#undef HIT_CHANCE_CHEAT +#undef HIT_CHANCE_STANDARD diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index 67472743a738..86bc3acf61a4 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -151,9 +151,13 @@ to_chat(user, SPAN_DANGER("Assembly part missing!")) return if(istype(a_left,a_right.type))//If they are the same type it causes issues due to window code - switch(alert("Which side would you like to use?",,"Left","Right")) - if("Left") a_left.attack_self(user) - if("Right") a_right.attack_self(user) + var/response = tgui_alert(user, "Which side would you like to use?", "Side selection", list("Left","Right")) + if(response && (user.l_hand == src || user.r_hand == src)) + switch(response) + if("Left") + a_left.attack_self(user) + if("Right") + a_right.attack_self(user) return else if(!istype(a_left,/obj/item/device/assembly/igniter)) diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 8e5d2d4f48d3..c7658d8b1104 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -183,3 +183,12 @@ .["min_delay"] = PROXY_MINIMUM_DELAY .["max_delay"] = PROXY_MAXIMUM_DELAY + +/obj/item/device/assembly/prox_sensor/attack_alien(mob/living/carbon/xenomorph/xeno) + . = ..() + if(scanning) + playsound(loc, "alien_claw_metal", 25, 1) + xeno.animation_attack_on(src) + xeno.visible_message(SPAN_XENOWARNING("[xeno] slashes [src], turning it off!"), SPAN_XENONOTICE("You slash [src], turning it off!")) + toggle_scan() + return XENO_ATTACK_ACTION diff --git a/code/modules/assembly/signaller.dm b/code/modules/assembly/signaller.dm index fe5ce3e3f426..4ac25854e8ea 100644 --- a/code/modules/assembly/signaller.dm +++ b/code/modules/assembly/signaller.dm @@ -139,7 +139,7 @@ /obj/item/device/assembly/signaller/proc/set_frequency(new_frequency) SSradio.remove_object(src, frequency) frequency = new_frequency - radio_connection = SSradio.add_object(src, frequency, RADIO_CHAT) + radio_connection = SSradio.add_object(src, frequency, RADIO_SIGNALS) /obj/item/device/assembly/signaller/Destroy() SSradio.remove_object(src, frequency) diff --git a/code/modules/asset_cache/asset_cache_item.dm b/code/modules/asset_cache/asset_cache_item.dm index 52ebc7190372..72d976bf11f1 100644 --- a/code/modules/asset_cache/asset_cache_item.dm +++ b/code/modules/asset_cache/asset_cache_item.dm @@ -33,3 +33,9 @@ if (extstart) ext = ".[copytext(name, extstart+1)]" resource = file + +/datum/asset_cache_item/vv_edit_var(var_name, var_value) + return FALSE + +/datum/asset_cache_item/CanProcCall(procname) + return FALSE diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index aea849b9bd28..3f0775c0b65d 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -143,6 +143,7 @@ assets = list( "wylogo.png" = 'html/images/wylogo.png', "uscmlogo.png" = 'html/images/uscmlogo.png', + "upplogo.png" = 'html/images/upplogo.png', "faxwylogo.png" = 'html/images/faxwylogo.png', "faxbackground.jpg" = 'html/images/faxbackground.jpg', ) @@ -204,10 +205,10 @@ /datum/asset/spritesheet/playtime_rank/register() var/icon_file = 'icons/mob/hud/hud.dmi' - var/tier1_state = "hudxenoupgrade1" - var/tier2_state = "hudxenoupgrade2" - var/tier3_state = "hudxenoupgrade3" - var/tier4_state = "hudxenoupgrade4" + var/tier1_state = "hudxenoupgrade2" + var/tier2_state = "hudxenoupgrade3" + var/tier3_state = "hudxenoupgrade4" + var/tier4_state = "hudxenoupgrade5" var/icon/tier1_icon = icon(icon_file, tier1_state, SOUTH) var/icon/tier2_icon = icon(icon_file, tier2_state, SOUTH) @@ -271,7 +272,6 @@ /datum/asset/spritesheet/ranks/register() var/icon_file = 'icons/mob/hud/marine_hud.dmi' - var/list/squads = list("Alpha", "Bravo", "Charlie", "Delta", "Foxtrot", "Cryo") var/list/icon_data = list( list("Mar", null), @@ -280,14 +280,12 @@ list("Med", "hudsquad_med"), list("SG", "hudsquad_gun"), list("Spc", "hudsquad_spec"), - list("RTO", "hudsquad_rto"), + list("TL", "hudsquad_tl"), list("SL", "hudsquad_leader"), ) - var/i - for(i = 1; i < length(squads); i++) - var/squad = squads[i] - var/color = squad_colors[i] + for(var/datum/squad/marine/squad in RoleAuthority.squads) + var/color = squad.equipment_color for(var/iref in icon_data) var/list/iconref = iref var/icon/background = icon('icons/mob/hud/marine_hud.dmi', "hudsquad", SOUTH) diff --git a/code/modules/asset_cache/transports/webroot_transport.dm b/code/modules/asset_cache/transports/webroot_transport.dm new file mode 100644 index 000000000000..e3cb33b8fabf --- /dev/null +++ b/code/modules/asset_cache/transports/webroot_transport.dm @@ -0,0 +1,87 @@ +/// CDN Webroot asset transport. +/datum/asset_transport/webroot + name = "CDN Webroot asset transport" + +/datum/asset_transport/webroot/Load() + if (validate_config(log = FALSE)) + load_existing_assets() + +/// Processes thru any assets that were registered before we were loaded as a transport. +/datum/asset_transport/webroot/proc/load_existing_assets() + for (var/asset_name in SSassets.cache) + var/datum/asset_cache_item/ACI = SSassets.cache[asset_name] + save_asset_to_webroot(ACI) + +/// Register a browser asset with the asset cache system +/// We also save it to the CDN webroot at this step instead of waiting for send_assets() +/// asset_name - the identifier of the asset +/// asset - the actual asset file or an asset_cache_item datum. +/datum/asset_transport/webroot/register_asset(asset_name, asset) + . = ..() + var/datum/asset_cache_item/ACI = . + + if (istype(ACI) && ACI.hash) + save_asset_to_webroot(ACI) + +/// Saves the asset to the webroot taking into account namespaces and hashes. +/datum/asset_transport/webroot/proc/save_asset_to_webroot(datum/asset_cache_item/ACI) + var/webroot = CONFIG_GET(string/asset_cdn_webroot) + var/newpath = "[webroot][get_asset_suffex(ACI)]" + if (fexists(newpath)) + return + if (fexists("[newpath].gz")) //its a common pattern in webhosting to save gzip'ed versions of text files and let the webserver serve them up as gzip compressed normal files, sometimes without keeping the original version. + return + return fcopy(ACI.resource, newpath) + +/// Returns a url for a given asset. +/// asset_name - Name of the asset. +/// asset_cache_item - asset cache item datum for the asset, optional, overrides asset_name +/datum/asset_transport/webroot/get_asset_url(asset_name, datum/asset_cache_item/asset_cache_item) + if (!istype(asset_cache_item)) + asset_cache_item = SSassets.cache[asset_name] + var/url = CONFIG_GET(string/asset_cdn_url) //config loading will handle making sure this ends in a / + return "[url][get_asset_suffex(asset_cache_item)]" + +/datum/asset_transport/webroot/proc/get_asset_suffex(datum/asset_cache_item/asset_cache_item) + var/base = "[copytext(asset_cache_item.hash, 1, 3)]/" + var/filename = "asset.[asset_cache_item.hash][asset_cache_item.ext]" + if (length(asset_cache_item.namespace)) + base = "namespaces/[copytext(asset_cache_item.namespace, 1, 3)]/[asset_cache_item.namespace]/" + if (!asset_cache_item.namespace_parent) + filename = "[asset_cache_item.name]" + return base + filename + + +/// webroot asset sending - does nothing unless passed legacy assets +/datum/asset_transport/webroot/send_assets(client/client, list/asset_list) + . = FALSE + var/list/legacy_assets = list() + if (!islist(asset_list)) + asset_list = list(asset_list) + for (var/asset_name in asset_list) + var/datum/asset_cache_item/ACI = asset_list[asset_name] + if (!istype(ACI)) + ACI = SSassets.cache[asset_name] + if (!ACI) + legacy_assets += asset_name //pass it on to base send_assets so it can output an error + continue + if (ACI.legacy) + legacy_assets[asset_name] = ACI + if (length(legacy_assets)) + . = ..(client, legacy_assets) + + +/// webroot slow asset sending - does nothing. +/datum/asset_transport/webroot/send_assets_slow(client/client, list/files, filerate) + return FALSE + +/datum/asset_transport/webroot/validate_config(log = TRUE) + if (!CONFIG_GET(string/asset_cdn_url)) + if (log) + log_asset("ERROR: [type]: Invalid Config: ASSET_CDN_URL") + return FALSE + if (!CONFIG_GET(string/asset_cdn_webroot)) + if (log) + log_asset("ERROR: [type]: Invalid Config: ASSET_CDN_WEBROOT") + return FALSE + return TRUE diff --git a/code/modules/autowiki/autowiki.dm b/code/modules/autowiki/autowiki.dm new file mode 100644 index 000000000000..8b38ec76706b --- /dev/null +++ b/code/modules/autowiki/autowiki.dm @@ -0,0 +1,36 @@ +/// When the `AUTOWIKI` define is enabled, will generate an output file for tools/autowiki/autowiki.js to consume. +/// Autowiki code intentionally still *exists* even without the define, to ensure developers notice +/// when they break it immediately, rather than until CI or worse, call time. +#if defined(AUTOWIKI) || defined(UNIT_TESTS) +/proc/setup_autowiki() + Master.sleep_offline_after_initializations = FALSE + UNTIL(SSticker.current_state == GAME_STATE_PREGAME) + + //trigger things to run the whole process + SSticker.request_start() + CONFIG_SET(number/round_end_countdown, 0) + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(generate_autowiki))) + +/proc/generate_autowiki() + var/output = generate_autowiki_output() + rustg_file_write(output, "data/autowiki_edits.txt") + qdel(world) +#endif + +/// Returns a string of the autowiki output file +/proc/generate_autowiki_output() + var/total_output = "" + + for (var/datum/autowiki/autowiki_type as anything in subtypesof(/datum/autowiki)) + var/datum/autowiki/autowiki = new autowiki_type + var/output = autowiki.generate() + + if (!istext(output)) + CRASH("[autowiki_type] does not generate a proper output!") + + total_output += json_encode(list( + "title" = autowiki.page, + "text" = output, + )) + "\n" + + return total_output diff --git a/code/modules/autowiki/pages/_page.dm b/code/modules/autowiki/pages/_page.dm new file mode 100644 index 000000000000..8e745ace61c2 --- /dev/null +++ b/code/modules/autowiki/pages/_page.dm @@ -0,0 +1,54 @@ +/// A representation of an automated wiki page. +/datum/autowiki + /// The page on the wiki to be replaced. + /// This should never be a user-facing page, like "Guide to circuits". + /// It should always be a template that only Autowiki should touch. + /// For example: "Template:Autowiki/CircuitInfo". + var/page + +/// Override and return the new text of the page. +/// This proc can be impure, usually to call `upload_file`. +/datum/autowiki/proc/generate() + SHOULD_CALL_PARENT(FALSE) + CRASH("[type] does not implement generate()!") + +/// Generates an auto formatted template user. +/// Your autowiki should ideally be a *lot* of these. +/// It lets wiki editors edit it much easier later, without having to enter repo. +/// Parameters will be passed in by name. That means your template should expect +/// something that looks like `{{ Autowiki_Circuit|name=Combiner|description=This combines }}` +/// Lists, which must be array-like (no keys), will be turned into a flat list with their key and a number, +/// such that list("food" = list("fruit", "candy")) -> food1=fruit|food2=candy +/datum/autowiki/proc/include_template(name, parameters) + var/template_text = "{{[name]" + + var/list/prepared_parameters = list() + for (var/key in parameters) + var/value = parameters[key] + if (islist(value)) + for (var/index in 1 to length(value)) + prepared_parameters["[key][index]"] = "[value[index]]" + else + prepared_parameters[key] = value + + for (var/parameter_name in prepared_parameters) + template_text += "|[parameter_name]=" + template_text += "[prepared_parameters[parameter_name]]" + + template_text += "}}" + + return template_text + +/// Takes an icon and uploads it to Autowiki-name.png. +/// Do your best to make sure this is unique, so it doesn't clash with other autowiki icons. +/datum/autowiki/proc/upload_icon(icon/icon, name) + // Fuck you + if (IsAdminAdvancedProcCall()) + return + + fcopy(icon, "data/autowiki_files/[name].png") + +/// Escape a parameter such that it can be correctly put inside a wiki output +/datum/autowiki/proc/escape_value(parameter) + // | is a special character in MediaWiki, and must be escaped by...using another template. + return replacetextEx(parameter, "|", "{{!}}") diff --git a/code/modules/autowiki/pages/guns.dm b/code/modules/autowiki/pages/guns.dm new file mode 100644 index 000000000000..0946b552fe31 --- /dev/null +++ b/code/modules/autowiki/pages/guns.dm @@ -0,0 +1,118 @@ +/datum/autowiki/guns + page = "Template:Autowiki/Content/GunData" + + +/datum/autowiki/guns/generate() + var/output = "" + + var/list/gun_to_ammo = list() + + for(var/obj/item/ammo_magazine/typepath as anything in subtypesof(/obj/item/ammo_magazine) - subtypesof(/obj/item/ammo_magazine/internal)) + LAZYADD(gun_to_ammo[initial(typepath.gun_type)], typepath) + + for(var/typepath in sort_list(subtypesof(/obj/item/weapon/gun), GLOBAL_PROC_REF(cmp_typepaths_asc))) + var/obj/item/weapon/gun/generating_gun = new typepath() + + var/filename = SANITIZE_FILENAME(escape_value(format_text(generating_gun.name))) + + var/list/gun_data = generating_gun.ui_data() + + var/list/valid_mag_types = list() + for(var/path in gun_to_ammo) + if(!istype(generating_gun, path)) + continue + + valid_mag_types += gun_to_ammo[path] + + var/ammo = "" + var/damage_table = "" + for(var/ammo_typepath in valid_mag_types) + var/obj/item/ammo_magazine/generating_mag = new ammo_typepath() + + var/ammo_filename = SANITIZE_FILENAME(escape_value(format_text(generating_mag.name))) + + if(!fexists("data/autowiki_files/[ammo_filename].png")) + upload_icon(getFlatIcon(generating_mag, no_anim = TRUE), ammo_filename) + + var/datum/ammo/current_ammo = GLOB.ammo_list[generating_mag.default_ammo] + + ammo += include_template("Autowiki/AmmoMagazine", list( + "icon" = escape_value(ammo_filename), + "name" = escape_value(generating_mag.name), + "capacity" = escape_value(generating_mag.max_rounds), + "damage" = escape_value(current_ammo.damage), + "max_range" = escape_value(current_ammo.max_range), + "fall_off" = escape_value(current_ammo.damage_falloff), + "penetration" = escape_value(current_ammo.penetration), + "punch" = escape_value(current_ammo.pen_armor_punch), + )) + + generating_gun.current_mag = generating_mag + + var/list/gun_ammo_data = generating_gun.ui_data() + var/list/armor_data = list() + + var/iterator = 1 + for(var/header in gun_ammo_data["damage_armor_profile_headers"]) + var/damage = gun_ammo_data["damage_armor_profile_marine"][iterator] + armor_data["armor-[header]"] = damage + iterator++ + + var/list/damage = list("ammo_name" = escape_value(generating_mag.name)) + damage += armor_data + + damage_table += include_template("Autowiki/DamageVersusArmorRow", damage) + + qdel(generating_mag) + + gun_data["ammo_types"] = ammo + gun_data["damage_table"] = damage_table + + var/list/attachments_by_slot = list() + for(var/obj/item/attachable/attachment_typepath as anything in generating_gun.attachable_allowed) + LAZYADD(attachments_by_slot[capitalize(initial(attachment_typepath.slot))], attachment_typepath) + + var/attachments = "" + for(var/slot in attachments_by_slot) + var/list/attachments_in_slot = "" + + for(var/attachment_typepath in attachments_by_slot[slot]) + var/obj/item/attachable/generating_attachment = new attachment_typepath() + + var/attachment_filename = SANITIZE_FILENAME(escape_value(format_text(generating_attachment.name))) + + if(!fexists("data/autowiki_files/[attachment_filename].png")) + upload_icon(getFlatIcon(generating_attachment, no_anim = TRUE), attachment_filename) + + attachments_in_slot += include_template("Autowiki/AvailableAttachment", list( + "icon" = escape_value(attachment_filename), + "name" = escape_value(generating_attachment.name), + )) + + qdel(generating_attachment) + + attachments += include_template("Autowiki/AttachmentsBySlot", list( + "slot" = escape_value(slot), + "attachments" = attachments_in_slot, + )) + gun_data["attachments"] = attachments + + + upload_icon(getFlatIcon(generating_gun, no_anim = TRUE), filename) + gun_data["icon"] = filename + + output += include_template("Autowiki/Gun", gun_data) + + qdel(generating_gun) + + return output + +/datum/autowiki/guns/proc/wiki_sanitize_assoc(list/sanitizing_list) + var/list/sanitized = list() + + for(var/key in sanitizing_list) + var/value = sanitizing_list[key] + + sanitized[escape_value(key)] = escape_value(value) + + return sanitized diff --git a/code/modules/character_traits/biology_traits.dm b/code/modules/character_traits/biology_traits.dm index 2ff7292f7427..87fb0b70ec36 100644 --- a/code/modules/character_traits/biology_traits.dm +++ b/code/modules/character_traits/biology_traits.dm @@ -59,11 +59,13 @@ return ADD_TRAIT(target, TRAIT_LISPING, TRAIT_SOURCE_QUIRK) + target.speech_problem_flag = TRUE ..() /datum/character_trait/biology/lisp/unapply_trait(mob/living/carbon/human/target) REMOVE_TRAIT(target, TRAIT_LISPING, TRAIT_SOURCE_QUIRK) + target.speech_problem_flag = FALSE ..() /datum/character_trait/biology/bad_leg @@ -113,3 +115,21 @@ ..() //datum/character_trait/biology/bad_leg/unapply_trait(mob/living/carbon/human/target) // IMPOSSIBLE + +/datum/character_trait/biology/hardcore + trait_name = "Hardcore" + trait_desc = "One life. One chance. (Rifleman Only)" + applyable = TRUE + cost = 1 + +/datum/character_trait/biology/hardcore/apply_trait(mob/living/carbon/human/target, datum/equipment_preset/preset) + if(target.job != JOB_SQUAD_MARINE) + to_chat(target, SPAN_WARNING("Only riflemen can have the Hardcore trait.")) + return + + ADD_TRAIT(target, TRAIT_HARDCORE, TRAIT_SOURCE_QUIRK) + ..() + +/datum/character_trait/biology/hardcore/unapply_trait(mob/living/carbon/human/target) + REMOVE_TRAIT(target, TRAIT_HARDCORE, TRAIT_SOURCE_QUIRK) + ..() diff --git a/code/modules/character_traits/robotic_limbs.dm b/code/modules/character_traits/robotic_limbs.dm index ee72f22d9d07..be72eca2f6fc 100644 --- a/code/modules/character_traits/robotic_limbs.dm +++ b/code/modules/character_traits/robotic_limbs.dm @@ -20,7 +20,7 @@ /datum/character_trait/robo_limb/apply_trait(mob/living/carbon/human/target, datum/equipment_preset/preset) var/string_paygrade = preset.load_rank(target) var/datum/paygrade/paygrade_datum = GLOB.paygrades[string_paygrade] - if(paygrade_datum.ranking < minimum_ranking) + if(paygrade_datum?.ranking < minimum_ranking) to_chat(target, SPAN_WARNING("You aren't a high enough rank to be eligible to have a prosthetic [robo_limb_name]!")) return var/obj/limb/limb = target.get_limb(code_limb) diff --git a/code/modules/clans/client.dm b/code/modules/clans/client.dm index 2d06725736ce..d1f403c08300 100644 --- a/code/modules/clans/client.dm +++ b/code/modules/clans/client.dm @@ -405,10 +405,10 @@ to_chat(src, SPAN_WARNING("This player doesn't belong to a clan!")) return - var/list/datum/rank/ranks = clan_ranks.Copy() + var/list/datum/yautja_rank/ranks = clan_ranks.Copy() ranks -= CLAN_RANK_ADMIN // Admin rank should not and cannot be obtained from here - var/datum/rank/chosen_rank + var/datum/yautja_rank/chosen_rank if(has_clan_permission(CLAN_PERMISSION_ADMIN_MODIFY, warn = FALSE)) var/input = tgui_input_list(src, "Select the rank to change this user to.", "Select Rank", ranks) diff --git a/code/modules/clans/rank.dm b/code/modules/clans/rank.dm index b0748ce60662..a6b78a0d95e9 100644 --- a/code/modules/clans/rank.dm +++ b/code/modules/clans/rank.dm @@ -1,4 +1,4 @@ -/datum/rank +/datum/yautja_rank var/name var/limit_type @@ -7,29 +7,29 @@ var/permissions = CLAN_PERMISSION_USER_VIEW var/permission_required = CLAN_PERMISSION_USER_MODIFY -/datum/rank/unblooded +/datum/yautja_rank/unblooded name = CLAN_RANK_UNBLOODED permission_required = CLAN_PERMISSION_ADMIN_MODIFY -/datum/rank/young +/datum/yautja_rank/young name = CLAN_RANK_YOUNG -/datum/rank/blooded +/datum/yautja_rank/blooded name = CLAN_RANK_BLOODED -/datum/rank/elite +/datum/yautja_rank/elite name = CLAN_RANK_ELITE limit_type = CLAN_LIMIT_SIZE limit = 5 -/datum/rank/elder +/datum/yautja_rank/elder name = CLAN_RANK_ELDER limit_type = CLAN_LIMIT_SIZE limit = 12 -/datum/rank/leader +/datum/yautja_rank/leader name = CLAN_RANK_LEADER permissions = CLAN_PERMISSION_USER_ALL @@ -37,7 +37,7 @@ limit_type = CLAN_LIMIT_NUMBER limit = 1 -/datum/rank/ancient +/datum/yautja_rank/ancient name = CLAN_RANK_ADMIN permission_required = CLAN_PERMISSION_ADMIN_MANAGER diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index be2f977b6a53..2facce7c3a59 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -27,7 +27,7 @@ var/area = null var/time_died_as_mouse = null //when the client last died as a mouse - var/donator = 0 + var/donator = FALSE var/adminhelped = 0 var/datum/click_intercept = null @@ -42,7 +42,7 @@ var/played = 0 var/midi_silenced = 0 var/datum/soundOutput/soundOutput - var/list/volume_preferences = list(1, 0.5, 1, 0.85)//Game, music, admin midis, lobby music + var/list/volume_preferences = list(1, 0.5, 1, 0.6)//Game, music, admin midis, lobby music //////////// //SECURITY// diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index c0a4dd718877..3722b32fb2b4 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -46,6 +46,7 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( /client/proc/toggle_eject_to_hand, /client/proc/toggle_automatic_punctuation, /client/proc/toggle_middle_mouse_click, + /client/proc/toggle_ability_deactivation, /client/proc/toggle_clickdrag_override, /client/proc/toggle_dualwield, /client/proc/toggle_middle_mouse_swap_hands, @@ -103,6 +104,11 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( // Tgui Topic middleware if(tgui_Topic(href_list)) return + + //Logs all other hrefs + if(CONFIG_GET(flag/log_hrefs) && GLOB.world_href_log) + WRITE_LOG(GLOB.world_href_log, "[src] (usr:[usr]) || [hsrc ? "[hsrc] " : ""][href]
") + if(href_list["reload_tguipanel"]) nuke_chat() if(href_list["reload_statbrowser"]) @@ -144,8 +150,17 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( return else if(href_list["FaxView"]) - var/info = locate(href_list["FaxView"]) - show_browser(usr, "[info]", "Fax Message", "Fax Message") + + var/datum/fax/info = locate(href_list["FaxView"]) + + if(!istype(info)) + return + + if(info.photo_list) + for(var/photo in info.photo_list) + usr << browse_rsc(info.photo_list[photo], photo) + + show_browser(usr, "[info.data]", "Fax Message", "Fax Message") else if(href_list["medals_panel"]) GLOB.medals_panel.tgui_interact(mob) @@ -194,10 +209,6 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( var/datum/entity/player/P = get_player_from_key(key) P.remove_note(index) - //Logs all hrefs - if(CONFIG_GET(flag/log_hrefs) && href_logfile) - href_logfile << "[time2text(world.timeofday,"hh:mm")] [src] (usr:[usr]) || [hsrc ? "[hsrc] " : ""][href]
" - switch(href_list["_src_"]) if("admin_holder") hsrc = admin_holder @@ -276,11 +287,6 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( if(!(connection in list("seeker", "web"))) //Invalid connection type. return null - if(IsGuestKey(key)) - alert(src,"This server doesn't allow guest accounts to play. Please go to http://www.byond.com/ and register for a key.","Guest","OK") - qdel(src) - return - GLOB.clients += src GLOB.directory[ckey] = src @@ -304,7 +310,7 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( if(!CONFIG_GET(flag/no_localhost_rank)) var/static/list/localhost_addresses = list("127.0.0.1", "::1") if(isnull(address) || (address in localhost_addresses)) - var/datum/admins/admin = new("!localhost!", R_EVERYTHING, ckey) + var/datum/admins/admin = new("!localhost!", RL_HOST, ckey) admin.associate(src) RoleAuthority.roles_whitelist[ckey] = WHITELIST_EVERYTHING @@ -424,7 +430,7 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( for(var/line in lines) if(src.ckey == line) - src.donator = 1 + src.donator = TRUE add_verb(src, /client/proc/set_ooc_color_self) //if(prefs.window_skin & TOGGLE_WINDOW_SKIN) @@ -441,6 +447,10 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( ////////////// /client/Del() if(!gc_destroyed) + gc_destroyed = world.time + if (!QDELING(src)) + stack_trace("Client does not purport to be QDELING, this is going to cause bugs in other places!") + SEND_SIGNAL(src, COMSIG_PARENT_QDELETING, TRUE) Destroy() return ..() @@ -464,6 +474,9 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( if(CLIENT_IS_STAFF(src)) message_admins("Admin logout: [key_name(src)]") + var/list/adm = get_admin_counts(R_MOD) + REDIS_PUBLISH("byond.access", "type" = "logout", "key" = src.key, "remaining" = length(adm["total"]), "afk" = length(adm["afk"])) + ..() return QDEL_HINT_HARDDEL_NOW @@ -477,6 +490,10 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( log_access("Login: [key_name(src)] from [address ? address : "localhost"]-[computer_id] || BYOND v[byond_version].[byond_build]") if(CLIENT_IS_STAFF(src)) message_admins("Admin login: [key_name(src)]") + + var/list/adm = get_admin_counts(R_MOD) + REDIS_PUBLISH("byond.access", "type" = "login", "key" = src.key, "remaining" = length(adm["total"]), "afk" = length(adm["afk"])) + if(CONFIG_GET(flag/log_access)) for(var/mob/M in GLOB.player_list) if( M.key && (M.key != key) ) @@ -595,7 +612,8 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( */ /client/proc/init_verbs() if(IsAdminAdvancedProcCall()) - return + alert_proccall("init_verbs") + return PROC_BLOCKED var/list/verblist = list() var/list/verbstoprocess = verbs.Copy() if(mob) @@ -692,17 +710,8 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( winset(src, "srvkeybinds-[REF(key)]", "parent=default;name=[key];command=[looc]") else winset(src, "srvkeybinds-[REF(key)]", "parent=default;name=[key];command=looc") - if(MOD_CHANNEL) - if(admin_holder?.check_for_rights(R_MOD)) - if(prefs.tgui_say) - var/msay = tgui_say_create_open_command(MOD_CHANNEL) - winset(src, "srvkeybinds-[REF(key)]", "parent=default;name=[key];command=[msay]") - else - winset(src, "srvkeybinds-[REF(key)]", "parent=default;name=[key];command=msay") - else - winset(src, "srvkeybinds-[REF(key)]", "parent=default;name=[key];command=") if(ADMIN_CHANNEL) - if(admin_holder?.check_for_rights(R_ADMIN)) + if(admin_holder?.check_for_rights(R_MOD)) if(prefs.tgui_say) var/asay = tgui_say_create_open_command(ADMIN_CHANNEL) winset(src, "srvkeybinds-[REF(key)]", "parent=default;name=[key];command=[asay]") diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm index 06dafdbea63a..634fd8fb627e 100644 --- a/code/modules/client/player_details.dm +++ b/code/modules/client/player_details.dm @@ -7,7 +7,12 @@ GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details var/list/post_logout_callbacks = list() var/list/played_names = list() //List of names this key played under this round var/byond_version = "Unknown" + /// The descriminator for larva queue ordering: Generally set to timeofdeath except for facehuggers/admin z-level play + var/larva_queue_time +/datum/player_details/New() + larva_queue_time = world.time + return ..() /proc/log_played_names(ckey, ...) if(!ckey) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index c3ddfde38b1e..4f1161709657 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -53,6 +53,7 @@ var/const/MAX_SAVE_SLOTS = 10 var/be_special = 0 // Special role selection var/toggle_prefs = TOGGLE_MIDDLE_MOUSE_CLICK|TOGGLE_DIRECTIONAL_ATTACK|TOGGLE_MEMBER_PUBLIC|TOGGLE_AMBIENT_OCCLUSION|TOGGLE_VEND_ITEM_TO_HAND // flags in #define/mode.dm var/auto_fit_viewport = FALSE + var/adaptive_zoom = 0 var/UI_style = "midnight" var/toggles_admin = TOGGLES_ADMIN_DEFAULT var/toggles_chat = TOGGLES_CHAT_DEFAULT @@ -99,12 +100,13 @@ var/const/MAX_SAVE_SLOTS = 10 var/predator_flavor_text = "" //CO-specific preferences var/commander_sidearm = "Mateba" + var/affiliation = "Unaligned" //SEA specific preferences ///holds our preferred job options for jobs - var/pref_special_job_options = list() - - var/preferred_survivor_variant = ANY_SURVIVOR + var/list/pref_special_job_options = list() + ///Holds assignment of character slots to jobs. + var/list/pref_job_slots = list() //WL Council preferences. var/yautja_status = WHITELIST_NORMAL @@ -122,8 +124,9 @@ var/const/MAX_SAVE_SLOTS = 10 var/age = 19 //age of character var/spawnpoint = "Arrivals Shuttle" //where this character will spawn (0-2). var/underwear = "Boxers (Camo Conforming)" //underwear type - var/undershirt = "Undershirt" //undershirt type + var/undershirt = "Undershirt (Tan)" //undershirt type var/backbag = 2 //backpack type + var/preferred_armor = "Random" //preferred armor type (from their primary prep vendor) var/h_style = "Crewcut" //Hair type var/r_hair = 0 //Hair color @@ -330,6 +333,8 @@ var/const/MAX_SAVE_SLOTS = 10 dat += "

Occupation Choices:

" dat += "
" dat += "\tSet Role Preferences" + dat += "
" + dat += "\tAssign Character Slots to Roles" dat += "" dat += "
" @@ -371,6 +376,8 @@ var/const/MAX_SAVE_SLOTS = 10 dat += "Backpack Type: [backbaglist[backbag]]
" + dat += "Preferred Armor: [preferred_armor]
" + dat += "Show Job Gear: [show_job_gear ? "True" : "False"]
" dat += "Background: Cycle Background
" @@ -383,7 +390,7 @@ var/const/MAX_SAVE_SLOTS = 10 if(length(gear)) dat += "
" for(var/i = 1; i <= gear.len; i++) - var/datum/gear/G = gear_datums[gear[i]] + var/datum/gear/G = gear_datums_by_name[gear[i]] if(G) total_cost += G.cost dat += "[gear[i]] ([G.cost] points) Remove
" @@ -466,16 +473,13 @@ var/const/MAX_SAVE_SLOTS = 10 dat += "Be [role_name]: [be_special & (1<
" n++ - - dat += "
" - dat += "\tSet Role Preferences" - dat += "
" if(MENU_CO) if(RoleAuthority.roles_whitelist[user.ckey] & WHITELIST_COMMANDER) dat += "
" dat += "

Commander Settings:

" dat += "Commander Whitelist Status: [commander_status]
" dat += "Commander Sidearm: [commander_sidearm]
" + dat += "Commander Affiliation: [affiliation]
" dat += "
" else dat += "You do not have the whitelist for this role." @@ -568,6 +572,7 @@ var/const/MAX_SAVE_SLOTS = 10 dat += "

Game Settings:

" dat += "Ambient Occlusion: [toggle_prefs & TOGGLE_AMBIENT_OCCLUSION ? "Enabled" : "Disabled"]
" dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"]
" + dat += "Adaptive Zoom: [adaptive_zoom ? "[adaptive_zoom * 2]x" : "Disabled"]
" dat += "tgui Window Mode: [(tgui_fancy) ? "Fancy (default)" : "Compatible (slower)"]
" dat += "tgui Window Placement: [(tgui_lock) ? "Primary monitor" : "Free (default)"]
" dat += "Play Admin Midis: [(toggles_sound & SOUND_MIDI) ? "Yes" : "No"]
" @@ -585,11 +590,13 @@ var/const/MAX_SAVE_SLOTS = 10 dat += "
" dat += "

Gameplay Toggles:

" dat += "Toggle Being Able to Hurt Yourself: \ - [toggle_prefs & TOGGLE_IGNORE_SELF ? "On" : "Off"]
" +
[toggle_prefs & TOGGLE_IGNORE_SELF ? "Off" : "On"]
" dat += "Toggle Help Intent Safety: \ [toggle_prefs & TOGGLE_HELP_INTENT_SAFETY ? "On" : "Off"]
" dat += "Toggle Middle Mouse Ability Activation: \ [toggle_prefs & TOGGLE_MIDDLE_MOUSE_CLICK ? "On" : "Off"]
" + dat += "Toggle Ability Deactivation: \ + [toggle_prefs & TOGGLE_ABILITY_DEACTIVATION_OFF ? "Off" : "On"]
" dat += "Toggle Directional Assist: \ [toggle_prefs & TOGGLE_DIRECTIONAL_ATTACK ? "On" : "Off"]
" dat += "Toggle Magazine Auto-Ejection: \ @@ -622,11 +629,6 @@ var/const/MAX_SAVE_SLOTS = 10 dat += "Spawn as Miscellaneous: [toggles_ert & PLAY_MISC ? "Yes" : "No"]
" dat += "
" - dat += "
" - dat += "

Survivor Settings:

" - dat += "Preferred Survivor Variant: [preferred_survivor_variant]" - dat += "
" - dat += "" winshow(user, "preferencewindow", TRUE) @@ -653,7 +655,7 @@ var/const/MAX_SAVE_SLOTS = 10 var/list/active_role_names = GLOB.gamemode_roles[GLOB.master_mode] if(!active_role_names) - active_role_names = ROLES_REGULAR_ALL + active_role_names = ROLES_DISTRESS_SIGNAL for(var/role_name as anything in active_role_names) var/datum/job/job = RoleAuthority.roles_by_name[role_name] @@ -684,10 +686,12 @@ var/const/MAX_SAVE_SLOTS = 10 HTML += "[job.disp_title]" if(job.job_options) - if(!pref_special_job_options || !pref_special_job_options[role_name]) + if(pref_special_job_options) + pref_special_job_options[role_name] = sanitize_inlist(pref_special_job_options[role_name], job.job_options, job.job_options[1]) + else pref_special_job_options[role_name] = job.job_options[1] - var/txt = pref_special_job_options[role_name] + var/txt = job.job_options[pref_special_job_options[role_name]] HTML += "[txt]" HTML += "" @@ -744,6 +748,83 @@ var/const/MAX_SAVE_SLOTS = 10 onclose(user, "mob_occupation", user.client, list("_src_" = "prefs", "preference" = "job", "task" = "close")) return +//limit - The amount of jobs allowed per column. Defaults to 13 to make it look nice. +//splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice. +//width - Screen' width. Defaults to 550 to make it look nice. +//height - Screen's height. Defaults to 500 to make it look nice. +/datum/preferences/proc/set_job_slots(mob/user, limit = 19, list/splitJobs = list(JOB_CHIEF_REQUISITION), width = 950, height = 700) + if(!RoleAuthority) + return + + var/HTML = "" + HTML += "
" + HTML += "Assign character slots to jobs.
Unavailable occupations are crossed out.

" + HTML += "
Done

" // Easier to press up here. + HTML += "
" // Table within a table for alignment, also allows you to easily add more colomns. + HTML += "" + var/index = -1 + + //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. + + var/list/active_role_names = GLOB.gamemode_roles[GLOB.master_mode] + if(!active_role_names) + active_role_names = ROLES_DISTRESS_SIGNAL + + for(var/role_name as anything in active_role_names) + var/datum/job/job = RoleAuthority.roles_by_name[role_name] + if(!job) + debug_log("Missing job for prefs: [role_name]") + continue + index++ + if((index >= limit) || (job.title in splitJobs)) + HTML += "
" + index = 0 + + HTML += "" + continue + else if(job.flags_startup_parameters & ROLE_WHITELISTED && !(RoleAuthority.roles_whitelist[user.ckey] & job.flags_whitelist)) + HTML += "[job.disp_title]" + continue + else if(!job.can_play_role(user.client)) + HTML += "[job.disp_title]" + continue + + HTML += "[job.disp_title]" + + var/slot_name = get_job_slot_name(job.title) + HTML += "" + + HTML += "
" + if(jobban_isbanned(user, job.title)) + HTML += "[job.disp_title]BANNED
WHITELISTED
TIMELOCKED
[slot_name]" + HTML += "
" + HTML += "

" + + var/b_color + var/msg + if(toggle_prefs & TOGGLE_START_JOIN_CURRENT_SLOT) + b_color = "red" + msg = "This preference is ignored when joining at the start of the round." + else + b_color = "green" + msg = "This preference is used when joining at the start of the round." + HTML += "
[msg]
" + if(toggle_prefs & TOGGLE_LATE_JOIN_CURRENT_SLOT) + b_color = "red" + msg = "This preference is ignored when joining a round in progress." + else + b_color = "green" + msg = "This preference is used when joining a round in progress." + HTML += "
[msg]
" + + HTML += "
Reset
" + HTML += "
" + + close_browser(user, "preferences") + show_browser(user, HTML, "Job Assignment", "job_slots_assignment", "size=[width]x[height]") + onclose(user, "job_slots_assignment", user.client, list("_src_" = "prefs", "preference" = "job_slot", "task" = "close")) + return + /datum/preferences/proc/SetRecords(mob/user) var/HTML = "" HTML += "
" @@ -834,6 +915,40 @@ var/const/MAX_SAVE_SLOTS = 10 job_preference_list[J.title] = priority return TRUE +/datum/preferences/proc/assign_job_slot(mob/user, target_job) + var/list/slot_options = list(JOB_SLOT_RANDOMISED_TEXT = JOB_SLOT_RANDOMISED_SLOT, JOB_SLOT_CURRENT_TEXT = JOB_SLOT_CURRENT_SLOT) + var/savefile/S = new /savefile(path) + var/slot_name + for(var/slot in 1 to MAX_SAVE_SLOTS) + S.cd = "/character[slot]" + S["real_name"] >> slot_name + if(slot_name) + slot_options["[slot_name] (slot #[slot])"] = slot + var/chosen_slot = tgui_input_list(user, "Assign character for [target_job] job", "Slot assignment", slot_options) + if(chosen_slot) + pref_job_slots[target_job] = slot_options[chosen_slot] + set_job_slots(user) + +/datum/preferences/proc/get_job_slot_name(job_title) + . = JOB_SLOT_CURRENT_TEXT + if(!(job_title in pref_job_slots)) + return + var/slot_number = pref_job_slots[job_title] + switch(slot_number) + if(JOB_SLOT_RANDOMISED_SLOT) + return JOB_SLOT_RANDOMISED_TEXT + if(1 to MAX_SAVE_SLOTS) + var/savefile/S = new /savefile(path) + S.cd = "/character[slot_number]" + return "[S["real_name"]] (slot #[slot_number])" + +/datum/preferences/proc/reset_job_slots() + pref_job_slots = list() + var/datum/job/J + for(var/role in RoleAuthority.roles_by_path) + J = RoleAuthority.roles_by_path[role] + pref_job_slots[J.title] = JOB_SLOT_CURRENT_SLOT + /datum/preferences/proc/process_link(mob/user, list/href_list) var/whitelist_flags = RoleAuthority.roles_whitelist[user.ckey] @@ -859,40 +974,52 @@ var/const/MAX_SAVE_SLOTS = 10 SetJob(user, href_list["text"], priority) else SetChoices(user) - return 1 + return TRUE + if("job_slot") + switch(href_list["task"]) + if("close") + close_browser(user, "job_slots_assignment") + ShowChoices(user) + if("assign") + assign_job_slot(user, href_list["target_job"]) + if("start_join") + toggle_prefs ^= TOGGLE_START_JOIN_CURRENT_SLOT + set_job_slots(user) + if("late_join") + toggle_prefs ^= TOGGLE_LATE_JOIN_CURRENT_SLOT + set_job_slots(user) + if("reset") + reset_job_slots() + set_job_slots(user) + else + set_job_slots(user) + return TRUE if("loadout") switch(href_list["task"]) if("input") + var/gear_category = tgui_input_list(user, "Select gear category: ", "Gear to add", gear_datums_by_category) + if(!gear_category) + return + var/choice = tgui_input_list(user, "Select gear to add: ", gear_category, gear_datums_by_category[gear_category]) + if(!choice) + return - var/list/valid_gear_choices = list() - - for(var/gear_name in gear_datums) - var/datum/gear/G = gear_datums[gear_name] - if(G.whitelisted && !is_alien_whitelisted(user, G.whitelisted)) - continue - valid_gear_choices += gear_name - - var/choice = tgui_input_list(user, "Select gear to add: ", "Gear to add", valid_gear_choices) - - if(choice && gear_datums[choice]) - - var/total_cost = 0 - - if(isnull(gear) || !islist(gear)) gear = list() - - if(gear && gear.len) - for(var/gear_name in gear) - if(gear_datums[gear_name]) - var/datum/gear/G = gear_datums[gear_name] - total_cost += G.cost - - var/datum/gear/C = gear_datums[choice] - total_cost += C.cost - if(C && total_cost <= MAX_GEAR_COST) - gear += choice - to_chat(user, SPAN_NOTICE("Added \the '[choice]' for [C.cost] points ([MAX_GEAR_COST - total_cost] points remaining).")) - else - to_chat(user, SPAN_WARNING("Adding \the '[choice]' will exceed the maximum loadout cost of [MAX_GEAR_COST] points.")) + var/total_cost = 0 + var/datum/gear/G + if(isnull(gear) || !islist(gear)) + gear = list() + if(gear.len) + for(var/gear_name in gear) + G = gear_datums_by_name[gear_name] + total_cost += G?.cost + + G = gear_datums_by_category[gear_category][choice] + total_cost += G.cost + if(total_cost <= MAX_GEAR_COST) + gear += G.display_name + to_chat(user, SPAN_NOTICE("Added \the '[G.display_name]' for [G.cost] points ([MAX_GEAR_COST - total_cost] points remaining).")) + else + to_chat(user, SPAN_WARNING("Adding \the '[choice]' will exceed the maximum loadout cost of [MAX_GEAR_COST] points.")) if("remove") var/i_remove = text2num(href_list["gear"]) @@ -1103,8 +1230,9 @@ var/const/MAX_SAVE_SLOTS = 10 if("pred_gender") predator_gender = predator_gender == MALE ? FEMALE : MALE if("pred_age") - var/new_predator_age = tgui_input_number(user, "Choose your Predator's age(20 to 10000):", "Character Preference", 1234, 10000, 20) - if(new_predator_age) predator_age = max(min( round(text2num(new_predator_age)), 10000),20) + var/new_predator_age = tgui_input_number(user, "Choose your Predator's age(175 to 3000):", "Character Preference", 1234, 3000, 175) + if(new_predator_age) + predator_age = max(min( round(text2num(new_predator_age)), 3000),175) if("pred_trans_type") var/new_translator_type = tgui_input_list(user, "Choose your translator type.", "Translator Type", PRED_TRANSLATORS) if(!new_translator_type) @@ -1125,7 +1253,7 @@ var/const/MAX_SAVE_SLOTS = 10 return predator_mask_material = new_pred_mask_mat if("pred_armor_mat") - var/new_pred_armor_mat = tgui_input_list(user, "Choose your armour material:", "Armor Material", PRED_MATERIALS) + var/new_pred_armor_mat = tgui_input_list(user, "Choose your armor material:", "Armor Material", PRED_MATERIALS) if(!new_pred_armor_mat) return predator_armor_material = new_pred_armor_mat @@ -1203,6 +1331,13 @@ var/const/MAX_SAVE_SLOTS = 10 return commander_sidearm = new_co_sidearm + if("co_affiliation") + var/new_co_affiliation = tgui_input_list(user, "Choose your faction affiliation.", "Commanding Officer's Affiliation", FACTION_ALLEGIANCE_USCM_COMMANDER) + if(!new_co_affiliation) + return + affiliation = new_co_affiliation + + if("yautja_status") var/list/options = list("Normal" = WHITELIST_NORMAL) @@ -1466,6 +1601,11 @@ var/const/MAX_SAVE_SLOTS = 10 if(new_pref_squad) preferred_squad = new_pref_squad + if("prefarmor") + var/new_pref_armor = tgui_input_list(user, "Choose your character's default style of armor:", "Character Preferences", GLOB.armor_style_list) + if(new_pref_armor) + preferred_armor = new_pref_armor + if("limbs") var/limb_name = tgui_input_list(user, "Which limb do you want to change?", list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand")) if(!limb_name) return @@ -1555,12 +1695,6 @@ var/const/MAX_SAVE_SLOTS = 10 return religion = choice - if("preferred_survivor_variant") - var/new_preferred_survivor_variant = tgui_input_list(user, "Choose your preferred survivor variant:", "Preferred Survivor Variant", SURVIVOR_VARIANT_LIST) - if(!new_preferred_survivor_variant) - return - preferred_survivor_variant = new_preferred_survivor_variant - if("special_job_select") var/datum/job/job = RoleAuthority.roles_by_name[href_list["text"]] if(!job) @@ -1722,6 +1856,12 @@ var/const/MAX_SAVE_SLOTS = 10 if(auto_fit_viewport && owner) owner.fit_viewport() + if("adaptive_zoom") + adaptive_zoom += 1 + if(adaptive_zoom == 3) + adaptive_zoom = 0 + owner?.adaptive_zoom() + if("inputstyle") var/result = tgui_alert(user, "Which input style do you want?", "Input Style", list("Modern", "Legacy")) if(!result) @@ -1801,11 +1941,32 @@ var/const/MAX_SAVE_SLOTS = 10 ShowChoices(user) return 1 -// Transfers both physical characteristics and character information to character -/datum/preferences/proc/copy_all_to(mob/living/carbon/human/character, safety = 0) + +/// Loads appropriate character slot for the given job as assigned in preferences. +/datum/preferences/proc/find_assigned_slot(job_title, is_late_join = FALSE) + if(toggle_prefs & (is_late_join ? TOGGLE_LATE_JOIN_CURRENT_SLOT : TOGGLE_START_JOIN_CURRENT_SLOT)) + return + var/slot_for_job = pref_job_slots[job_title] + switch(slot_for_job) + if(JOB_SLOT_RANDOMISED_SLOT) + be_random_body = TRUE + be_random_name = TRUE + if(1 to MAX_SAVE_SLOTS) + load_character(slot_for_job) + +/// Transfers both physical characteristics and character information to character +/datum/preferences/proc/copy_all_to(mob/living/carbon/human/character, job_title, is_late_join = FALSE, check_datacore = FALSE) if(!istype(character)) return + find_assigned_slot(job_title, is_late_join) + if(check_datacore && !(be_random_body && be_random_name)) + for(var/datum/data/record/record as anything in GLOB.data_core.locked) + if(record.fields["name"] == real_name) + be_random_body = TRUE + be_random_name = TRUE + break + if(be_random_name) real_name = random_name(gender) @@ -1821,20 +1982,22 @@ var/const/MAX_SAVE_SLOTS = 10 character.voice = real_name character.name = character.real_name - character.flavor_texts["general"] = flavor_texts["general"] - character.flavor_texts["head"] = flavor_texts["head"] - character.flavor_texts["face"] = flavor_texts["face"] - character.flavor_texts["eyes"] = flavor_texts["eyes"] - character.flavor_texts["torso"] = flavor_texts["torso"] - character.flavor_texts["arms"] = flavor_texts["arms"] - character.flavor_texts["hands"] = flavor_texts["hands"] - character.flavor_texts["legs"] = flavor_texts["legs"] - character.flavor_texts["feet"] = flavor_texts["feet"] - - character.med_record = strip_html(med_record) - character.sec_record = strip_html(sec_record) - character.gen_record = strip_html(gen_record) - character.exploit_record = strip_html(exploit_record) + if(!be_random_body) + character.flavor_texts["general"] = flavor_texts["general"] + character.flavor_texts["head"] = flavor_texts["head"] + character.flavor_texts["face"] = flavor_texts["face"] + character.flavor_texts["eyes"] = flavor_texts["eyes"] + character.flavor_texts["torso"] = flavor_texts["torso"] + character.flavor_texts["arms"] = flavor_texts["arms"] + character.flavor_texts["hands"] = flavor_texts["hands"] + character.flavor_texts["legs"] = flavor_texts["legs"] + character.flavor_texts["feet"] = flavor_texts["feet"] + + if(!be_random_name) + character.med_record = strip_html(med_record) + character.sec_record = strip_html(sec_record) + character.gen_record = strip_html(gen_record) + character.exploit_record = strip_html(exploit_record) character.age = age character.gender = gender @@ -1983,47 +2146,6 @@ var/const/MAX_SAVE_SLOTS = 10 message_admins("[character] ([character.ckey]) has spawned with their gender as plural or neuter. Please notify coders.") character.gender = MALE - -// Transfers the character's information (name, flavor text, records, roundstart clothes, etc.) to the mob -/datum/preferences/proc/copy_information_to(mob/living/carbon/human/character, safety = 0) - if(!istype(character)) - return - - if(be_random_name) - real_name = random_name(gender) - - if(CONFIG_GET(flag/humans_need_surnames)) - var/firstspace = findtext(real_name, " ") - var/name_length = length(real_name) - if(!firstspace) //we need a surname - real_name += " [pick(last_names)]" - else if(firstspace == name_length) - real_name += "[pick(last_names)]" - - character.real_name = real_name - character.voice = real_name - character.name = character.real_name - - character.flavor_texts["general"] = flavor_texts["general"] - character.flavor_texts["head"] = flavor_texts["head"] - character.flavor_texts["face"] = flavor_texts["face"] - character.flavor_texts["eyes"] = flavor_texts["eyes"] - character.flavor_texts["torso"] = flavor_texts["torso"] - character.flavor_texts["arms"] = flavor_texts["arms"] - character.flavor_texts["hands"] = flavor_texts["hands"] - character.flavor_texts["legs"] = flavor_texts["legs"] - character.flavor_texts["feet"] = flavor_texts["feet"] - - character.med_record = med_record - character.sec_record = sec_record - character.gen_record = gen_record - character.exploit_record = exploit_record - - character.origin = origin - character.personal_faction = faction - character.religion = religion - - /datum/preferences/proc/open_load_dialog(mob/user) var/dat = "" dat += "
" diff --git a/code/modules/client/preferences_gear.dm b/code/modules/client/preferences_gear.dm index 3c28324236ce..e712e267fb2d 100644 --- a/code/modules/client/preferences_gear.dm +++ b/code/modules/client/preferences_gear.dm @@ -1,694 +1,811 @@ -var/global/list/gear_datums = list() +var/global/list/gear_datums_by_category = list() +var/global/list/gear_datums_by_name = list() /proc/populate_gear_list() - for(var/type in typesof(/datum/gear)-/datum/gear) - var/datum/gear/G = new type() - gear_datums[G.display_name] = G - return 1 + var/datum/gear/G + for(var/gear_type in subtypesof(/datum/gear)) + G = new gear_type() + if(!G.display_name) + continue //Skipping parent types that are not actual items. + if(!G.category) + log_debug("Improper gear datum: [gear_type].") + continue + if(G.display_name in gear_datums_by_name) + log_debug("Duplicate gear datum name: [G.display_name].") + continue + LAZYSET(gear_datums_by_category[G.category], "[G.display_name] [G.cost == 1 ? "(1 point)" : "([G.cost] points)"]", G) + gear_datums_by_name[G.display_name] = G /datum/gear var/display_name // Name/index. + var/category //Used for sorting in the loadout selection. var/path // Path to item. - var/cost // Number of points used. - var/slot // Slot to equip to. + var/cost = 2 // Number of points used. + var/slot // Slot to equip to, if any. var/list/allowed_roles // Roles that can spawn with this item. - var/whitelisted // Term to check the whitelist for.. var/list/allowed_origins -// This is sorted both by slot and alphabetically! Don't fuck it up! -// Headslot items +/datum/gear/eyewear + category = "Eyewear" + slot = WEAR_EYES -/datum/gear/cmbandana - display_name = "USCM Bandana (Green)" - path = /obj/item/clothing/head/cmbandana - cost = 3 - slot = WEAR_HEAD +/datum/gear/eyewear/aviators + display_name = "Aviator shades" + path = /obj/item/clothing/glasses/sunglasses/aviator + +/datum/gear/eyewear/eyepatch + display_name = "Eyepatch" + path = /obj/item/clothing/glasses/eyepatch + +/datum/gear/eyewear/rpg_glasses + display_name = "Marine RPG Glasses" + path = /obj/item/clothing/glasses/regular allowed_origins = USCM_ORIGINS -/datum/gear/cmbandanatan - display_name = "USCM Bandana (Tan)" - path = /obj/item/clothing/head/cmbandana/tan - cost = 3 - slot = WEAR_HEAD +/datum/gear/eyewear/prescription_glasses + display_name = "Prescription Glasses" + path = /obj/item/clothing/glasses/regular/hipster + +/datum/gear/eyewear/goggles + display_name = "Ballistic goggles" + path = /obj/item/clothing/glasses/mgoggles + +/datum/gear/eyewear/prescription_goggles + display_name = "Prescription ballistic goggles" + path = /obj/item/clothing/glasses/mgoggles/prescription + +/datum/gear/eyewear/goggles_black + display_name = "Ballistic goggles, black" + path = /obj/item/clothing/glasses/mgoggles/black + +/datum/gear/eyewear/goggles_orange + display_name = "Ballistic goggles, orange" + path = /obj/item/clothing/glasses/mgoggles/orange + +/datum/gear/eyewear/bimex_shades + display_name = "BiMex personal shades" + path = /obj/item/clothing/glasses/sunglasses/big + +/datum/gear/eyewear/sunglasses + display_name = "Sunglasses" + path = /obj/item/clothing/glasses/sunglasses + +/datum/gear/eyewear/prescription_sunglasses + display_name = "Prescription sunglasses" + path = /obj/item/clothing/glasses/sunglasses/prescription + +/datum/gear/mask + category = "Masks and scarves" + slot = WEAR_FACE + +/datum/gear/mask/balaclava_black + display_name = "Balaclava, black" + path = /obj/item/clothing/mask/balaclava + +/datum/gear/mask/balaclava_green + display_name = "Balaclava, green" + path = /obj/item/clothing/mask/balaclava/tactical + +/datum/gear/mask/coif + display_name = "Coif" + path = /obj/item/clothing/mask/rebreather/scarf + +/datum/gear/mask/face_wrap_black + display_name = "Face wrap, black" + path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask/black + +/datum/gear/mask/face_wrap_green + display_name = "Face wrap, green" + path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask/green + +/datum/gear/mask/face_wrap_grey + display_name = "Face wrap, grey" + path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask + +/datum/gear/mask/face_wrap_red + display_name = "Face wrap, red" + path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask/red + +/datum/gear/mask/face_wrap_tan + display_name = "Face wrap, tan" + path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask/tan + +/datum/gear/mask/face_wrap_squad + display_name = "Face wrap, squad specific" + path =/obj/item/clothing/mask/rebreather/scarf/tacticalmask/squad + +/datum/gear/mask/gas + display_name = "Gas mask" + path = /obj/item/clothing/mask/gas + +/datum/gear/mask/scarf_black + display_name = "Scarf, black" + path = /obj/item/clothing/mask/tornscarf/black + +/datum/gear/mask/scarf_desert + display_name = "Scarf, desert" + path = /obj/item/clothing/mask/tornscarf/desert + +/datum/gear/mask/scarf_green + display_name = "Scarf, green" + path = /obj/item/clothing/mask/tornscarf/green + +/datum/gear/mask/scarf_grey + display_name = "Scarf, grey" + path = /obj/item/clothing/mask/tornscarf + +/datum/gear/mask/scarf_urban + display_name = "Scarf, urban" + path = /obj/item/clothing/mask/tornscarf/urban + +/datum/gear/mask/scarf_white + display_name = "Scarf, white" + path = /obj/item/clothing/mask/tornscarf/snow + +/datum/gear/mask/uscm allowed_origins = USCM_ORIGINS -/datum/gear/cmbeanie - display_name = "USCM Beanie (Gray)" - path = /obj/item/clothing/head/beanie/gray +/datum/gear/mask/uscm/balaclava_green + display_name = "USCM balaclava, green" + path = /obj/item/clothing/mask/rebreather/scarf/green + +/datum/gear/mask/uscm/balaclava_grey + display_name = "USCM balaclava, grey" + path = /obj/item/clothing/mask/rebreather/scarf/gray + +/datum/gear/mask/uscm/balaclava_tan + display_name = "USCM balaclava, tan" + path = /obj/item/clothing/mask/rebreather/scarf/tan + +/datum/gear/headwear + category = "Headwear" cost = 3 slot = WEAR_HEAD + +/datum/gear/headwear/durag_black + display_name = "Durag, black" + path = /obj/item/clothing/head/durag/black + +/datum/gear/headwear/durag + display_name = "Durag, mission specific" + path = /obj/item/clothing/head/durag + +/datum/gear/headwear/uscm allowed_origins = USCM_ORIGINS -/datum/gear/cmbeanie/green - display_name = "USCM Beanie (Green)" +/datum/gear/headwear/uscm/bandana_green + display_name = "USCM bandana, green" + path = /obj/item/clothing/head/cmbandana + +/datum/gear/headwear/uscm/bandana_tan + display_name = "USCM bandana, tan" + path = /obj/item/clothing/head/cmbandana/tan + +/datum/gear/headwear/uscm/beanie_grey + display_name = "USCM beanie, grey" + path = /obj/item/clothing/head/beanie/gray + +/datum/gear/headwear/uscm/beanie_green + display_name = "USCM beanie, green" path = /obj/item/clothing/head/beanie/green -/datum/gear/cmbeanie/tan - display_name = "USCM Beanie (Tan)" +/datum/gear/headwear/uscm/beanie_tan + display_name = "USCM beanie, tan" path = /obj/item/clothing/head/beanie/tan -/datum/gear/squadberet - display_name = "USCM Beret (Squad Specific)" +/datum/gear/headwear/uscm/beret_squad + display_name = "USCM beret, squad specific" path = /obj/item/clothing/head/beret/cm/squadberet - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS -/datum/gear/cmberet - display_name = "USCM Beret (Green)" + +/datum/gear/headwear/uscm/beret_green + display_name = "USCM beret, green" path = /obj/item/clothing/head/beret/cm - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS -/datum/gear/cmberettan - display_name = "USCM Beret (Tan)" +/datum/gear/headwear/uscm/beret_tan + display_name = "USCM beret, tan" path = /obj/item/clothing/head/beret/cm/tan - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS -/datum/gear/cmheadband - display_name = "USCM Headband (Green)" - path = /obj/item/clothing/head/headband - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS +/datum/gear/headwear/uscm/boonie_olive + display_name = "USCM boonie hat, olive" + path = /obj/item/clothing/head/cmcap/boonie -/datum/gear/cmheadbandred - display_name = "USCM Headband (Red)" - path = /obj/item/clothing/head/headband/red - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS +/datum/gear/headwear/uscm/boonie_tan + display_name = "USCM boonie hat, tan" + path = /obj/item/clothing/head/cmcap/boonie/tan -/datum/gear/cmheadbandtan - display_name = "USCM Headband (Tan)" - path = /obj/item/clothing/head/headband/tan - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS +/datum/gear/headwear/uscm/cap + display_name = "USCM cap" + path = /obj/item/clothing/head/cmcap -/datum/gear/cmheadbandbrown - display_name = "USCM Headband (Brown)" +/datum/gear/headwear/uscm/headband_brown + display_name = "USCM headband, brown" path = /obj/item/clothing/head/headband/brown - cost = 3 - slot = WEAR_HEAD -/datum/gear/cmheadbandgray - display_name = "USCM Headband (Gray)" +/datum/gear/headwear/uscm/headband_green + display_name = "USCM headband, green" + path = /obj/item/clothing/head/headband + +/datum/gear/headwear/uscm/headband_grey + display_name = "USCM headband, grey" path = /obj/item/clothing/head/headband/gray - cost = 3 - slot = WEAR_HEAD -/datum/gear/cmheadbandsquad - display_name = "USCM Headband (Squad)" +/datum/gear/headwear/uscm/headband_red + display_name = "USCM headband, red" + path = /obj/item/clothing/head/headband/red + +/datum/gear/headwear/uscm/headband_tan + display_name = "USCM headband, tan" + path = /obj/item/clothing/head/headband/tan + +/datum/gear/headwear/uscm/headband_squad + display_name = "USCM headband, squad specific" path = /obj/item/clothing/head/headband/squad - cost = 3 - slot = WEAR_HEAD -/datum/gear/cmheadset - display_name = "USCM Earpiece" +/datum/gear/headwear/uscm/headset + display_name = "USCM headset" path = /obj/item/clothing/head/headset - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS -/datum/gear/cmcap - display_name = "USCM Cap" - path = /obj/item/clothing/head/cmcap - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS +/datum/gear/helmet_garb + category = "Helmet accessories" + cost = 1 -/datum/gear/booniehat - display_name = "USCM Boonie Hat (Olive)" - path = /obj/item/clothing/head/cmcap/boonie - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS +/datum/gear/helmet_garb/flair_initech + display_name = "Flair, Initech" + path = /obj/item/prop/helmetgarb/flair_initech -/datum/gear/booniehattan - display_name = "USCM Boonie Hat (Tan)" - path = /obj/item/clothing/head/cmcap/boonie/tan - cost = 3 - slot = WEAR_HEAD - allowed_origins = USCM_ORIGINS +/datum/gear/helmet_garb/flair_io + display_name = "Flair, Io" + path = /obj/item/prop/helmetgarb/flair_io -/datum/gear/durag - display_name = "Durag (Mission Specific)" - path = /obj/item/clothing/head/durag - cost = 3 - slot = WEAR_HEAD +/datum/gear/helmet_garb/flair_peace + display_name = "Flair, Peace and Love" + path = /obj/item/prop/helmetgarb/flair_peace -/datum/gear/duragblack - display_name = "Durag (Black)" - path = /obj/item/clothing/head/durag/black - cost = 3 - slot = WEAR_HEAD +/datum/gear/helmet_garb/flair_uscm + display_name = "Flair, USCM" + path = /obj/item/prop/helmetgarb/flair_uscm -/datum/gear/eyepatch - display_name = "Eyepatch" - path = /obj/item/clothing/glasses/eyepatch - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/helmet_gasmask + display_name = "M5 integrated gasmask" + path = /obj/item/prop/helmetgarb/helmet_gasmask -/datum/gear/thugshades - display_name = "BiMex Personal Shades" - path = /obj/item/clothing/glasses/sunglasses/big - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/gunoil + display_name = "Gun oil" + path = /obj/item/prop/helmetgarb/gunoil -/datum/gear/sunglasses - display_name = "Cheap Sunglasses" - path = /obj/item/clothing/glasses/sunglasses - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/netting + display_name = "Helmet netting" + path = /obj/item/prop/helmetgarb/netting -/datum/gear/prescription_sunglasses - display_name = "Prescription Sunglasses" - path = /obj/item/clothing/glasses/sunglasses/prescription - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/lucky_feather + display_name = "Lucky feather, red" + path = /obj/item/prop/helmetgarb/lucky_feather -/datum/gear/cigar - display_name = "Premium Cigar" - path = /obj/item/clothing/mask/cigarette/cigar - slot = WEAR_FACE - cost = 2 +/datum/gear/helmet_garb/lucky_feather/yellow + display_name = "Lucky feather, yellow" + path = /obj/item/prop/helmetgarb/lucky_feather/yellow -/datum/gear/classic_cigar - display_name = "Classic Cigar" - path = /obj/item/clothing/mask/cigarette/cigar/classic - slot = WEAR_FACE - cost = 3 +/datum/gear/helmet_garb/lucky_feather/purple + display_name = "Lucky feather, purple" + path = /obj/item/prop/helmetgarb/lucky_feather/purple -/datum/gear/cigarette - display_name = "Cigarette" - path = /obj/item/clothing/mask/cigarette - slot = WEAR_FACE - cost = 1 +/datum/gear/helmet_garb/lucky_feather/blue + display_name = "Lucky feather, blue" + path = /obj/item/prop/helmetgarb/lucky_feather/blue -/datum/gear/balaclava - display_name = "Black Balaclava" - path = /obj/item/clothing/mask/balaclava - slot = WEAR_FACE - cost = 2 +/datum/gear/helmet_garb/broken_nvgs + display_name = "Night vision goggles, broken" + path = /obj/item/prop/helmetgarb/helmet_nvg/cosmetic -/datum/gear/balaclava/green - display_name = "Green Balaclava" - path = /obj/item/clothing/mask/balaclava/tactical - slot = WEAR_FACE - cost = 2 +/datum/gear/helmet_garb/prescription_bottle + display_name = "Prescription bottle" + path = /obj/item/prop/helmetgarb/prescription_bottle -/datum/gear/coif - display_name = "Coif" - path = /obj/item/clothing/mask/rebreather/scarf - cost = 2 - slot = WEAR_FACE +/datum/gear/helmet_garb/raincover + display_name = "Rain cover" + path = /obj/item/prop/helmetgarb/raincover -/datum/gear/cmbalaclava - display_name = "USCM Balaclava (Green)" - path = /obj/item/clothing/mask/rebreather/scarf/green - cost = 2 - slot = WEAR_FACE - allowed_origins = USCM_ORIGINS +/datum/gear/helmet_garb/rabbits_foot + display_name = "Rabbit's foot" + path = /obj/item/prop/helmetgarb/rabbitsfoot -/datum/gear/cmbalaclava/tan - display_name = "USCM Balaclava (Tan)" - path = /obj/item/clothing/mask/rebreather/scarf/tan - cost = 2 - slot = WEAR_FACE +/datum/gear/helmet_garb/rosary + display_name = "Rosary" + path = /obj/item/prop/helmetgarb/rosary -/datum/gear/cmbalaclava/gray - display_name = "USCM Balaclava (Gray)" - path = /obj/item/clothing/mask/rebreather/scarf/gray - cost = 2 - slot = WEAR_FACE +/datum/gear/helmet_garb/spent_buck + display_name = "Spent buckshot" + path = /obj/item/prop/helmetgarb/spent_buckshot -/datum/gear/cmgoggles - display_name = "Ballistic Goggles" - path = /obj/item/clothing/glasses/mgoggles - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/spent_flechette + display_name = "Spent flechette" + path = /obj/item/prop/helmetgarb/spent_flech -/datum/gear/cmPgoggles - display_name = "Prescription Ballistic Goggles" - path = /obj/item/clothing/glasses/mgoggles/prescription - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/spent_slugs + display_name = "Spent slugs" + path = /obj/item/prop/helmetgarb/spent_slug -/datum/gear/cmgogglesblack - display_name = "Ballistic Goggles (Black)" - path = /obj/item/clothing/glasses/mgoggles/black - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/spacejam_tickets + display_name = "Tickets to Space Jam" + path = /obj/item/prop/helmetgarb/spacejam_tickets -/datum/gear/cmgogglesorange - display_name = "Ballistic Goggles (Orange)" - path = /obj/item/clothing/glasses/mgoggles/orange - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/trimmed_wire + display_name = "Trimmed barbed wire" + path = /obj/item/prop/helmetgarb/trimmed_wire -/datum/gear/aviators - display_name = "Aviator Shades" - path = /obj/item/clothing/glasses/sunglasses/aviator - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/bullet_pipe + display_name = "10x99mm XM42B casing pipe" + path = /obj/item/prop/helmetgarb/bullet_pipe + allowed_origins = USCM_ORIGINS -/datum/gear/rpgglasses - display_name = "Marine RPG Glasses" - path = /obj/item/clothing/glasses/regular - cost = 2 - slot = WEAR_EYES +/datum/gear/helmet_garb/chaplain_patch + display_name = "USCM chaplain helmet patch" + path = /obj/item/prop/helmetgarb/chaplain_patch allowed_origins = USCM_ORIGINS -/datum/gear/prescglasses - display_name = "Prescription Glasses" - path = /obj/item/clothing/glasses/regular/hipster - cost = 2 - slot = WEAR_EYES +/datum/gear/paperwork + category = "Paperwork" -/datum/gear/tacticalmask - display_name = "Face Wrap (Gray)" - path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/pen + display_name = "Pen, black" + path = /obj/item/tool/pen + cost = 1 -/datum/gear/tacticalmasktan - display_name = "Face Wrap (Tan)" - path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask/tan - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/pen_blue + display_name = "Pen, blue" + path = /obj/item/tool/pen/blue -/datum/gear/tacticalmaskred - display_name = "Face Wrap (Red)" - path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask/red - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/pen_green + display_name = "Pen, green" + path = /obj/item/tool/pen/green -/datum/gear/tacticalmaskgreeen - display_name = "Face Wrap (Green)" - path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask/green - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/pen_red + display_name = "Pen, red" + path = /obj/item/tool/pen/red -/datum/gear/tacticalmasksquad - display_name = "Face Wrap (Squad)" - path =/obj/item/clothing/mask/rebreather/scarf/tacticalmask/squad - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/pen_fountain + display_name = "Pen, fountain" + path = /obj/item/tool/pen/fountain + cost = 3 -/datum/gear/tacticalmaskblack - display_name = "Face Wrap (Black)" - path = /obj/item/clothing/mask/rebreather/scarf/tacticalmask/black - slot = WEAR_FACE - cost = 2 -// -/datum/gear/tornscarfclassic - display_name = "Scarf (Grey)" - path = /obj/item/clothing/mask/tornscarf - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/paper + display_name = "Sheet of paper" + path = /obj/item/paper + cost = 1 -/datum/gear/tornscarfgreen - display_name = "Scarf (Green)" - path = /obj/item/clothing/mask/tornscarf/green - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/clipboard + display_name = "Clipboard" + path = /obj/item/clipboard -/datum/gear/tornscarfwhite - display_name = "Scarf (White)" - path = /obj/item/clothing/mask/tornscarf/snow - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/folder_black + display_name = "Folder, black" + path = /obj/item/folder/black -/datum/gear/tornscarfdesert - display_name = "Scarf (Desert)" - path = /obj/item/clothing/mask/tornscarf/desert - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/folder_blue + display_name = "Folder, blue" + path = /obj/item/folder/blue -/datum/gear/tornscarfurban - display_name = "Scarf (Urban)" - path = /obj/item/clothing/mask/tornscarf/urban - slot = WEAR_FACE - cost = 2 +/datum/gear/paperwork/folder_red + display_name = "Folder, red" + path = /obj/item/folder/red -/datum/gear/tornscarfblack - display_name = "Scarf (Black)" - path = /obj/item/clothing/mask/tornscarf/black - slot = WEAR_FACE - cost = 2 -// -/datum/gear/greenfacepaint - display_name = "Green Facepaint" - path = /obj/item/facepaint/green - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/paperwork/folder_white + display_name = "Folder, white" + path = /obj/item/folder/white -/datum/gear/brownfacepaint - display_name = "Brown Facepaint" - path = /obj/item/facepaint/brown - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/paperwork/folder_yellow + display_name = "Folder, yellow" + path = /obj/item/folder/yellow -/datum/gear/blackfacepaint - display_name = "Black Facepaint" - path = /obj/item/facepaint/black - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/paperwork/notepad_black + display_name = "Notepad, black" + path = /obj/item/notepad/black -/datum/gear/fullbodyfacepaint - display_name = "Fullbody Paint" - path = /obj/item/facepaint/sniper - slot = WEAR_IN_BACK - cost = 4 //To match with the skull paint amount of point, gave this amount of point for the same reason of the skull facepaint (too cool for everyone to be able to constantly use) +/datum/gear/paperwork/notepad_blue + display_name = "Notepad, blue" + path = /obj/item/notepad/blue -/datum/gear/aceofspades - display_name = "Ace of Spades" - path = /obj/item/toy/handcard/aceofspades - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/paperwork/notepad_green + display_name = "Notepad, green" + path = /obj/item/notepad/green -/datum/gear/pack_emeraldgreen - display_name = "Pack Of Emerald Greens" - path = /obj/item/storage/fancy/cigarettes/emeraldgreen - slot = WEAR_IN_BACK +/datum/gear/paperwork/notepad_red + display_name = "Notepad, red" + path = /obj/item/notepad/red + +/datum/gear/toy + category = "Recreational" + +/datum/gear/toy/camera + display_name = "Camera" + path = /obj/item/device/camera + +/datum/gear/toy/mags cost = 1 -/datum/gear/pack_lucky_strikes - display_name = "Pack Of Lucky Strikes" - path = /obj/item/storage/fancy/cigarettes/lucky_strikes - slot = WEAR_IN_BACK +/datum/gear/toy/mags/magazine_dirty + display_name = "Magazine" + path = /obj/item/prop/magazine/dirty + +/datum/gear/toy/mags/boots_magazine_one + display_name = "Boots Issue No.117" + path = /obj/item/prop/magazine/boots/n117 + +/datum/gear/toy/mags/boots_magazine_two + display_name = "Boots Issue No.150" + path = /obj/item/prop/magazine/boots/n150 + +/datum/gear/toy/mags/boot_magazine_three + display_name = "Boots Issue No.160" + path = /obj/item/prop/magazine/boots/n160 + +/datum/gear/toy/mags/boots_magazine_four + display_name = "Boots Issue No.54" + path = /obj/item/prop/magazine/boots/n054 + +/datum/gear/toy/mags/boots_magazine_five + display_name = "Boots Issue No.55" + path = /obj/item/prop/magazine/boots/n055 + +/datum/gear/toy/film + display_name = "Camera film" + path = /obj/item/device/camera_film cost = 1 -/datum/gear/weed_joint - display_name = "Joint of Space Weed" - path = /obj/item/clothing/mask/cigarette/weed - slot = WEAR_IN_BACK +/datum/gear/toy/card + cost = 1 + +/datum/gear/toy/card/ace_of_spades + display_name = "Card, ace of spades" + path = /obj/item/toy/handcard/aceofspades + +/datum/gear/toy/card/uno_reverse_red + display_name = "Card, Uno Reverse - red" + path = /obj/item/toy/handcard/uno_reverse_red + +/datum/gear/toy/card/uno_reverse_blue + display_name = "Card, Uno Reverse - blue" + path = /obj/item/toy/handcard/uno_reverse_blue + +/datum/gear/toy/card/uno_reverse_purple + display_name = "Card, Uno Reverse - purple" + path = /obj/item/toy/handcard/uno_reverse_purple + +/datum/gear/toy/card/uno_reverse_yellow + display_name = "Card, Uno Reverse - yellow" + path = /obj/item/toy/handcard/uno_reverse_yellow + +/datum/gear/toy/deck + display_name = "Deck of cards, regular" + path = /obj/item/toy/deck + +/datum/gear/toy/deck/uno + display_name = "Deck of cards, Uno" + path = /obj/item/toy/deck/uno + +/datum/gear/toy/d6 + display_name = "Die, 6 sides" + path = /obj/item/toy/dice + +/datum/gear/toy/d20 + display_name = "Die, 20 sides" + path = /obj/item/toy/dice/d20 + +/datum/gear/toy/walkman + display_name = "Walkman" + path = /obj/item/device/walkman + +/datum/gear/toy/crayon + display_name = "Crayon" + path = /obj/item/toy/crayon/rainbow + +/datum/gear/weapon + category = "Weapons" cost = 4 -/datum/gear/type_80_Bayonet +/datum/gear/weapon/type_80_Bayonet display_name = "Type 80 Bayonet" path = /obj/item/attachable/bayonet/upp_replica - slot = WEAR_IN_BACK - cost = 4 -/datum/gear/m8_cartridge_bayonet +/datum/gear/weapon/m8_cartridge_bayonet display_name = "M8 Cartridge Bayonet" - path = /obj/item/storage/box/c02_knife - slot = WEAR_IN_BACK - cost = 4 + path = /obj/item/storage/box/co2_knife -/datum/gear/clfpistol +/datum/gear/weapon/clfpistol display_name = "D18 Holdout Pistol" path = /obj/item/storage/box/clf - slot = WEAR_IN_BACK - cost = 4 -/datum/gear/m4a3_custom +/datum/gear/weapon/m4a3_custom display_name = "M4A3 Custom Pistol" path = /obj/item/weapon/gun/pistol/m4a3/custom - slot = WEAR_IN_BACK - cost = 4 allowed_origins = USCM_ORIGINS -/datum/gear/m44_custom_revolver +/datum/gear/weapon/m44_custom_revolver display_name = "M44 Custom Revolver" path = /obj/item/weapon/gun/revolver/m44/custom - slot = WEAR_IN_BACK - cost = 7 allowed_origins = USCM_ORIGINS -/datum/gear/jungle_boots - display_name = "Jungle Pattern Combat Boots" - path = /obj/item/clothing/shoes/marine/jungle - slot = WEAR_IN_BACK - cost = 3 +/datum/gear/drink + category = "Canned drinks" -/datum/gear/uno_reverse_red - display_name = "Uno Reverse - Red" - path = /obj/item/toy/handcard/uno_reverse_red - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/drink/water + display_name = "Bottled water" + path = /obj/item/reagent_container/food/drinks/cans/waterbottle + cost = 1 -/datum/gear/uno_reverse_blue - display_name = "Uno Reverse - Blue" - path = /obj/item/toy/handcard/uno_reverse_blue - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/drink/grape_juice + display_name = "Grape juice" + path = /obj/item/reagent_container/food/drinks/cans/grape_juice -/datum/gear/uno_reverse_purple - display_name = "Uno Reverse - Purple" - path = /obj/item/toy/handcard/uno_reverse_purple - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/drink/lemon_lime + display_name = "Lemon lime" + path = /obj/item/reagent_container/food/drinks/cans/lemon_lime -/datum/gear/uno_reverse_yellow - display_name = "Uno Reverse - Yellow" - path = /obj/item/toy/handcard/uno_reverse_yellow - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/drink/iced_tea + display_name = "Iced tea" + path = /obj/item/reagent_container/food/drinks/cans/iced_tea + +/datum/gear/drink/cola + display_name = "Classic Cola" + path = /obj/item/reagent_container/food/drinks/cans/classcola + +/datum/gear/drink/mountain_wind + display_name = "Mountain Wind" + path = /obj/item/reagent_container/food/drinks/cans/space_mountain_wind + +/datum/gear/drink/space_up + display_name = "Space Up" + path = /obj/item/reagent_container/food/drinks/cans/space_up + +/datum/gear/drink/souto_classic + display_name = "Classic Souto" + path = /obj/item/reagent_container/food/drinks/cans/souto/classic + +/datum/gear/drink/souto_diet + display_name = "Diet Souto" + path = /obj/item/reagent_container/food/drinks/cans/souto/diet/classic + +/datum/gear/drink/boda + display_name = "Boda Soda" + path = /obj/item/reagent_container/food/drinks/cans/boda + cost = 3 //Legally imported from UPP. + +/datum/gear/drink/boda/plus + display_name = "Boda Cola" + path = /obj/item/reagent_container/food/drinks/cans/bodaplus + +/datum/gear/drink/alcohol + cost = 3 //Illegal in military. + +/datum/gear/drink/alcohol/ale + display_name = "Weyland-Yutani IPA Ale" + path = /obj/item/reagent_container/food/drinks/cans/ale + +/datum/gear/drink/alcohol/aspen + display_name = "Weyland-Yutani Aspen Beer" + path = /obj/item/reagent_container/food/drinks/cans/aspen + +/datum/gear/drink/alcohol/beer + display_name = "Weyland-Yutani Lite Beer" + path = /obj/item/reagent_container/food/drinks/cans/beer + +/datum/gear/drink/alcohol/loko + display_name = "Thirteen Loko" + path = /obj/item/reagent_container/food/drinks/cans/thirteenloko + +/datum/gear/flask + category = "Flasks" + +/datum/gear/flask/canteen + display_name = "Canteen" + path = /obj/item/reagent_container/food/drinks/flask/canteen + +/datum/gear/flask/leather + display_name = "Leather flask" + path = /obj/item/reagent_container/food/drinks/flask/detflask + +/datum/gear/flask/leather_black + display_name = "Black leather flask" + path = /obj/item/reagent_container/food/drinks/flask/barflask -/datum/gear/candy +/datum/gear/flask/metal + display_name = "Metal flask" + path = /obj/item/reagent_container/food/drinks/flask + +/datum/gear/flask/uscm + display_name = "USCM flask" + path = /obj/item/reagent_container/food/drinks/flask/marine + +/datum/gear/flask/vacuum + display_name = "Vacuum flask" + path = /obj/item/reagent_container/food/drinks/flask/vacuumflask + +/datum/gear/flask/wy + display_name = "WY flask" + path = /obj/item/reagent_container/food/drinks/flask/weylandyutani + +/datum/gear/snack_sweet + category = "Food (sweets)" + +/datum/gear/snack_sweet/candy display_name = "Bar of candy" path = /obj/item/reagent_container/food/snacks/candy - slot = WEAR_IN_BACK - cost = 2 -/datum/gear/lime - display_name = "Lucky Lime" - path = /obj/item/reagent_container/food/snacks/grown/lime - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/snack_sweet/chocolate + display_name = "Bar of chocolate" + path = /obj/item/reagent_container/food/snacks/chocolatebar -/datum/gear/pen - display_name = "Pen" - path = /obj/item/tool/pen - slot = WEAR_IN_BACK - cost = 1 +/datum/gear/snack_sweet/candy_apple + display_name = "Candied apple" + path = /obj/item/reagent_container/food/snacks/candiedapple -/datum/gear/lighter - display_name = "Random Lighter" - path = /obj/item/tool/lighter/random - slot = WEAR_IN_BACK - cost = 2 +/datum/gear/snack_sweet/cookie + display_name = "Cookie" + path = /obj/item/reagent_container/food/snacks/cookie -/datum/gear/uscmpatch - display_name = "USCM shoulder patch" - path = /obj/item/clothing/accessory/patch - cost = 1 - slot = WEAR_IN_ACCESSORY - allowed_origins = USCM_ORIGINS +/datum/gear/snack_sweet/fortune_cookie + display_name = "Fortune cookie" + path = /obj/item/reagent_container/food/snacks/fortunecookie/prefilled + cost = 3 -/datum/gear/falconpatch - display_name = "Falling Falcons shoulder patch" - path = /obj/item/clothing/accessory/patch/falcon - cost = 1 - slot = WEAR_IN_ACCESSORY - allowed_origins = USCM_ORIGINS +/datum/gear/snack_sweet/donut_normal + display_name = "Donut" + path = /obj/item/reagent_container/food/snacks/donut/normal -/datum/gear/gas_mask - display_name = "Gas Mask" - path = /obj/item/clothing/mask/gas - cost = 2 - slot = WEAR_FACE +/datum/gear/snack_sweet/donut_jelly + display_name = "Jelly donut" + path = /obj/item/reagent_container/food/snacks/donut/jelly -/datum/gear/gunoil - display_name = "Gun Oil" - path = /obj/item/prop/helmetgarb/gunoil - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_sweet/donut_cherry + display_name = "Cherry donut" + path = /obj/item/reagent_container/food/snacks/donut/cherryjelly -/datum/gear/netting - display_name = "Helmet Netting" - path = /obj/item/prop/helmetgarb/netting - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_packaged + category = "Food (packaged)" -/datum/gear/spent_buck - display_name = "Spent Buckshot" - path = /obj/item/prop/helmetgarb/spent_buckshot - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_packaged/beef_jerky + display_name = "Beef jerky" + path = /obj/item/reagent_container/food/snacks/sosjerky -/datum/gear/spent_slugs - display_name = "Spent Slugs" - path = /obj/item/prop/helmetgarb/spent_slug - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_packaged/meat_bar + display_name = "MEAT bar" + path = /obj/item/reagent_container/food/snacks/eat_bar -/datum/gear/spent_flechette - display_name = "Spent Flechette" - path = /obj/item/prop/helmetgarb/spent_flech - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_packaged/kepler_crisps + display_name = "Kepler Crisps" + path = /obj/item/reagent_container/food/snacks/kepler_crisps -/datum/gear/prescription_bottle - display_name = "Prescription Bottle" - path = /obj/item/prop/helmetgarb/prescription_bottle - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_packaged/burrito + display_name = "Packaged burrito" + path = /obj/item/reagent_container/food/snacks/packaged_burrito -/datum/gear/raincover - display_name = "Helmet Rain Cover" - path = /obj/item/prop/helmetgarb/raincover - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_packaged/cheeseburger + display_name = "Packaged cheeseburger" + path = /obj/item/reagent_container/food/snacks/packaged_burger -/datum/gear/rabbits_foot - display_name = "Rabbit's Foot" - path = /obj/item/prop/helmetgarb/rabbitsfoot - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_packaged/hotdog + display_name = "Packaged hotdog" + path = /obj/item/reagent_container/food/snacks/packaged_hdogs -/datum/gear/rosary - display_name = "Rosary" - path = /obj/item/prop/helmetgarb/rosary - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_packaged/chips_pepper + display_name = "W-Y Pepper Chips" + path = /obj/item/reagent_container/food/snacks/wy_chips/pepper -/datum/gear/lucky_feather - display_name = "Lucky Feather - Red" - path = /obj/item/prop/helmetgarb/lucky_feather - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_grown + category = "Food (healthy)" -/datum/gear/lucky_feather/blue - display_name = "Lucky Feather - Blue" - path = /obj/item/prop/helmetgarb/lucky_feather/blue +/datum/gear/snack_grown/apple + display_name = "Apple" + path = /obj/item/reagent_container/food/snacks/grown/apple -/datum/gear/lucky_feather/purple - display_name = "Lucky Feather - Purple" - path = /obj/item/prop/helmetgarb/lucky_feather/purple +/datum/gear/snack_grown/carrot + display_name = "Carrot" + path = /obj/item/reagent_container/food/snacks/grown/carrot -/datum/gear/lucky_feather/yellow - display_name = "Lucky Feather - Yellow" - path = /obj/item/prop/helmetgarb/lucky_feather/yellow +/datum/gear/snack_grown/corn + display_name = "Corn" + path = /obj/item/reagent_container/food/snacks/grown/corn -/datum/gear/helmet_gasmask - display_name = "M5 integrated gasmask" - path = /obj/item/prop/helmetgarb/helmet_gasmask - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/snack_grown/lemon + display_name = "Lemon" + path = /obj/item/reagent_container/food/snacks/grown/lemon -/datum/gear/trimmed_wire - display_name = "Trimmed Barbed Wire" - path = /obj/item/prop/helmetgarb/trimmed_wire - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/snack_grown/lime + display_name = "Lime" + path = /obj/item/reagent_container/food/snacks/grown/lime -/datum/gear/bullet_pipe - display_name = "10x99mm XM42B casing pipe" - path = /obj/item/prop/helmetgarb/bullet_pipe - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_grown/orange + display_name = "Orange" + path = /obj/item/reagent_container/food/snacks/grown/orange -/datum/gear/flair_initech - display_name = "Initech Flair" - path = /obj/item/prop/helmetgarb/flair_initech - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/snack_grown/potato + display_name = "Potato" + path = /obj/item/reagent_container/food/snacks/grown/potato -/datum/gear/flair_io - display_name = "Io Flair" - path = /obj/item/prop/helmetgarb/flair_io - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/smoking + category = "Smoking" -/datum/gear/flair_peace - display_name = "Peace and Love Flair" - path = /obj/item/prop/helmetgarb/flair_peace +/datum/gear/smoking/cigarette + display_name = "Cigarette" + path = /obj/item/clothing/mask/cigarette cost = 1 - slot = WEAR_IN_BACK + slot = WEAR_FACE -/datum/gear/flair_uscm - display_name = "USCM Flair" - path = /obj/item/prop/helmetgarb/flair_uscm - cost = 1 - slot = WEAR_IN_BACK - allowed_origins = USCM_ORIGINS +/datum/gear/smoking/cigarette/cigar_classic + display_name = "Classic cigar" + path = /obj/item/clothing/mask/cigarette/cigar/classic + cost = 3 -/datum/gear/broken_nvgs - display_name = "Broken Night Vision Goggles" - path = /obj/item/prop/helmetgarb/helmet_nvg/cosmetic - cost = 1 - slot = WEAR_IN_BACK +/datum/gear/smoking/cigarette/cigar_premium + display_name = "Premium cigar" + path = /obj/item/clothing/mask/cigarette/cigar + cost = 2 -/datum/gear/spacejam_tickets - display_name = "Authentic Tickets to Space Jam" - path = /obj/item/prop/helmetgarb/spacejam_tickets - cost = 4 - slot = WEAR_IN_BACK +/datum/gear/smoking/pack_emerald_green + display_name = "Pack Of Emerald Greens" + path = /obj/item/storage/fancy/cigarettes/emeraldgreen -/datum/gear/weyland_booze - display_name = "Weyland-Yutani Lite" - path = /obj/item/reagent_container/food/drinks/cans/beer - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/smoking/pack_lucky_strikes + display_name = "Pack Of Lucky Strikes" + path = /obj/item/storage/fancy/cigarettes/lucky_strikes -/datum/gear/weyland_IPA - display_name = "Weyland-Yutani IPA" - path = /obj/item/reagent_container/food/drinks/cans/beer - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/smoking/weed_joint + display_name = "Joint of space weed" + path = /obj/item/clothing/mask/cigarette/weed + cost = 4 -/datum/gear/flask - display_name = "Metal Flask" - path = /obj/item/reagent_container/food/drinks/flask - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/smoking/lighter + display_name = "Lighter, cheap" + path = /obj/item/tool/lighter/random + cost = 1 -/datum/gear/flask_canteen - display_name = "Canteen" - path = /obj/item/reagent_container/food/drinks/flask/canteen - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/smoking/zippo + display_name = "Lighter, zippo" + path = /obj/item/tool/lighter/zippo -/datum/gear/flask_uscm - display_name = "USCM Flask" - path = /obj/item/reagent_container/food/drinks/flask/marine - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/misc + category = "Miscellaneous" -/datum/gear/flask_wy - display_name = "WY Flask" - path = /obj/item/reagent_container/food/drinks/flask/weylandyutani - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/misc/facepaint_green + display_name = "Facepaint, green" + path = /obj/item/facepaint/green -/datum/gear/flask_det - display_name = "Leather Flask" - path = /obj/item/reagent_container/food/drinks/flask/detflask - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/misc/facepaint_brown + display_name = "Facepaint, brown" + path = /obj/item/facepaint/brown -/datum/gear/flask_bar - display_name = "Black Leather Flask" - path = /obj/item/reagent_container/food/drinks/flask/barflask - cost = 2 - slot = WEAR_IN_BACK +/datum/gear/misc/facepaint_black + display_name = "Facepaint, black" + path = /obj/item/facepaint/black -/datum/gear/flask_vacuum - display_name = "Vacuum Flask" - path = /obj/item/reagent_container/food/drinks/flask/vacuumflask - cost = 3 //they're too cool for 2 points - slot = WEAR_IN_BACK +/datum/gear/misc/facepaint_body + display_name = "Fullbody paint" + path = /obj/item/facepaint/sniper + cost = 4 //To match with the skull paint amount of point, gave this amount of point for the same reason of the skull facepaint (too cool for everyone to be able to constantly use) + +/datum/gear/misc/jungle_boots + display_name = "Jungle pattern combat boots" + path = /obj/item/clothing/shoes/marine/jungle + cost = 3 -/datum/gear/pdt_kit - display_name = "PDT/L Kit" +/datum/gear/misc/pdt_kit + display_name = "PDT/L kit" path = /obj/item/storage/box/pdt_kit cost = 3 - slot = WEAR_IN_BACK -/datum/gear/sunscreen_stick - display_name = "USCM Issue Sunscreen" +/datum/gear/misc/sunscreen_stick + display_name = "USCM issue sunscreen" path = /obj/item/facepaint/sunscreen_stick cost = 1 //The cadmium poisoning pays for the discounted cost longterm - slot = WEAR_IN_BACK + allowed_origins = USCM_ORIGINS -/datum/gear/chaplain_patch - display_name = "USCM Chaplain Helmet Patch" - path = /obj/item/prop/helmetgarb/chaplain_patch - cost = 1 //similar price to flairs - slot = WEAR_IN_BACK +/datum/gear/misc/patch_uscm + display_name = "USCM shoulder patch" + path = /obj/item/clothing/accessory/patch + cost = 1 + slot = WEAR_IN_ACCESSORY + allowed_origins = USCM_ORIGINS + +/datum/gear/misc/patch_uscm/falcon + display_name = "Falling Falcons shoulder patch" + path = /obj/item/clothing/accessory/patch/falcon diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index aef1895745ba..0f482fa7f894 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -90,7 +90,7 @@ /proc/sanitize_keybindings(value) var/list/base_bindings = sanitize_islist(value, list()) - if(!base_bindings) + if(!length(base_bindings)) base_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) for(var/key in base_bindings) base_bindings[key] = base_bindings[key] & GLOB.keybindings_by_name @@ -149,6 +149,8 @@ S["xeno_vision_level_pref"] >> xeno_vision_level_pref S["view_controller"] >> View_MC S["observer_huds"] >> observer_huds + S["pref_special_job_options"] >> pref_special_job_options + S["pref_job_slots"] >> pref_job_slots S["synth_name"] >> synthetic_name S["synth_type"] >> synthetic_type @@ -171,13 +173,12 @@ S["commander_status"] >> commander_status S["co_sidearm"] >> commander_sidearm + S["co_affiliation"] >> affiliation S["yautja_status"] >> yautja_status S["synth_status"] >> synth_status S["key_bindings"] >> key_bindings check_keybindings() - S["preferred_survivor_variant"] >> preferred_survivor_variant - var/list/remembered_key_bindings S["remembered_key_bindings"] >> remembered_key_bindings @@ -191,30 +192,29 @@ S["custom_cursors"] >> custom_cursors S["autofit_viewport"] >> auto_fit_viewport - - S["pref_special_job_options"] >> pref_special_job_options + S["adaptive_zoom"] >> adaptive_zoom //Sanitize ooccolor = sanitize_hexcolor(ooccolor, CONFIG_GET(string/ooc_color_default)) lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) UI_style = sanitize_inlist(UI_style, list("white", "dark", "midnight", "orange", "old"), initial(UI_style)) tgui_say = sanitize_integer(tgui_say, FALSE, TRUE, TRUE) - be_special = sanitize_integer(be_special, 0, 65535, initial(be_special)) + be_special = sanitize_integer(be_special, 0, SHORT_REAL_LIMIT, initial(be_special)) default_slot = sanitize_integer(default_slot, 1, MAX_SAVE_SLOTS, initial(default_slot)) - toggles_chat = sanitize_integer(toggles_chat, 0, 65535, initial(toggles_chat)) - chat_display_preferences = sanitize_integer(chat_display_preferences, 0, 65535, initial(chat_display_preferences)) - toggles_ghost = sanitize_integer(toggles_ghost, 0, 65535, initial(toggles_ghost)) - toggles_langchat = sanitize_integer(toggles_langchat, 0, 65535, initial(toggles_langchat)) - toggles_sound = sanitize_integer(toggles_sound, 0, 65535, initial(toggles_sound)) - toggle_prefs = sanitize_integer(toggle_prefs, 0, 65535, initial(toggle_prefs)) - toggles_flashing= sanitize_integer(toggles_flashing, 0, 65535, initial(toggles_flashing)) - toggles_ert = sanitize_integer(toggles_ert, 0, 65535, initial(toggles_ert)) - toggles_admin = sanitize_integer(toggles_admin, 0, 65535, initial(toggles_admin)) + toggles_chat = sanitize_integer(toggles_chat, 0, SHORT_REAL_LIMIT, initial(toggles_chat)) + chat_display_preferences = sanitize_integer(chat_display_preferences, 0, SHORT_REAL_LIMIT, initial(chat_display_preferences)) + toggles_ghost = sanitize_integer(toggles_ghost, 0, SHORT_REAL_LIMIT, initial(toggles_ghost)) + toggles_langchat = sanitize_integer(toggles_langchat, 0, SHORT_REAL_LIMIT, initial(toggles_langchat)) + toggles_sound = sanitize_integer(toggles_sound, 0, SHORT_REAL_LIMIT, initial(toggles_sound)) + toggle_prefs = sanitize_integer(toggle_prefs, 0, SHORT_REAL_LIMIT, initial(toggle_prefs)) + toggles_flashing= sanitize_integer(toggles_flashing, 0, SHORT_REAL_LIMIT, initial(toggles_flashing)) + toggles_ert = sanitize_integer(toggles_ert, 0, SHORT_REAL_LIMIT, initial(toggles_ert)) + toggles_admin = sanitize_integer(toggles_admin, 0, SHORT_REAL_LIMIT, initial(toggles_admin)) UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color)) UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha)) item_animation_pref_level = sanitize_integer(item_animation_pref_level, SHOW_ITEM_ANIMATIONS_NONE, SHOW_ITEM_ANIMATIONS_ALL, SHOW_ITEM_ANIMATIONS_ALL) pain_overlay_pref_level = sanitize_integer(pain_overlay_pref_level, PAIN_OVERLAY_BLURRY, PAIN_OVERLAY_LEGACY, PAIN_OVERLAY_BLURRY) - window_skin = sanitize_integer(window_skin, 0, 65535, initial(window_skin)) + window_skin = sanitize_integer(window_skin, 0, SHORT_REAL_LIMIT, initial(window_skin)) ghost_vision_pref = sanitize_inlist(ghost_vision_pref, list(GHOST_VISION_LEVEL_NO_NVG, GHOST_VISION_LEVEL_MID_NVG, GHOST_VISION_LEVEL_FULL_NVG), GHOST_VISION_LEVEL_MID_NVG) ghost_orbit = sanitize_inlist(ghost_orbit, GLOB.ghost_orbits, initial(ghost_orbit)) playtime_perks = sanitize_integer(playtime_perks, 0, 1, 1) @@ -224,6 +224,7 @@ no_radials_preference = sanitize_integer(no_radials_preference, FALSE, TRUE, FALSE) no_radial_labels_preference = sanitize_integer(no_radial_labels_preference, FALSE, TRUE, FALSE) auto_fit_viewport = sanitize_integer(auto_fit_viewport, FALSE, TRUE, TRUE) + adaptive_zoom = sanitize_integer(adaptive_zoom, 0, 2, 0) synthetic_name = synthetic_name ? sanitize_text(synthetic_name, initial(synthetic_name)) : initial(synthetic_name) synthetic_type = sanitize_inlist(synthetic_type, PLAYER_SYNTHS, initial(synthetic_type)) @@ -245,7 +246,7 @@ predator_flavor_text = predator_flavor_text ? sanitize_text(predator_flavor_text, initial(predator_flavor_text)) : initial(predator_flavor_text) commander_status = sanitize_inlist(commander_status, whitelist_hierarchy, initial(commander_status)) commander_sidearm = sanitize_inlist(commander_sidearm, list("Mateba","Colonel's Mateba","Golden Desert Eagle","Desert Eagle"), initial(commander_sidearm)) - preferred_survivor_variant = sanitize_inlist(preferred_survivor_variant, SURVIVOR_VARIANT_LIST, ANY_SURVIVOR) + affiliation = sanitize_inlist(affiliation, FACTION_ALLEGIANCE_USCM_COMMANDER, initial(affiliation)) yautja_status = sanitize_inlist(yautja_status, whitelist_hierarchy + list("Elder"), initial(yautja_status)) synth_status = sanitize_inlist(synth_status, whitelist_hierarchy, initial(synth_status)) key_bindings = sanitize_keybindings(key_bindings) @@ -253,6 +254,7 @@ hotkeys = sanitize_integer(hotkeys, FALSE, TRUE, TRUE) custom_cursors = sanitize_integer(custom_cursors, FALSE, TRUE, TRUE) pref_special_job_options = sanitize_islist(pref_special_job_options, list()) + pref_job_slots = sanitize_islist(pref_job_slots, list()) vars["fps"] = fps if(remembered_key_bindings) @@ -327,6 +329,8 @@ S["view_controller"] << View_MC S["observer_huds"] << observer_huds + S["pref_special_job_options"] << pref_special_job_options + S["pref_job_slots"] << pref_job_slots S["synth_name"] << synthetic_name S["synth_type"] << synthetic_type @@ -347,10 +351,9 @@ S["pred_skin_color"] << predator_skin_color S["pred_flavor_text"] << predator_flavor_text - S["preferred_survivor_variant"] << preferred_survivor_variant - S["commander_status"] << commander_status S["co_sidearm"] << commander_sidearm + S["co_affiliation"] << affiliation S["yautja_status"] << yautja_status S["synth_status"] << synth_status @@ -360,6 +363,7 @@ S["hotkeys"] << hotkeys S["autofit_viewport"] << auto_fit_viewport + S["adaptive_zoom"] << adaptive_zoom S["hear_vox"] << hear_vox @@ -368,8 +372,6 @@ S["no_radial_labels_preference"] << no_radial_labels_preference S["custom_cursors"] << custom_cursors - S["pref_special_job_options"] << pref_special_job_options - return TRUE /datum/preferences/proc/load_character(slot) @@ -449,6 +451,7 @@ S["traits"] >> traits S["preferred_squad"] >> preferred_squad + S["preferred_armor"] >> preferred_armor S["nanotrasen_relation"] >> nanotrasen_relation //S["skin_style"] >> skin_style @@ -498,6 +501,7 @@ underwear = sanitize_inlist(underwear, gender == MALE ? GLOB.underwear_m : GLOB.underwear_f, initial(underwear)) undershirt = sanitize_inlist(undershirt, gender == MALE ? GLOB.undershirt_m : GLOB.undershirt_f, initial(undershirt)) backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag)) + preferred_armor = sanitize_inlist(preferred_armor, GLOB.armor_style_list, "Random") //b_type = sanitize_text(b_type, initial(b_type)) alternate_option = sanitize_integer(alternate_option, 0, 3, initial(alternate_option)) @@ -593,6 +597,7 @@ S["nanotrasen_relation"] << nanotrasen_relation S["preferred_squad"] << preferred_squad + S["preferred_armor"] << preferred_armor //S["skin_style"] << skin_style S["uplinklocation"] << uplinklocation @@ -616,16 +621,17 @@ var/addedbind = FALSE if(hotkeys) for(var/hotkeytobind in kb.hotkey_keys) - if(!length(key_bindings[hotkeytobind])) + if(!length(key_bindings[hotkeytobind]) || hotkeytobind == "Unbound") //Only bind to the key if nothing else is bound expect for Unbound LAZYADD(key_bindings[hotkeytobind], kb.name) addedbind = TRUE else for(var/classickeytobind in kb.classic_keys) - if(!length(key_bindings[classickeytobind])) + if(!length(key_bindings[classickeytobind]) || classickeytobind == "Unbound") //Only bind to the key if nothing else is bound expect for Unbound LAZYADD(key_bindings[classickeytobind], kb.name) addedbind = TRUE if(!addedbind) notadded += kb + save_preferences() if(length(notadded)) addtimer(CALLBACK(src, PROC_REF(announce_conflict), notadded), 5 SECONDS) @@ -637,10 +643,10 @@ if(hotkeys) for(var/entry in conflicted.hotkey_keys) - key_bindings[entry] -= conflicted.name + LAZYREMOVE(key_bindings[entry], conflicted.name) else for(var/entry in conflicted.classic_keys) - key_bindings[entry] -= conflicted.name + LAZYREMOVE(key_bindings[entry], conflicted.name) LAZYADD(key_bindings["Unbound"], conflicted.name) // set it to unbound to prevent this from opening up again in the future diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index 90b605b7f54f..b81411a26440 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -201,13 +201,19 @@ to_chat(src, SPAN_BOLDNOTICE("The icon on your taskbar will no longer flash when an admin messages you. Warning, use at own risk.")) //be special -/client/verb/toggle_be_special(role in be_special_flags) +/client/verb/toggle_be_special() set name = "Toggle SpecialRole Candidacy" set category = "Preferences" set desc = "Toggles which special roles you would like to be a candidate for, during events." - var/role_flag = be_special_flags[role] - if(!role_flag) return + var/list/be_special_flags = list( + "Xenomorph after unrevivable death" = BE_ALIEN_AFTER_DEATH, + "Agent" = BE_AGENT, + ) + var/role = tgui_input_list(usr, "Toggle which candidacy?", "Select role", be_special_flags) + if(!role) + return + var/role_flag = be_special_flags[role] prefs.be_special ^= role_flag prefs.save_preferences() to_chat(src, SPAN_BOLDNOTICE("You will [(prefs.be_special & role_flag) ? "now" : "no longer"] be considered for [role] events (where possible).")) @@ -268,6 +274,7 @@ "Toggle 'Unload Weapon' Ejecting Magazines to Your Hands
", "Toggle Automatic Punctuation
", "Toggle Middle Mouse Ability Activation
", + "Toggle Ability Deactivation
", "Toggle Combat Click-Drag Override
", "Toggle Alternate-Fire Dual Wielding
", "Toggle Middle Mouse Swapping Hands
", @@ -281,7 +288,7 @@ for (var/pref_button in pref_buttons) dat += "[pref_button]\n" - var/height = 50+22*length(pref_buttons) + var/height = 50+24*length(pref_buttons) show_browser(src, dat, "Toggle Preferences", "togglepreferences", "size=475x[height]") @@ -349,6 +356,14 @@ to_chat(src, SPAN_NOTICE("Your selected ability will now be activated with shift clicking.")) prefs.save_preferences() +/client/proc/toggle_ability_deactivation() // Toggle whether the current ability can be deactivated when re-selected + prefs.toggle_prefs ^= TOGGLE_ABILITY_DEACTIVATION_OFF + if (prefs.toggle_prefs & TOGGLE_ABILITY_DEACTIVATION_OFF) + to_chat(src, SPAN_NOTICE("Your current ability can no longer be toggled off when re-selected.")) + else + to_chat(src, SPAN_NOTICE("Your current ability can be toggled off when re-selected.")) + prefs.save_preferences() + /client/proc/toggle_clickdrag_override() //Toggle whether mousedown clicks immediately when on disarm or harm intent to prevent click-dragging from 'eating' attacks. prefs.toggle_prefs ^= TOGGLE_COMBAT_CLICKDRAG_OVERRIDE if(prefs.toggle_prefs & TOGGLE_COMBAT_CLICKDRAG_OVERRIDE) @@ -507,10 +522,30 @@ prefs.auto_fit_viewport = !prefs.auto_fit_viewport if(prefs.auto_fit_viewport) to_chat(src, SPAN_NOTICE("Now auto fitting viewport.")) + fit_viewport() else to_chat(src, SPAN_NOTICE("No longer auto fitting viewport.")) prefs.save_preferences() +/client/verb/toggle_adaptive_zooming() + set name = "Toggle Adaptive Zooming" + set category = "Preferences.UI" + + switch(prefs.adaptive_zoom) + if(0) + prefs.adaptive_zoom = 1 + to_chat(src, SPAN_BOLDNOTICE("Adaptive Zooming is now enabled, switching between x1 and x2 zoom. This is recommended for 1080p monitors.")) + adaptive_zoom() + if(1) + prefs.adaptive_zoom = 2 + to_chat(src, SPAN_BOLDNOTICE("Adaptive Zooming is now enabled, switching between x2 and x4 zoom.")) + adaptive_zoom() + if(2) + prefs.adaptive_zoom = 0 + to_chat(src, SPAN_BOLDNOTICE("Adaptive Zooming is now disabled.")) + adaptive_zoom() + prefs.save_preferences() + //------------ GHOST PREFERENCES --------------------------------- /client/proc/show_ghost_preferences() // Shows ghost-related preferences. diff --git a/code/modules/client/tgui_macro.dm b/code/modules/client/tgui_macro.dm index 684cf90942ea..f245f1d657d4 100644 --- a/code/modules/client/tgui_macro.dm +++ b/code/modules/client/tgui_macro.dm @@ -45,6 +45,7 @@ GLOBAL_LIST_EMPTY(ui_data_keybindings) if(!ui) ui = new(user, src, "KeyBinds", "Keybind Preference") ui.open() + ui.set_autoupdate(FALSE) /datum/tgui_macro/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() diff --git a/code/modules/clothing/clothing_accessories.dm b/code/modules/clothing/clothing_accessories.dm index 187d9c83061c..ba855e42d3ba 100644 --- a/code/modules/clothing/clothing_accessories.dm +++ b/code/modules/clothing/clothing_accessories.dm @@ -74,7 +74,7 @@ /obj/item/clothing/attack_hand(mob/user, mods) //only forward to the attached accessory if the clothing is equipped (not in a storage) if(LAZYLEN(accessories) && src.loc == user) - var/delegated //So that accessories don't block attack_hands unless they actually did something. Specifically meant for armour vests with medals, but can't hurt in general. + var/delegated //So that accessories don't block attack_hands unless they actually did something. Specifically meant for armor vests with medals, but can't hurt in general. for(var/obj/item/clothing/accessory/A in accessories) if(A.attack_hand(user, mods)) delegated = TRUE diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 79584be10f0a..7bcf1dd6645c 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -541,7 +541,7 @@ /obj/item/clothing/glasses/sunglasses desc = "Generic off-brand eyewear, used to help provide rudimentary eye cover. Enhanced shielding blocks many flashes." - name = "cheap sunglasses" + name = "sunglasses" icon_state = "sun" item_state = "sunglasses" darkness_view = -1 diff --git a/code/modules/clothing/glasses/meson.dm b/code/modules/clothing/glasses/meson.dm index 859368cd7afc..b0823910365d 100644 --- a/code/modules/clothing/glasses/meson.dm +++ b/code/modules/clothing/glasses/meson.dm @@ -16,19 +16,6 @@ desc = "Used for shield the user's eyes from harmful electromagnetic emissions, can also be used as safety googles. Contains prescription lenses." prescription = TRUE -/obj/item/clothing/glasses/meson/yautja - name = "bio-mask x-ray" - desc = "A vision overlay generated by the Bio-Mask. Used to see through objects." - icon = 'icons/obj/items/hunter/pred_gear.dmi' - icon_state = "visor_meson" - item_state = "securityhud" - darkness_view = 12 - lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE - vision_flags = SEE_TURFS - flags_inventory = COVEREYES - flags_item = NODROP|DELONDROP - actions_types = null - /obj/item/clothing/glasses/meson/refurbished name = "refurbished meson scanner" desc = "Used to shield the user's eyes from harmful electromagnetic emissions, also used as general safety goggles. A special version with upgraded optics." diff --git a/code/modules/clothing/glasses/night.dm b/code/modules/clothing/glasses/night.dm index be58dd80cc25..63d0c8f364af 100644 --- a/code/modules/clothing/glasses/night.dm +++ b/code/modules/clothing/glasses/night.dm @@ -100,27 +100,25 @@ req_skill_level = SKILL_SPEC_SMARTGUN var/far_sight = FALSE - var/powerpack = null + var/obj/item/weapon/gun/smartgun/linked_smartgun = null /obj/item/clothing/glasses/night/m56_goggles/Destroy() - powerpack = null + linked_smartgun = null disable_far_sight() return ..() -/obj/item/clothing/glasses/night/m56_goggles/proc/link_powerpack(mob/user) - if(!QDELETED(user) && !QDELETED(user.back)) - if(istype(user.back, /obj/item/smartgun_powerpack)) - powerpack = user.back +/obj/item/clothing/glasses/night/m56_goggles/proc/link_smartgun(mob/user) + if(!QDELETED(user)) + linked_smartgun = locate() in user + if(linked_smartgun) return TRUE return FALSE /obj/item/clothing/glasses/night/m56_goggles/mob_can_equip(mob/user, slot) if(slot == WEAR_EYES) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(!istype(H.back, /obj/item/smartgun_powerpack)) - to_chat(user, "You must be wearing an M56 Powerpack on your back to wear these.") - return FALSE + if(!link_smartgun(user)) + to_chat(user, SPAN_NOTICE("You must have your smartgun equipped to wear these.")) + return FALSE return ..() /obj/item/clothing/glasses/night/m56_goggles/equipped(mob/user, slot) @@ -129,6 +127,7 @@ return ..() /obj/item/clothing/glasses/night/m56_goggles/dropped(mob/living/carbon/human/user) + linked_smartgun = null disable_far_sight(user) return ..() @@ -137,8 +136,8 @@ if(user.glasses != src) to_chat(user, SPAN_WARNING("You can't activate far sight without wearing \the [src]!")) return - if(!link_powerpack(user)) - to_chat(user, SPAN_WARNING("You can't use this without a powerpack!")) + if(!link_smartgun(user)) + to_chat(user, SPAN_WARNING("You can't use this without a smartgun!")) return far_sight = TRUE if(user) @@ -146,7 +145,7 @@ user.client.change_view(8, src) START_PROCESSING(SSobj, src) else - powerpack = null + linked_smartgun = null far_sight = FALSE if(user) if(user.client) @@ -154,8 +153,8 @@ STOP_PROCESSING(SSobj, src) var/datum/action/item_action/m56_goggles/far_sight/FT = locate(/datum/action/item_action/m56_goggles/far_sight) in actions - FT.update_button_icon() - + if(FT) + FT.update_button_icon() /obj/item/clothing/glasses/night/m56_goggles/proc/disable_far_sight(mob/living/carbon/human/user) if(!istype(user)) @@ -169,14 +168,11 @@ if(!istype(user)) set_far_sight(null, FALSE) return PROCESS_KILL - if(powerpack != user.back) + if(!link_smartgun(user)) set_far_sight(user, FALSE) return PROCESS_KILL - var/obj/item/smartgun_powerpack/pp = user.back - if(istype(pp)) - var/obj/item/cell/c = pp.pcell - if(!pp.drain_powerpack(25 * delta_time, c)) - set_far_sight(user, FALSE) + if(!linked_smartgun.drain_battery(25 * delta_time)) + set_far_sight(user, FALSE) /datum/action/item_action/m56_goggles/far_sight/New() . = ..() diff --git a/code/modules/clothing/glasses/thermal.dm b/code/modules/clothing/glasses/thermal.dm index 607e53cf65f1..bfc60d271724 100644 --- a/code/modules/clothing/glasses/thermal.dm +++ b/code/modules/clothing/glasses/thermal.dm @@ -70,18 +70,6 @@ item_state = "syringe_kit" toggleable = FALSE -/obj/item/clothing/glasses/thermal/yautja - name = "bio-mask thermal" - desc = "A vision overlay generated by the Bio-Mask. Used to sense the heat of prey." - icon = 'icons/obj/items/hunter/pred_gear.dmi' - icon_state = "visor_thermal" - item_state = "securityhud" - vision_flags = SEE_MOBS - invisa_view = 2 - flags_inventory = COVEREYES - flags_item = NODROP|DELONDROP - toggleable = FALSE - /obj/item/clothing/glasses/thermal/empproof desc = "Thermals in the shape of glasses. This one is EMP proof." blinds_on_emp = FALSE diff --git a/code/modules/clothing/gloves/marine_gloves.dm b/code/modules/clothing/gloves/marine_gloves.dm index 4d5b17f35847..04d0b2f1c0cb 100644 --- a/code/modules/clothing/gloves/marine_gloves.dm +++ b/code/modules/clothing/gloves/marine_gloves.dm @@ -22,11 +22,17 @@ armor_rad = CLOTHING_ARMOR_NONE armor_internaldamage = CLOTHING_ARMOR_LOW var/adopts_squad_color = TRUE + /// The dmi where the grayscale squad overlays are contained + var/squad_overlay_icon = 'icons/mob/humans/onmob/hands_garb.dmi' -/obj/item/clothing/gloves/marine/get_mob_overlay(mob/living/carbon/human/H, slot) +/obj/item/clothing/gloves/marine/get_mob_overlay(mob/living/carbon/human/current_human, slot) var/image/ret = ..() - if(adopts_squad_color && slot == WEAR_HANDS && istype(H) && H.assigned_squad) - ret.overlays += glovemarkings[H.assigned_squad.color] + if(!adopts_squad_color || !(current_human.assigned_squad && current_human.assigned_squad.equipment_color)) + return ret + var/image/glove_overlay = image(squad_overlay_icon, icon_state = "std-gloves") + glove_overlay.alpha = current_human.assigned_squad.armor_alpha + glove_overlay.color = current_human.assigned_squad.equipment_color + ret.overlays += glove_overlay return ret /obj/item/clothing/gloves/marine/insulated @@ -163,3 +169,18 @@ /obj/item/clothing/gloves/marine/veteran/insulated/van_bandolier name = "custom shooting gloves" desc = "Highly protective against injury, temperature, and electric shock. Cool in the summer, warm in the winter, and a secure grip on any surface. You could buy a lot for the price of these, and they're worth every penny." + +/obj/item/clothing/gloves/marine/joe + name = "Seegson hazardous gloves" + desc = "Special Synthetic gloves made for touching and interacting with extremely hazardous materials. Resistant to biohazard liquids, corrosive materials and more. SEEGSON is proudly displayed on the back, along with a biohazard symbol. Tomorrow, Together." + icon_state = "working_joe" + item_state = "working_joe" + siemens_coefficient = 0 + armor_melee = CLOTHING_ARMOR_LOW + armor_energy = CLOTHING_ARMOR_MEDIUM + armor_bomb = CLOTHING_ARMOR_MEDIUM + armor_bio = CLOTHING_ARMOR_VERYHIGH + armor_rad = CLOTHING_ARMOR_VERYHIGH + armor_internaldamage = CLOTHING_ARMOR_MEDIUM + unacidable = TRUE + adopts_squad_color = FALSE diff --git a/code/modules/clothing/head/collectable.dm b/code/modules/clothing/head/collectable.dm index e11014392393..addac1ecf139 100644 --- a/code/modules/clothing/head/collectable.dm +++ b/code/modules/clothing/head/collectable.dm @@ -29,3 +29,7 @@ worn_x_dimension = 64 worn_y_dimension = 64 w_class = SIZE_LARGE + +/obj/item/clothing/head/collectable/petehat + icon_state = "petehat" + item_state = "petehat" diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index dcee7800ba1b..165dc03f25e2 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -57,8 +57,9 @@ if(!toggleable) to_chat(user, SPAN_WARNING("You cannot toggle [src] on or off.")) return FALSE + if(!isturf(user.loc)) - to_chat(user, "You cannot turn the light on while in [user.loc].") //To prevent some lighting anomalies. + to_chat(user, SPAN_WARNING("You cannot turn the light [on ? "off" : "on"] while in [user.loc].")) //To prevent some lighting anomalies. return FALSE on = !on diff --git a/code/modules/clothing/head/head.dm b/code/modules/clothing/head/head.dm index 6feac30f341c..0916ecfb34e9 100644 --- a/code/modules/clothing/head/head.dm +++ b/code/modules/clothing/head/head.dm @@ -248,7 +248,9 @@ /obj/item/prop/helmetgarb/lucky_feather = "lucky_feather", /obj/item/prop/helmetgarb/lucky_feather/blue = "lucky_feather_blue", /obj/item/prop/helmetgarb/lucky_feather/purple = "lucky_feather_purple", - /obj/item/prop/helmetgarb/lucky_feather/yellow = "lucky_feather_yellow") + /obj/item/prop/helmetgarb/lucky_feather/yellow = "lucky_feather_yellow", + /obj/item/tool/pen/fountain = "fountainpen", + ) var/storage_slots = 1 var/storage_slots_reserved_for_garb = 1 var/storage_max_w_class = SIZE_TINY @@ -353,19 +355,19 @@ flags_atom = FPRINT|NO_SNOW_TYPE /obj/item/clothing/head/cmcap/co - name = "\improper USCM captain cap" + name = "\improper USCM Commanding officer cap" icon_state = "cocap" desc = "A hat usually worn by senior officers in the USCM. While it provides no protection, some officers wear it in the field to make themselves more recognisable." /obj/item/clothing/head/cmcap/co/formal - name = "\improper USCM formal captain's white cap" + name = "\improper USCM formal Commanding Officer's white cap" icon_state = "co_formalhat_white" - desc = "A formal cover worn by Commanding Officers of the USCM." + desc = "A formal cover worn by senior officers of the USCM." flags_marine_hat = HAT_GARB_OVERLAY flags_atom = FPRINT|NO_SNOW_TYPE /obj/item/clothing/head/cmcap/co/formal/black - name = "\improper USCM formal captain's black cap" + name = "\improper USCM formal Commanding Officer's black cap" icon_state = "co_formalhat_black" /obj/item/clothing/head/cmcap/ro @@ -460,8 +462,8 @@ desc = "A beret with the UAAC-TIS insignia emblazoned on it. A mark of a TIS Special Agent, these berets are one of the only pieces of equipment that the TIS actually manufactures for itself and earning one is one of the rare signs of achievement the Three Eyes allows." /obj/item/clothing/head/beret/marine/commander - name = "marine captain beret" - desc = "A beret with the captain insignia emblazoned on it. Wearer may suffer the heavy weight of responsibility upon their head and shoulders." + name = "marine commanding officer beret" + desc = "A beret with the commanding officer's insignia emblazoned on it. Wearer may suffer the heavy weight of responsibility upon their head and shoulders." icon = 'icons/obj/items/clothing/cm_hats.dmi' icon_state = "coberet" item_icons = list( @@ -499,8 +501,8 @@ ) /obj/item/clothing/head/marine/peaked/captain - name = "marine captain peaked cap" - desc = "A peaked cap with the captain insignia emblazoned on it. Wearer may suffer the heavy weight of responsibility upon their head and shoulders." + name = "marine commanding officer peaked cap" + desc = "A peaked cap with the commanding officer's insignia emblazoned on it. Wearer may suffer the heavy weight of responsibility upon their head and shoulders." icon = 'icons/obj/items/clothing/cm_hats.dmi' icon_state = "copeaked" item_icons = list( @@ -509,13 +511,13 @@ black_market_value = 30 /obj/item/clothing/head/marine/peaked/captain/white - name = "captain's dress white peaked cap" - desc = "A white, Navy-style peaked cap for the Captain. Wearer may suffer the heavy weight of responsibility upon their head." + name = "commanding officer's dress white peaked cap" + desc = "A white, Navy-style peaked cap for the Commanding Officer. Wearer may suffer the heavy weight of responsibility upon their head." icon_state = "co_peakedcap_white" /obj/item/clothing/head/marine/peaked/captain/black - name = "captain's dress black peaked cap" - desc = "A black, Navy-style peaked cap for the Captain. Wearer may suffer the heavy weight of responsibility upon their head." + name = "commanding officer's dress black peaked cap" + desc = "A black, Navy-style peaked cap for the Commanding Officer. Wearer may suffer the heavy weight of responsibility upon their head." icon_state = "co_peakedcap_black" /obj/item/clothing/head/beret/marine/chiefofficer diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 47e7210c963b..0181d239c574 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -58,6 +58,10 @@ flags_inventory = COVEREYES|BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEEYES|HIDETOPHAIR +/obj/item/clothing/head/helmet/riot/vintage_riot + desc = "A scarred riot helmet covered in cobwebs. It still protects your ears." + icon_state = "old_riot" + /obj/item/clothing/head/helmet/augment name = "augment array" desc = "A helmet with optical and cranial augments coupled to it." @@ -91,7 +95,7 @@ siemens_coefficient = 0.8 /obj/item/clothing/head/helmet/HoS/dermal - name = "Dermal Armour Patch" + name = "Dermal Armor Patch" desc = "You're not quite sure how you manage to take it on and off, but it implants nicely in your head." icon_state = "dermal" item_state = "dermal" @@ -322,6 +326,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( /obj/item/prop/helmetgarb/riot_shield = "helmet_riot_shield", /obj/item/attachable/flashlight = HELMET_GARB_RELAY_ICON_STATE, /obj/item/prop/helmetgarb/chaplain_patch = "chaplain_patch", + /obj/item/tool/pen/fountain = "fountainpen", // MEDICAL /obj/item/stack/medical/bruise_pack ="brutepack (bandages)", @@ -355,7 +360,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( var/flags_marine_helmet = HELMET_SQUAD_OVERLAY|HELMET_GARB_OVERLAY|HELMET_DAMAGE_OVERLAY var/helmet_bash_cooldown = 0 - var/specialty = "M10 pattern marine" //Give them a specialty var so that they show up correctly in vendors. + var/specialty = "M10 pattern marine" //Give them a specialty var so that they show up correctly in vendors. speciality does NOTHING if you have NO_NAME_OVERRIDE. valid_accessory_slots = list(ACCESSORY_SLOT_HELM_C) restricted_accessory_slots = list(ACCESSORY_SLOT_HELM_C) item_icons = list( @@ -367,8 +372,8 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( var/storage_slots_reserved_for_garb = 1 var/storage_max_w_class = SIZE_TINY // can hold tiny items only, EXCEPT for glasses & metal flask. var/storage_max_storage_space = 4 - - //speciality does NOTHING if you have NO_NAME_OVERRIDE + /// The dmi where the grayscale squad overlays are contained + var/helmet_overlay_icon = 'icons/mob/humans/onmob/head_1.dmi' /obj/item/clothing/head/helmet/marine/New(loc, new_protection[] = list(MAP_ICE_COLONY = ICE_PLANET_MIN_COLD_PROT)) @@ -608,7 +613,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( /obj/item/clothing/head/helmet/marine/rto name = "\improper M12 pattern dust helmet" - desc = "An experimental brain-bucket. A dust ruffle hangs from back instead of the standard lobster shell design. Moderately better at deflecting blunt objects at the cost of humiliation. But who will be laughing at the memorial? Not you, you'll be busy getting medals for your IMPORTANT phone calls. Usually worn by Radio Telephone Operators." + desc = "An experimental brain-bucket. A dust ruffle hangs from back instead of the standard lobster shell design. Moderately better at deflecting blunt objects at the cost of humiliation. But who will be laughing at the memorial? Not you, you'll be busy getting medals for your fantastic leadership." icon_state = "io" item_state = "io" armor_melee = CLOTHING_ARMOR_MEDIUMHIGH @@ -714,8 +719,8 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( specialty = "M45 ghillie" /obj/item/clothing/head/helmet/marine/CO - name = "\improper M10 pattern captain helmet" - desc = "A special M10 Pattern Helmet worn by Captains of the USCM. It reads on the label, 'The difference between an open-casket and closed-casket funeral. Wear on head for best results.'." + name = "\improper M10 pattern commanding officer helmet" + desc = "A special M10 Pattern Helmet worn by Commanding Officers of the USCM. It reads on the label, 'The difference between an open-casket and closed-casket funeral. Wear on head for best results.'." icon_state = "co_officer" item_state = "co_officer" armor_melee = CLOTHING_ARMOR_MEDIUMHIGH @@ -732,13 +737,19 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( item_state = "mp_helmet" armor_energy = CLOTHING_ARMOR_MEDIUMLOW specialty = "M10 pattern military police" - flags_atom = NO_SNOW_TYPE + +/obj/item/clothing/head/helmet/marine/MP/WO + name = "\improper M3 pattern chief MP helmet" + desc = "A well-crafted variant of the M10 Helmet typically distributed to Chief MPs. Useful for letting your men know who is in charge." + icon_state = "cmp_helmet" + item_state = "cmp_helmet" + specialty = "M10 pattern chief MP" /obj/item/clothing/head/helmet/marine/MP/SO name = "\improper M10 pattern Officer Helmet" desc = "A special variant of the M10 Pattern Helmet worn by Officers of the USCM, attracting the attention of the grunts and sniper fire alike." - icon_state = "d_helmet" - item_state = "d_helmet" + icon_state = "helmet" + item_state = "helmet" specialty = "M10 pattern officer" /obj/item/clothing/head/helmet/marine/mp/provost/marshal @@ -877,7 +888,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( name = "\improper Dutch's Dozen cap" desc = "A protective cap worn by some seriously experienced mercs." icon_state = "dutch_cap" - flags_inventory = BLOCKSHARPOBJ + flags_inventory = NO_FLAGS flags_inv_hide = NO_FLAGS flags_marine_helmet = NO_FLAGS @@ -885,7 +896,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( name = "\improper Dutch's Dozen band" desc = "A protective band worn by some seriously experienced mercs." icon_state = "dutch_band" - flags_inventory = BLOCKSHARPOBJ + flags_inventory = NO_FLAGS flags_inv_hide = NO_FLAGS flags_marine_helmet = NO_FLAGS @@ -1030,7 +1041,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( armor_bio = CLOTHING_ARMOR_MEDIUMLOW armor_rad = CLOTHING_ARMOR_MEDIUMLOW armor_internaldamage = CLOTHING_ARMOR_MEDIUM - flags_inventory = BLOCKSHARPOBJ + flags_inventory = NO_FLAGS flags_inv_hide = HIDEEARS|HIDETOPHAIR item_icons = list( WEAR_HEAD = 'icons/mob/humans/onmob/head_1.dmi' @@ -1053,7 +1064,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( armor_bio = CLOTHING_ARMOR_MEDIUMLOW armor_rad = CLOTHING_ARMOR_MEDIUMLOW armor_internaldamage = CLOTHING_ARMOR_LOW - flags_inventory = BLOCKSHARPOBJ + flags_inventory = NO_FLAGS flags_inv_hide = HIDEEARS|HIDETOPHAIR item_icons = list( WEAR_HEAD = 'icons/mob/humans/onmob/head_1.dmi' @@ -1071,7 +1082,6 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( switch(icon_state) if("s_skullcapm") desc = "A hood meant to protect the wearer from both the cold and the guise of the enemy in the tundra." - flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEALLHAIR //===========================//HELGHAST - MERCENARY\\================================\\ diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index c5a001a97c0b..e6dd7be603df 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -130,8 +130,9 @@ ..() if(!isturf(user.loc)) - to_chat(user, "You cannot turn the light on while in [user.loc]") //To prevent some lighting anomalities. + to_chat(user, SPAN_WARNING("You cannot turn the light [on ? "off" : "on" ] while in [user.loc].")) //To prevent some lighting anomalies. return + on = !on icon_state = "hardhat[on]_pumpkin" diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm index 2efed5d79bf0..6c69c750fe37 100644 --- a/code/modules/clothing/shoes/colour.dm +++ b/code/modules/clothing/shoes/colour.dm @@ -38,6 +38,11 @@ desc = "Stylish red shoes." icon_state = "red" +/obj/item/clothing/shoes/red/knife + name = "dirty red shoes" + desc = "Stylish red shoes with a small space to hold a knife." + items_allowed = list(/obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, /obj/item/weapon/gun/pistol/clfpistol, /obj/item/tool/screwdriver) + /obj/item/clothing/shoes/white name = "white shoes" icon_state = "white" diff --git a/code/modules/clothing/shoes/marine_shoes.dm b/code/modules/clothing/shoes/marine_shoes.dm index afe5068950dd..d4c772336e2a 100644 --- a/code/modules/clothing/shoes/marine_shoes.dm +++ b/code/modules/clothing/shoes/marine_shoes.dm @@ -19,7 +19,7 @@ max_heat_protection_temperature = SHOE_MAX_HEAT_PROT siemens_coefficient = 0.7 var/armor_stage = 0 - items_allowed = list(/obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, /obj/item/weapon/gun/pistol/clfpistol, /obj/item/tool/screwdriver) + items_allowed = list(/obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, /obj/item/weapon/gun/pistol/clfpistol, /obj/item/tool/screwdriver, /obj/item/tool/surgery/scalpel) var/knife_type /obj/item/clothing/shoes/marine/Initialize(mapload, ...) @@ -63,6 +63,16 @@ /obj/item/clothing/shoes/marine/upp_knife knife_type = /obj/item/attachable/bayonet/upp +/obj/item/clothing/shoes/marine/joe + name = "biohazard boots" + desc = "A pair of somewhat cheaply made biohazard boots. Tomorrow, Together." + armor_bullet = CLOTHING_ARMOR_LOW + armor_energy = CLOTHING_ARMOR_MEDIUMLOW + armor_bio = CLOTHING_ARMOR_MEDIUMHIGH + armor_rad = CLOTHING_ARMOR_MEDIUMHIGH + armor_internaldamage = CLOTHING_ARMOR_MEDIUMLOW + knife_type = /obj/item/attachable/bayonet + /obj/item/clothing/shoes/dress name = "dress shoes" desc = "Pre-polished fancy dress shoes. You can see your reflection in them." @@ -145,7 +155,7 @@ knife_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/marine/ress - name = "armoured sandals" + name = "armored sandals" icon_state = "sandals" item_state = "sandals" items_allowed = null diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 9d53ac1103c0..e3b07a76a2ff 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -159,8 +159,8 @@ max_heat_protection_temperature = SHOE_MAX_HEAT_PROT /obj/item/clothing/shoes/souto - name = "\improper Souto Man's boots. Harder than the kick of Souto Red." - desc = "Souto Man boots" + name = "Souto Man boots" + desc = "\improper Souto Man's boots. Harder than the kick of Souto Red" icon_state = "souto_man" item_state = "souto_man" flags_inventory = CANTSTRIP|NOSLIPPING diff --git a/code/modules/clothing/spacesuits/breaches.dm b/code/modules/clothing/spacesuits/breaches.dm index 2d5df82ad773..f2be4eaf2062 100644 --- a/code/modules/clothing/spacesuits/breaches.dm +++ b/code/modules/clothing/spacesuits/breaches.dm @@ -1,5 +1,5 @@ //A 'wound' system for space suits. -//Breaches greatly increase the amount of lost gas and decrease the armour rating of the suit. +//Breaches greatly increase the amount of lost gas and decrease the armor rating of the suit. //They can be healed with plastic or metal sheeting. /datum/breach diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 059cd5539cab..d969587e32e5 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -134,7 +134,7 @@ /obj/item/clothing/suit/armor/vest/warden name = "Warden's jacket" - desc = "An armoured jacket with silver rank pips and livery." + desc = "An armored jacket with silver rank pips and livery." icon_state = "warden_jacket" item_state = "armor" flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS @@ -238,6 +238,9 @@ time_to_unequip = 20 time_to_equip = 20 +/obj/item/clothing/suit/armor/riot/marine/vintage_riot + desc = "Barring the slightly off-color plates, it's preserved quite well." + icon_state = "old_riot" /obj/item/clothing/suit/armor/swat name = "swat suit" diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm index dbf47a54d70e..278ffb666bfd 100644 --- a/code/modules/clothing/suits/labcoat.dm +++ b/code/modules/clothing/suits/labcoat.dm @@ -170,7 +170,7 @@ /obj/item/clothing/suit/storage/snow_suit/synth name = "synthetic's snow suit" desc = "A snow suit designed for keeping synthetic units within acceptable temperature ranges in extremely cold environments to prevent power supply inefficiency. Due to advancements made in synthetic insulation, they are not required for most cold environments." - armor_melee = CLOTHING_ARMOR_NONE //no free armour for synths + armor_melee = CLOTHING_ARMOR_NONE //no free armor for synths armor_bullet = CLOTHING_ARMOR_NONE armor_laser = CLOTHING_ARMOR_NONE armor_energy = CLOTHING_ARMOR_NONE @@ -221,7 +221,6 @@ /obj/item/explosive/grenade, /obj/item/device/binoculars, /obj/item/attachable/bayonet, - /obj/item/storage/backpack/general_belt, /obj/item/storage/large_holster/machete, /obj/item/weapon/baseballbat, /obj/item/weapon/baseballbat/metal, @@ -289,7 +288,6 @@ /obj/item/explosive/grenade, /obj/item/device/binoculars, /obj/item/attachable/bayonet, - /obj/item/storage/backpack/general_belt, /obj/item/storage/large_holster/machete, /obj/item/weapon/baseballbat, /obj/item/weapon/baseballbat/metal, @@ -297,3 +295,7 @@ /obj/item/device/walkman, ) +/obj/item/clothing/suit/storage/snow_suit/liaison + name = "liaison's winter coat" + desc = "A Weyland-Yutani winter coat. Only the best comfort for the liaison in a cold environment." + icon_state = "snowsuit_liaison" diff --git a/code/modules/clothing/suits/marine_armor.dm b/code/modules/clothing/suits/marine_armor.dm index 912bd32fb139..910bb032349e 100644 --- a/code/modules/clothing/suits/marine_armor.dm +++ b/code/modules/clothing/suits/marine_armor.dm @@ -28,44 +28,6 @@ #define SOF 7 #define NOSQUAD 8 -var/list/armormarkings = list() -var/list/armormarkings_sql = list() -var/list/helmetmarkings = list() -var/list/helmetmarkings_sql = list() -var/list/glovemarkings = list() -var/list/squad_colors = list(rgb(230,25,25), rgb(255,195,45), rgb(200,100,200), rgb(65,72,200), rgb(103,214,146), rgb(196, 122, 80), rgb(64, 0, 0)) -var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150,255), rgb(130,140,255), rgb(103,214,146), rgb(196, 122, 80), rgb(64, 0, 0)) - -/proc/initialize_marine_armor() - var/i - for(i=1, i<(length(squad_colors) + 1), i++) - var/squad_color = squad_colors[i] - var/armor_color = rgb(hex2num(copytext(squad_color, 2, 4)), hex2num(copytext(squad_color, 4, 6)), hex2num(copytext(squad_color, 6, 8)), 125) - - var/image/armor - var/image/helmet - var/image/glove - - armor = image('icons/mob/humans/onmob/suit_1.dmi',icon_state = "std-armor") - armor.color = armor_color - armormarkings += armor - armor = image('icons/mob/humans/onmob/suit_1.dmi',icon_state = "sql-armor") - armor.color = armor_color - armormarkings_sql += armor - - helmet = image('icons/mob/humans/onmob/head_1.dmi',icon_state = "std-helmet") - helmet.color = armor_color - helmetmarkings += helmet - helmet = image('icons/mob/humans/onmob/head_1.dmi',icon_state = "sql-helmet") - helmet.color = armor_color - helmetmarkings_sql += helmet - - glove = image('icons/mob/humans/onmob/hands_garb.dmi',icon_state = "std-gloves") - glove.color = armor_color - glovemarkings += glove - - - // MARINE STORAGE ARMOR /obj/item/clothing/suit/storage/marine @@ -78,6 +40,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 WEAR_JACKET = 'icons/mob/humans/onmob/suit_1.dmi' ) flags_atom = FPRINT|CONDUCT + flags_inventory = BLOCKSHARPOBJ flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS flags_cold_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS flags_heat_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS @@ -112,6 +75,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/storage/belt/gun/flaregun, /obj/item/device/motiondetector, /obj/item/device/walkman, + /obj/item/storage/belt/gun/m39, ) valid_accessory_slots = list(ACCESSORY_SLOT_MEDAL, ACCESSORY_SLOT_PONCHO) @@ -121,7 +85,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 var/armor_overlays[] actions_types = list(/datum/action/item_action/toggle) var/flags_marine_armor = ARMOR_SQUAD_OVERLAY|ARMOR_LAMP_OVERLAY - var/specialty = "M3 pattern marine" //Same thing here. Give them a specialty so that they show up correctly in vendors. + var/specialty = "M3 pattern marine" //Same thing here. Give them a specialty so that they show up correctly in vendors. speciality does NOTHING if you have NO_NAME_OVERRIDE w_class = SIZE_HUGE uniform_restricted = list(/obj/item/clothing/under/marine) sprite_sheets = list(SPECIES_MONKEY = 'icons/mob/humans/species/monkeys/onmob/suit_monkey_1.dmi') @@ -131,10 +95,10 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 drop_sound = "armorequip" equip_sounds = list('sound/handling/putting_on_armor1.ogg') var/armor_variation = 0 + /// The dmi where the grayscale squad overlays are contained + var/squad_overlay_icon = 'icons/mob/humans/onmob/suit_1.dmi' - //speciality does NOTHING if you have NO_NAME_OVERRIDE - -/obj/item/clothing/suit/storage/marine/Initialize() +/obj/item/clothing/suit/storage/marine/Initialize(mapload) . = ..() if(!(flags_atom & NO_NAME_OVERRIDE)) name = "[specialty]" @@ -142,12 +106,12 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 name += " snow armor" //Leave marine out so that armors don't have to have "Marine" appended (see: generals). else name += " armor" - if(armor_variation) - icon_state = replacetext(icon_state,"1","[rand(1,armor_variation)]") if(!(flags_atom & NO_SNOW_TYPE)) select_gamemode_skin(type) armor_overlays = list("lamp") //Just one for now, can add more later. + if(armor_variation && mapload) + post_vendor_spawn_hook() update_icon() pockets.max_w_class = SIZE_SMALL //Can contain small items AND rifle magazines. pockets.bypass_w_limit = list( @@ -170,6 +134,22 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 else armor_overlays["lamp"] = null if(user) user.update_inv_wear_suit() + +/obj/item/clothing/suit/storage/marine/post_vendor_spawn_hook(mob/living/carbon/human/user) //used for randomizing/selecting a variant for armors. + var/new_look //used for the icon_state text replacement. + + if(!user?.client?.prefs) + new_look = rand(1,armor_variation) + + else if(user.client.prefs.preferred_armor == "Random") + new_look = rand(1,armor_variation) + + else + new_look = GLOB.armor_style_list[user.client.prefs.preferred_armor] + + icon_state = replacetext(icon_state,"1","[new_look]") + update_icon(user) + /obj/item/clothing/suit/storage/marine/pickup(mob/user) if(flags_marine_armor & ARMOR_LAMP_ON) user.SetLuminosity(brightness_on, FALSE, src) @@ -205,8 +185,9 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 ..() if(!isturf(user.loc)) - to_chat(user, SPAN_WARNING("You cannot turn the light on while in [user.loc].")) //To prevent some lighting anomalities. + to_chat(user, SPAN_WARNING("You cannot turn the light [is_light_on() ? "off" : "on"] while in [user.loc].")) //To prevent some lighting anomalies. return + if(flashlight_cooldown > world.time) return if(!ishuman(user)) @@ -282,7 +263,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/clothing/suit/storage/marine/rto icon_state = "io" name = "\improper M4 pattern marine armor" - desc = "A well tinkered and crafted hybrid of Smart-Gunner mesh and M3 pattern plates. Robust, yet nimble, with room for all your pouches. Required for carrying a Radio Telephone Pack." + desc = "A well tinkered and crafted hybrid of Smart-Gunner mesh and M3 pattern plates. Robust, yet nimble, with room for all your pouches." armor_bio = CLOTHING_ARMOR_MEDIUMHIGH armor_rad = CLOTHING_ARMOR_MEDIUM storage_slots = 4 @@ -291,14 +272,13 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/clothing/suit/storage/marine/rto/intel name = "\improper XM4 pattern intelligence officer armor" - desc = "A well tinkered and crafted hybrid of Smart-Gunner mesh and M3 pattern plates. Robust, yet nimble, with room for all your pouches." - uniform_restricted = list(/obj/item/clothing/under/marine/officer, /obj/item/clothing/under/rank/ro_suit, /obj/item/clothing/under/marine/officer/intel) + uniform_restricted = list(/obj/item/clothing/under/marine/officer, /obj/item/clothing/under/rank/qm_suit, /obj/item/clothing/under/marine/officer/intel) specialty = "XM4 pattern intel" /obj/item/clothing/suit/storage/marine/MP name = "\improper M2 pattern MP armor" desc = "A standard Colonial Marines M2 Pattern Chestplate. Protects the chest from ballistic rounds, bladed objects and accidents. It has a small leather pouch strapped to it for limited storage." - icon_state = "mp" + icon_state = "mp_armor" armor_melee = CLOTHING_ARMOR_MEDIUMHIGH armor_bullet = CLOTHING_ARMOR_LOW armor_laser = CLOTHING_ARMOR_LOW @@ -308,7 +288,6 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_internaldamage = CLOTHING_ARMOR_MEDIUMLOW storage_slots = 2 slowdown = SLOWDOWN_ARMOR_LIGHT - flags_atom = NO_SNOW_TYPE allowed = list( /obj/item/weapon/gun, /obj/item/tank/emergency_oxygen, @@ -330,22 +309,9 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 ) uniform_restricted = list(/obj/item/clothing/under/marine/mp) specialty = "M2 pattern MP" - item_state_slots = list(WEAR_JACKET = "mp") + item_state_slots = list(WEAR_JACKET = "mp_armor") black_market_value = 20 -/obj/item/clothing/suit/storage/marine/MP/padless - name = "\improper M2 pattern padless MP armor" - icon_state = "mp_2" - specialty = "M2 pattern padless MP" - item_state_slots = list(WEAR_JACKET = "mp_2") - -/obj/item/clothing/suit/storage/marine/MP/jacket - name = "\improper MP service jacket over M2 pattern MP armor" - desc = "A standard Colonial Marines M2 Pattern Chestplate with an MP service jacket worn on top. Protects the chest from ballistic rounds, bladed objects and accidents. It has a small leather pouch strapped to it for limited storage. Arresting Marines for breaking windows has never felt so stylish." - icon_state = "mp_jacket" - specialty = "service jacket over M2 pattern MP" - item_state_slots = list(WEAR_JACKET = "mp_jacket") - /obj/item/clothing/suit/storage/marine/MP/warden icon_state = "warden" name = "\improper M3 pattern warden MP armor" @@ -356,19 +322,6 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 specialty = "M3 pattern warden MP" item_state_slots = list(WEAR_JACKET = "warden") -/obj/item/clothing/suit/storage/marine/MP/warden/padless - name = "\improper M3 pattern padless warden MP armor" - icon_state = "warden_2" - specialty = "M3 pattern padless warden MP" - item_state_slots = list(WEAR_JACKET = "warden_2") - -/obj/item/clothing/suit/storage/marine/MP/warden/jacket - name = "\improper warden service jacket over M3 pattern warden MP armor" - desc = "A well-crafted suit of M3 Pattern Armor typically distributed to Wardens, with a Warden service jacket worn on top. Look your best while you're escorting prisoners to their execution." - icon_state = "warden_jacket" - specialty = "warden service jacket over M3 pattern warden MP" - item_state_slots = list(WEAR_JACKET = "warden_jacket") - /obj/item/clothing/suit/storage/marine/MP/WO icon_state = "warrant_officer" name = "\improper M3 pattern chief MP armor" @@ -378,19 +331,6 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 item_state_slots = list(WEAR_JACKET = "warrant_officer") black_market_value = 30 -/obj/item/clothing/suit/storage/marine/MP/WO/padless - name = "\improper M3 pattern padless chief MP armor" - icon_state = "warrant_officer_2" - specialty = "M3 pattern padless chief MP" - item_state_slots = list(WEAR_JACKET = "warrant_officer_2") - -/obj/item/clothing/suit/storage/marine/MP/WO/jacket - name = "\improper CMP service jacket over M3 pattern chief MP armor" - desc = "A well-crafted suit of M3 Pattern Armor typically distributed to Chief MPs, with a CMP service jacket on top. Resonates with the strength of a thousand arguments with and arrests of superior officers." - icon_state = "warrant_officer_jacket" - specialty = "CMP service jacket over M3 pattern chief MP" - item_state_slots = list(WEAR_JACKET = "warrant_officer_jacket") - /obj/item/clothing/suit/storage/marine/MP/general name = "\improper M3 pattern general officer armor" desc = "A well-crafted suit of M3 Pattern Armor with a gold shine. It looks very expensive, but shockingly fairly easy to carry and wear." @@ -408,22 +348,22 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 icon_state = "officer" storage_slots = 3 flags_atom = null - uniform_restricted = list(/obj/item/clothing/under/marine/officer, /obj/item/clothing/under/rank/ro_suit, /obj/item/clothing/under/rank/chief_medical_officer) + uniform_restricted = list(/obj/item/clothing/under/marine/officer, /obj/item/clothing/under/rank/qm_suit, /obj/item/clothing/under/rank/chief_medical_officer) specialty = "M2 pattern officer" item_state_slots = list(WEAR_JACKET = "officer") //Making a new object because we might want to edit armor values and such. //Or give it its own sprite. It's more for the future. /obj/item/clothing/suit/storage/marine/MP/CO - name = "\improper M3 pattern captain armor" + name = "\improper M3 pattern commanding officer armor" desc = "A robust, well-polished suit of armor for the Commanding Officer. Custom-made to fit its owner with special straps to operate a smartgun. Show those Marines who's really in charge." icon_state = "co_officer" item_state = "co_officer" armor_bullet = CLOTHING_ARMOR_HIGH storage_slots = 3 flags_atom = NO_SNOW_TYPE - flags_inventory = SMARTGUN_HARNESS - uniform_restricted = list(/obj/item/clothing/under/marine, /obj/item/clothing/under/rank/ro_suit) + flags_inventory = BLOCKSHARPOBJ|SMARTGUN_HARNESS + uniform_restricted = list(/obj/item/clothing/under/marine, /obj/item/clothing/under/rank/qm_suit) specialty = "M3 pattern captain" item_state_slots = list(WEAR_JACKET = "co_officer") valid_accessory_slots = list(ACCESSORY_SLOT_MEDAL, ACCESSORY_SLOT_RANK, ACCESSORY_SLOT_DECOR, ACCESSORY_SLOT_PONCHO) @@ -431,7 +371,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/clothing/suit/storage/marine/MP/CO/jacket - name = "\improper M3 pattern captain armored coat" + name = "\improper M3 pattern commanding officer armored coat" desc = "A robust, well-polished suit of armor for the Commanding Officer. Custom-made to fit its owner with special straps to operate a smartgun. Show those Marines who's really in charge. This one has a coat over it for added warmth." icon_state = "bridge_coat_armored" item_state = "bridge_coat_armored" @@ -440,7 +380,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/clothing/suit/storage/marine/smartgunner - name = "M56 combat harness" + name = "\improper M56 combat harness" desc = "A heavy protective vest designed to be worn with the M56 Smartgun System. \nIt has specially designed straps and reinforcement to carry the Smartgun and accessories." icon_state = "8" item_state = "armor" @@ -449,7 +389,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_rad = CLOTHING_ARMOR_MEDIUM storage_slots = 2 slowdown = SLOWDOWN_ARMOR_LIGHT - flags_inventory = SMARTGUN_HARNESS + flags_inventory = BLOCKSHARPOBJ|SMARTGUN_HARNESS allowed = list( /obj/item/tank/emergency_oxygen, /obj/item/device/flashlight, @@ -470,6 +410,35 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 name = "M56 combat harness" //select_gamemode_skin(type) +/obj/item/clothing/suit/storage/marine/smartgunner/mob_can_equip(mob/equipping_mob, slot, disable_warning = FALSE) + . = ..() + + if(equipping_mob.back) + to_chat(equipping_mob, SPAN_WARNING("You can't equip [src] while wearing a backpack.")) + return FALSE + +/obj/item/clothing/suit/storage/marine/smartgunner/equipped(mob/user, slot, silent) + . = ..() + + if(slot == WEAR_JACKET) + RegisterSignal(user, COMSIG_HUMAN_ATTEMPTING_EQUIP, PROC_REF(check_equipping)) + +/obj/item/clothing/suit/storage/marine/smartgunner/proc/check_equipping(mob/living/carbon/human/equipping_human, obj/item/equipping_item, slot) + SIGNAL_HANDLER + + if(slot != WEAR_BACK) + return + + . = COMPONENT_HUMAN_CANCEL_ATTEMPT_EQUIP + + if(equipping_item.flags_equip_slot == SLOT_BACK) + to_chat(equipping_human, SPAN_WARNING("You can't equip [equipping_item] on your back while wearing [src].")) + return + +/obj/item/clothing/suit/storage/marine/smartgunner/unequipped(mob/user, slot) + . = ..() + + UnregisterSignal(user, COMSIG_HUMAN_ATTEMPTING_EQUIP) /obj/item/clothing/suit/storage/marine/leader name = "\improper B12 pattern marine armor" @@ -505,11 +474,35 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_melee = CLOTHING_ARMOR_MEDIUMLOW armor_bullet = CLOTHING_ARMOR_MEDIUMLOW armor_bomb = CLOTHING_ARMOR_MEDIUM - armor_bio = CLOTHING_ARMOR_MEDIUMHIGH + armor_bio = CLOTHING_ARMOR_MEDIUMLOW armor_rad = CLOTHING_ARMOR_MEDIUMHIGH armor_internaldamage = CLOTHING_ARMOR_LOW storage_slots = 2 +/obj/item/clothing/suit/storage/marine/light/padded + icon_state = "L1" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/light/padless + icon_state = "L2" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/light/padless_lines + icon_state = "L3" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/light/carrier + icon_state = "L4" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/light/skull + icon_state = "L5" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/light/smooth + icon_state = "L6" + armor_variation = 0 + /obj/item/clothing/suit/storage/marine/light/vest name = "\improper M3-VL pattern ballistics vest" desc = "Up until 2182 USCM non-combat personnel were issued non-standardized ballistics vests, though the lack of IMP compatibility and suit lamps proved time and time again inefficient. This modified M3-L shell is the result of a 6-year R&D program; It provides utility, protection, AND comfort to all USCM non-combat personnel." @@ -520,7 +513,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_bullet = CLOTHING_ARMOR_HIGH armor_energy = CLOTHING_ARMOR_LOW armor_bomb = CLOTHING_ARMOR_LOW - armor_bio = CLOTHING_ARMOR_NONE + armor_bio = CLOTHING_ARMOR_VERYLOW armor_rad = CLOTHING_ARMOR_NONE armor_internaldamage = CLOTHING_ARMOR_MEDIUM storage_slots = 1 @@ -550,6 +543,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_rad = CLOTHING_ARMOR_NONE armor_internaldamage = CLOTHING_ARMOR_NONE storage_slots = 3 + slowdown = SLOWDOWN_ARMOR_VERY_LIGHT time_to_unequip = 0.5 SECONDS time_to_equip = 1 SECONDS uniform_restricted = null @@ -560,7 +554,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/clothing/suit/storage/marine/heavy name = "\improper M3-EOD pattern heavy armor" - desc = "A heavier version of the standard M3 pattern armor, the armor is primarily designed to withstand ballistic, explosive, and internal damage, with the drawback of increased bulk and thus reduced movement speed, alongside little additional protection from standard blunt force impacts and none from biological threats." + desc = "A heavier version of the standard M3 pattern armor, the armor is primarily designed to withstand ballistic, explosive, and internal damage, with the drawback of increased bulk and thus reduced movement speed, alongside little additional protection from standard blunt force impacts and biological threats." desc_lore = "This configuration of the iconic armor was developed during the Canton War in 2160 between the UPP and USCM - Designed in response to a need for higher protection for ComTechs assigned as EODs during the conflict, this is the pinnacle of protection for your average marine. The shoulders and kneepads have both been expanded upon heavily, covering up the arteries on each limb. A special spall liner was developed for this suit, with the same technology being used in the M70 Flak Jacket being developed at the same time." specialty = "\improper M3-EOD pattern" icon_state = "H1" @@ -568,13 +562,37 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_melee = CLOTHING_ARMOR_MEDIUMHIGH armor_bullet = CLOTHING_ARMOR_HIGHPLUS armor_bomb = CLOTHING_ARMOR_HIGHPLUS - armor_bio = CLOTHING_ARMOR_MEDIUM + armor_bio = CLOTHING_ARMOR_MEDIUMHIGH armor_rad = CLOTHING_ARMOR_MEDIUM armor_internaldamage = CLOTHING_ARMOR_MEDIUMHIGH storage_slots = 2 slowdown = SLOWDOWN_ARMOR_LOWHEAVY movement_compensation = SLOWDOWN_ARMOR_MEDIUM +/obj/item/clothing/suit/storage/marine/heavy/padded + icon_state = "H1" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/heavy/padless + icon_state = "H2" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/heavy/padless_lines + icon_state = "H3" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/heavy/carrier + icon_state = "H4" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/heavy/skull + icon_state = "H5" + armor_variation = 0 + +/obj/item/clothing/suit/storage/marine/heavy/smooth + icon_state = "H6" + armor_variation = 0 + //===========================//SPECIALIST\\================================\\ //=======================================================================\\ @@ -589,7 +607,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_rad = CLOTHING_ARMOR_MEDIUMHIGH armor_internaldamage = CLOTHING_ARMOR_MEDIUMHIGH storage_slots = 2 - flags_inventory = BLOCK_KNOCKDOWN + flags_inventory = BLOCKSHARPOBJ|BLOCK_KNOCKDOWN flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS|BODY_FLAG_FEET flags_cold_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS|BODY_FLAG_FEET flags_heat_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS|BODY_FLAG_FEET @@ -630,7 +648,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_bomb = CLOTHING_ARMOR_VERYHIGH armor_bio = CLOTHING_ARMOR_MEDIUMLOW armor_internaldamage = CLOTHING_ARMOR_MEDIUMHIGH - flags_inventory = BLOCK_KNOCKDOWN + flags_inventory = BLOCKSHARPOBJ|BLOCK_KNOCKDOWN flags_item = MOB_LOCK_ON_EQUIP|NO_CRYO_STORE flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS|BODY_FLAG_FEET flags_cold_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS|BODY_FLAG_FEET @@ -976,6 +994,12 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 #undef FULL_CAMOUFLAGE_ALPHA +/obj/item/clothing/suit/storage/marine/ghillie/forecon + name = "UDEP Thermal Poncho" + desc = "UDEP or the Ultra Diffusive Environmental Poncho is a camouflaged rain-cover worn to protect against the elements and chemical spills. It's commonly treated with an infrared absorbing coating, making a marine almost invisible in the rain. Favoured by USCM specialists for it's comfort and practicality." + icon_state = "mercenary_miner_armor" + flags_atom = MOB_LOCK_ON_EQUIP|NO_SNOW_TYPE|NO_NAME_OVERRIDE + /obj/item/clothing/suit/storage/marine/sof name = "\improper SOF Armor" desc = "A heavily customized suit of M3 armor. Used by Marine Raiders." @@ -1030,7 +1054,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/clothing/suit/storage/marine/veteran/pmc/light name = "\improper M4 pattern light PMC armor" - desc = "A modification of the standard Armat Systems M3 armor. Designed for high-profile security operators and corporate mercenaries in mind. Has some armour plating removed for extra mobility." + desc = "A modification of the standard Armat Systems M3 armor. Designed for high-profile security operators and corporate mercenaries in mind. Has some armor plating removed for extra mobility." icon_state = "pmc_sniper" armor_melee = CLOTHING_ARMOR_MEDIUMLOW armor_bullet = CLOTHING_ARMOR_MEDIUM @@ -1076,7 +1100,6 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_bomb = CLOTHING_ARMOR_MEDIUM armor_rad = CLOTHING_ARMOR_MEDIUM armor_internaldamage = CLOTHING_ARMOR_MEDIUM - flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDELOWHAIR item_state_slots = list(WEAR_JACKET = "pmc_sniper") @@ -1104,7 +1127,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 name = "\improper PMC gunner armor" desc = "A modification of the standard Armat Systems M3 armor. Hooked up with harnesses and straps allowing the user to carry an M56 Smartgun." icon_state = "heavy_armor" - flags_inventory = BLOCK_KNOCKDOWN|SMARTGUN_HARNESS + flags_inventory = BLOCKSHARPOBJ|BLOCK_KNOCKDOWN|SMARTGUN_HARNESS flags_atom = NO_SNOW_TYPE|NO_NAME_OVERRIDE armor_bullet = CLOTHING_ARMOR_MEDIUMHIGH armor_laser = CLOTHING_ARMOR_MEDIUMLOW @@ -1168,11 +1191,11 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 name = "\improper D2 armored vest" desc = "A protective vest worn by some seriously experienced mercs." icon_state = "dutch_armor" - flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN + flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS|BODY_FLAG_LEGS //Makes no sense but they need leg/arm armor too. armor_melee = CLOTHING_ARMOR_HIGH armor_bullet = CLOTHING_ARMOR_HIGHPLUS armor_energy = CLOTHING_ARMOR_MEDIUMLOW - armor_bomb = CLOTHING_ARMOR_MEDIUM + armor_bomb = CLOTHING_ARMOR_HIGH armor_rad = CLOTHING_ARMOR_MEDIUM storage_slots = 2 brightness_on = 9 @@ -1181,7 +1204,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/clothing/suit/storage/marine/veteran/van_bandolier name = "safari jacket" - desc = "A tailored hunting jacket, cunningly lined with segmented armour plates. Sometimes the game shoots back." + desc = "A tailored hunting jacket, cunningly lined with segmented armor plates. Sometimes the game shoots back." icon_state = "van_bandolier" item_state = "van_bandolier_jacket" blood_overlay_type = "coat" @@ -1269,7 +1292,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 desc = "An extremely heavy-duty set of body armor in service with the UPP military, the UH7 (Union Heavy MK7) is known for having powerful ballistic protection, alongside a noticeable neck guard, fortified in order to allow the wearer to endure the stresses of the bulky helmet." icon_state = "upp_armor_heavy" slowdown = SLOWDOWN_ARMOR_HEAVY - flags_inventory = BLOCK_KNOCKDOWN + flags_inventory = BLOCKSHARPOBJ|BLOCK_KNOCKDOWN flags_armor_protection = BODY_FLAG_ALL_BUT_HEAD armor_melee = CLOTHING_ARMOR_MEDIUMHIGH armor_bullet = CLOTHING_ARMOR_HIGHPLUS @@ -1446,7 +1469,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 /obj/item/clothing/suit/storage/militia/smartgun name = "colonial militia harness" desc = "The hauberk of a colonist militia member, created from boiled leather and some modern armored plates. While not the most powerful form of armor, and primitive compared to most modern suits of armor, it gives the wearer almost perfect mobility, which suits the needs of the local colonists. It is also quick to don, easy to hide, and cheap to produce in large workshops. This one has straps interweaved with the plates, that allow the user to fire a captured smartgun, if a bit uncomfortably." - flags_inventory = SMARTGUN_HARNESS + flags_inventory = BLOCKSHARPOBJ|SMARTGUN_HARNESS /obj/item/clothing/suit/storage/CMB name = "\improper CMB jacket" @@ -1494,7 +1517,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 pockets.max_storage_space = 8 /obj/item/clothing/suit/storage/RO - name = "\improper RO jacket" + name = "quartermaster jacket" desc = "A green jacket worn by USCM personnel. The back has the flag of the United Americas on it." icon_state = "RO_jacket" blood_overlay_type = "coat" @@ -1509,7 +1532,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 name = "\improper K12 ceramic plated armor" desc = "A set of grey, heavy ceramic armor with dark blue highlights. It is the standard uniform of an unknown mercenary group working in the sector." icon_state = "mercenary_heavy_armor" - flags_inventory = BLOCK_KNOCKDOWN + flags_inventory = BLOCKSHARPOBJ|BLOCK_KNOCKDOWN armor_melee = CLOTHING_ARMOR_VERYHIGH armor_bullet = CLOTHING_ARMOR_VERYHIGH armor_energy = CLOTHING_ARMOR_MEDIUMLOW diff --git a/code/modules/clothing/suits/marine_coat.dm b/code/modules/clothing/suits/marine_coat.dm index 4442109ec425..4ca2a54af4bf 100644 --- a/code/modules/clothing/suits/marine_coat.dm +++ b/code/modules/clothing/suits/marine_coat.dm @@ -178,6 +178,11 @@ desc = "A Navy regulation dress blues coat for high-ranking officers. For those who wish for style and authority." icon_state = "co_suit" +/obj/item/clothing/suit/storage/jacket/marine/dress/officer/falcon + name = "commanding officer falcon jacket" + desc = "A refurbished jacket liner tailor made for a senior officer. This liner has become more of a proper piece of attire, with a new layer of fabric, wrist cuffs, front pockets, and a custom embroidered falcon on the back. This jacket will keep its wearer warm no matter the circumstance, from a cool Sunday drive to chilly autumn's eve." + icon_state = "co_falcon" + /obj/item/clothing/suit/storage/jacket/marine/dress/general name = "general's jacket" desc = "A black trench coat with gold metallic trim. Flashy, highly protective, and over-the-top. Fit for a king - or, in this case, a General. Has quite a few pockets." @@ -212,6 +217,13 @@ icon_state = "bridge_coat_grey" valid_accessory_slots = list(ACCESSORY_SLOT_ARMBAND, ACCESSORY_SLOT_RANK, ACCESSORY_SLOT_MEDAL) +/obj/item/clothing/suit/storage/jacket/marine/service/aso + name = "auxiliary support officer jacket" + desc = "A comfortable vest for officers who are expected to work long hours staring at rows of numbers and inspecting equipment from knives to torpedos to entire dropships." + icon_state = "aso_jacket" + blood_overlay_type = "coat" + flags_armor_protection = BODY_FLAG_CHEST + has_buttons = FALSE //=========================//PROVOST\\================================\\ diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index bd5b0da9cd39..c51f5f2575ed 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -9,7 +9,7 @@ * Lasertag */ /obj/item/clothing/suit/bluetag - name = "blue laser tag armour" + name = "blue laser tag armor" desc = "Blue Pride, Station Wide." icon_state = "bluetag" item_state = "bluetag" @@ -28,7 +28,7 @@ siemens_coefficient = 3 /obj/item/clothing/suit/redtag - name = "red laser tag armour" + name = "red laser tag armor" desc = "Reputed to go faster." icon_state = "redtag" item_state = "redtag" @@ -272,13 +272,11 @@ flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_ARMS /obj/item/clothing/suit/storage/webbing - name = "External webbing" + name = "external webbing" desc = "Designed to be worn over a jumpsuit rather than clipped on." icon_state = "webbing" item_state = "webbing" allowed = list( - /obj/item/storage/fancy/cigarettes, - /obj/item/tool/lighter, /obj/item/weapon/baton, /obj/item/handcuffs, /obj/item/device/binoculars, @@ -287,7 +285,6 @@ /obj/item/device/flashlight, /obj/item/device/healthanalyzer, /obj/item/device/radio, - /obj/item/tank/emergency_oxygen, /obj/item/tool/crowbar, /obj/item/tool/crew_monitor, /obj/item/tool/pen, @@ -295,6 +292,26 @@ /obj/item/device/motiondetector, ) +/obj/item/clothing/suit/storage/utility_vest + name = "utility vest" + desc = "A utility vest to hold tools in." + icon_state = "synth_utility_vest" + item_state = "synth_utility_vest" + allowed = list( + /obj/item/weapon/baton, + /obj/item/handcuffs, + /obj/item/device/binoculars, + /obj/item/attachable/bayonet, + + /obj/item/device/flashlight, + /obj/item/device/healthanalyzer, + /obj/item/device/radio, + /obj/item/tool/crowbar, + /obj/item/tool/crew_monitor, + /obj/item/storage/large_holster/machete, + /obj/item/device/motiondetector, + ) + //Blue suit jacket toggle /obj/item/clothing/suit/suit/verb/toggle() set name = "Toggle Jacket Buttons" diff --git a/code/modules/clothing/suits/storage.dm b/code/modules/clothing/suits/storage.dm index f3c569f3ad80..a18faa60c0d3 100644 --- a/code/modules/clothing/suits/storage.dm +++ b/code/modules/clothing/suits/storage.dm @@ -36,8 +36,8 @@ pockets.emp_act(severity) ..() -/obj/item/clothing/suit/storage/hear_talk(mob/M, msg) - pockets.hear_talk(M, msg) +/obj/item/clothing/suit/storage/hear_talk(mob/living/M, msg, verb, datum/language/speaking, italics) + pockets.hear_talk(M, msg, verb, speaking, italics) ..() /obj/item/clothing/suit/storage/verb/toggle_draw_mode() diff --git a/code/modules/clothing/under/jobs/civilian.dm b/code/modules/clothing/under/jobs/civilian.dm index 21c439454b1f..4b1fd077415c 100644 --- a/code/modules/clothing/under/jobs/civilian.dm +++ b/code/modules/clothing/under/jobs/civilian.dm @@ -127,6 +127,6 @@ /obj/item/clothing/under/mime name = "mime's outfit" - desc = "It's not very colourful." + desc = "It's not very colorful." icon_state = "mime" flags_jumpsuit = FALSE diff --git a/code/modules/clothing/under/marine_uniform.dm b/code/modules/clothing/under/marine_uniform.dm index 2da9eff26354..a4b38b657735 100644 --- a/code/modules/clothing/under/marine_uniform.dm +++ b/code/modules/clothing/under/marine_uniform.dm @@ -102,9 +102,8 @@ icon_state = "MP_jumpsuit" worn_state = "MP_jumpsuit" suit_restricted = list(/obj/item/clothing/suit/storage/marine, /obj/item/clothing/suit/armor/riot/marine, /obj/item/clothing/suit/storage/jacket/marine/service/mp) - flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE + flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE|UNIFORM_SLEEVE_CUTTABLE|UNIFORM_JACKET_REMOVABLE specialty = "military police" - flags_atom = NO_SNOW_TYPE /obj/item/clothing/under/marine/warden name = "military warden jumpsuit" @@ -112,7 +111,7 @@ icon_state = "warden_jumpsuit" worn_state = "warden_jumpsuit" suit_restricted = list(/obj/item/clothing/suit/storage/marine, /obj/item/clothing/suit/armor/riot/marine, /obj/item/clothing/suit/storage/jacket/marine/service/warden) - flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE + flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE|UNIFORM_SLEEVE_CUTTABLE|UNIFORM_JACKET_REMOVABLE specialty = "military warden" flags_atom = NO_SNOW_TYPE @@ -162,7 +161,7 @@ flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE flags_atom = NO_NAME_OVERRIDE flags_cold_protection = ICE_PLANET_MIN_COLD_PROT - suit_restricted = list(/obj/item/clothing/suit/armor/vest/pilot, /obj/item/clothing/suit/storage/marine/light/vest/dcc, /obj/item/clothing/suit/storage/jacket/marine/pilot) + suit_restricted = list(/obj/item/clothing/suit/armor/vest/pilot, /obj/item/clothing/suit/storage/marine/light/vest/dcc, /obj/item/clothing/suit/storage/jacket/marine/pilot, /obj/item/clothing/suit/storage/marine/light/vest) /obj/item/clothing/under/marine/officer/pilot/flight name = "tactical pilot officer flightsuit" @@ -203,7 +202,7 @@ /obj/item/clothing/under/marine/officer/exec name = "executive officer uniform" - desc = "A uniform typically worn by a commander Executive Officer in the USCM. It has shards of light Kevlar to help protect against stabbing weapons and bullets." + desc = "A uniform typically worn by an Executive Officer in the USCM. It has shards of light Kevlar to help protect against stabbing weapons and bullets." icon_state = "BO_jumpsuit" worn_state = "BO_jumpsuit" specialty = "executive officer" @@ -266,7 +265,7 @@ flags_atom = NO_SNOW_TYPE /obj/item/clothing/under/marine/officer/formal/servicedress - name = "captain's dress shirt" + name = "commanding officer's dress shirt" desc = "The shirt and tie of a two-piece Navy service dress uniform for high-ranking officers. Wear with style and substance." specialty = "captain's service dress" icon_state = "CO_service" @@ -274,7 +273,7 @@ flags_atom = NO_SNOW_TYPE /obj/item/clothing/under/marine/officer/formal/white - name = "captain's white formal uniform" + name = "Commanding Officer's white formal uniform" desc = "A well-ironed USCM officer uniform in brilliant white with gold accents, intended for parades or hot weather. Wear this with pride." icon_state = "CO_formal_white" worn_state = "CO_formal_white" @@ -282,7 +281,7 @@ flags_atom = NO_SNOW_TYPE /obj/item/clothing/under/marine/officer/formal/black - name = "captain's gray formal uniform" + name = "Commanding Officer's gray formal uniform" desc = "A well-ironed USCM officer uniform in subdued gray with gold accents, intended for more formal or somber events. Wear this with pride." icon_state = "CO_formal_black" worn_state = "CO_formal_black" @@ -528,7 +527,7 @@ min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROT has_sensor = UNIFORM_HAS_SENSORS sensor_faction = FACTION_UPP - suit_restricted = list(/obj/item/clothing/suit/storage/marine/faction/UPP, /obj/item/clothing/suit/gimmick/jason, /obj/item/clothing/suit/storage/snow_suit/soviet, /obj/item/clothing/suit/storage/snow_suit/survivor) + suit_restricted = list(/obj/item/clothing/suit/storage/marine/faction/UPP, /obj/item/clothing/suit/gimmick/jason, /obj/item/clothing/suit/storage/snow_suit/soviet, /obj/item/clothing/suit/storage/snow_suit/survivor, /obj/item/clothing/suit/storage/webbing) flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE /obj/item/clothing/under/marine/veteran/UPP/medic @@ -706,7 +705,7 @@ sensor_faction = FACTION_CLF /obj/item/clothing/under/colonist/ua_civvies - name = "gray utilities" + name = "\improper UA gray utility uniform" desc = "A stylish gray jumpsuit - standard issue for UA civilian support personnel." icon_state = "ua_civvies" worn_state = "ua_civvies" @@ -714,7 +713,7 @@ sensor_faction = FACTION_MARINE /obj/item/clothing/under/colonist/wy_davisone - name = "brown utilities" + name = "\improper UA brown utility uniform" desc = "A stylish brown jumpsuit - standard issue for UA civilian support personnel." icon_state = "wy_davisone" worn_state = "wy_davisone" @@ -738,14 +737,15 @@ desc = "A comfortable white T-shirt and brown jeans." icon_state = "tshirt_w_br" worn_state = "tshirt_w_br" + displays_id = FALSE has_sensor = UNIFORM_HAS_SENSORS sensor_faction = FACTION_MARINE - /obj/item/clothing/under/tshirt/gray_blu name = "gray T-shirt and jeans" desc = "A comfortable gray T-shirt and blue jeans." icon_state = "tshirt_gray_blu" worn_state = "tshirt_gray_blu" + displays_id = FALSE has_sensor = UNIFORM_HAS_SENSORS sensor_faction = FACTION_MARINE @@ -754,6 +754,7 @@ desc = "A comfortable red T-shirt and black jeans." icon_state = "tshirt_r_bla" worn_state = "tshirt_r_bla" + displays_id = FALSE has_sensor = UNIFORM_HAS_SENSORS sensor_faction = FACTION_MARINE @@ -778,12 +779,22 @@ icon_state = "liaison_regular" worn_state = "liaison_regular" +/obj/item/clothing/under/liaison_suit/charcoal + name = "liaison's charcoal suit" + desc = "A stiff, stylish charcoal suit commonly worn by businessmen from the Weyland-Yutani corporation. Expertly crafted to make you look like a prick." + icon_state = "liaison_charcoal" + worn_state = "liaison_charcoal" + /obj/item/clothing/under/liaison_suit/outing name = "liaison's outfit" desc = "A casual outfit consisting of a collared shirt and a vest. Looks like something you might wear on the weekends, or on a visit to a derelict colony." icon_state = "liaison_outing" worn_state = "liaison_outing" +/obj/item/clothing/under/liaison_suit/outing/red + icon_state = "liaison_outing_red" + worn_state = "liaison_outing_red" + /obj/item/clothing/under/liaison_suit/formal name = "liaison's white suit" desc = "A formal, white suit. Looks like something you'd wear to a funeral, a Weyland-Yutani corporate dinner, or both. Stiff as a board, but makes you feel like rolling out of a Rolls-Royce." @@ -796,6 +807,12 @@ icon_state = "liaison_suspenders" worn_state = "liaison_suspenders" +/obj/item/clothing/under/liaison_suit/blazer + name = "liaison's blue blazer" + desc = "A stiff but casual blue blazer. Similar can be found in any Weyland-Yutani office. Only the finest wear for the galaxy's most cunning." + icon_state = "liaison_blue_blazer" + worn_state = "liaison_blue_blazer" + /obj/item/clothing/under/marine/reporter name = "combat correspondent uniform" desc = "A relaxed and robust uniform fit for any potential reporting needs." @@ -822,9 +839,9 @@ desc = "A formal white undersuit." flags_jumpsuit = FALSE -/obj/item/clothing/under/rank/ro_suit - name = "requisition officer suit" - desc = "A nicely-fitting military suit for a requisition officer. It has shards of light Kevlar to help protect against stabbing weapons and bullets." +/obj/item/clothing/under/rank/qm_suit + name = "quartermaster suit" + desc = "A nicely-fitting military suit for a quartermaster. It has shards of light Kevlar to help protect against stabbing weapons and bullets." icon_state = "RO_jumpsuit" worn_state = "RO_jumpsuit" flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE @@ -836,6 +853,38 @@ worn_state = "rdalt" flags_jumpsuit = FALSE +/obj/item/clothing/under/rank/synthetic/frontier + name = "\improper frontier jumpsuit" + desc = "A cargo jumpsuit dressed down for full range of motion and state-of-the-art frontier temperature control. It's the best thing an engineer can wear in the Outer Veil." + icon_state = "synth_cargo_light" + worn_state = "synth_cargo_light" + displays_id = FALSE + +/obj/item/clothing/under/rank/synthetic/utility + name = "\improper UA utility uniform" + desc = "A green-on-green utility uniform, popularly issued to UA contract workers on the frontier." + icon_state = "synth_green_utility" + worn_state = "synth_green_utility" + displays_id = FALSE + +/obj/item/clothing/under/rank/synthetic/utility/yellow + name = "\improper utility uniform" + desc = "A grey utility uniform with yellow suspenders, made for shipside crew." + icon_state = "synth_yellow_utility" + worn_state = "synth_yellow_utility" + +/obj/item/clothing/under/rank/synthetic/utility/red + name = "\improper utility uniform" + desc = "A grey utility uniform with red suspenders and blue jeans, the sign of a veteran laborer, or someone not paid by the hour." + icon_state = "synth_red_utility" + worn_state = "synth_red_utility" + +/obj/item/clothing/under/rank/synthetic/utility/blue + name = "\improper utility uniform" + desc = "A blue utility uniform with teal suspenders and rugged pants." + icon_state = "synth_blue_utility" + worn_state = "synth_blue_utility" + /obj/item/clothing/under/rank/synthetic/councillor name = "\improper USCM Pristine Support Uniform" desc = "A nicely handcrafted uniform made for Synthetic crewmembers." @@ -843,12 +892,44 @@ worn_state = "synth_councillor" displays_id = FALSE +/obj/item/clothing/under/rank/synthetic/flight + name = "tactical flightsuit" + desc = "A flightsuit with plenty of leather straps, pouches, and other essential gear." + icon_state = "pilot_flightsuit_alt" + item_state = "pilot_flightsuit_alt" + worn_state = "pilot_flightsuit_alt" + flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE + flags_atom = NO_NAME_OVERRIDE|NO_SNOW_TYPE + flags_cold_protection = ICE_PLANET_MIN_COLD_PROT + /obj/item/clothing/under/rank/synthetic/old icon_state = "rdalt_s" worn_state = "rdalt_s" /obj/item/clothing/under/rank/synthetic/joe name = "\improper Working Joe Uniform" - desc = "A cheap uniform made for Synthetic labor." + desc = "A cheap uniform made for Synthetic labor. Tomorrow, Together." icon_state = "working_joe" worn_state = "working_joe" + +/obj/item/clothing/under/rank/synthetic/joe/engi + name = "\improper Working Joe Hazardous Uniform" + desc = "A reinforced uniform used for Synthetic labor in hazardous areas. Tomorrow, Together." + icon_state = "working_joe_engi" + worn_state = "working_joe_engi" + flags_inventory = CANTSTRIP + armor_melee = CLOTHING_ARMOR_LOW + armor_energy = CLOTHING_ARMOR_MEDIUMLOW + armor_bomb = CLOTHING_ARMOR_MEDIUMLOW + armor_bio = CLOTHING_ARMOR_MEDIUM + armor_rad = CLOTHING_ARMOR_HIGH + armor_internaldamage = CLOTHING_ARMOR_MEDIUMLOW + flags_jumpsuit = UNIFORM_SLEEVE_ROLLABLE + +/obj/item/clothing/under/rank/synthetic/joe/engi/overalls + name = "\improper Working Joe Hazardous Uniform" + desc = "A reinforced uniform used for Synthetic labor in hazardous areas. Comes with an additional layer for liquid hazards. Tomorrow, Together." + icon_state = "working_joe_overalls" + worn_state = "working_joe_overalls" + armor_bio = CLOTHING_ARMOR_MEDIUMHIGH + unacidable = TRUE diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index b5d2850575aa..42c61404a31a 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -82,8 +82,8 @@ item_state = "r_suit" /obj/item/clothing/under/blackskirt - name = "black skirt" - desc = "A black skirt, very fancy!" + name = "red dress skirt" + desc = "A black cardigan with a red skirt, quite fancy!" icon_state = "blackskirt" flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_ARMS diff --git a/code/modules/clothing/under/ties.dm b/code/modules/clothing/under/ties.dm index 84e053388826..329e2055778e 100644 --- a/code/modules/clothing/under/ties.dm +++ b/code/modules/clothing/under/ties.dm @@ -359,6 +359,11 @@ desc = "A fire-resistant shoulder patch, worn by the men and women of the USS Hanyut, USCM FORECON." icon_state = "forecon_patch" +/obj/item/clothing/accessory/patch/upp + name = "UPP Airborne Reconnaissance patch" + desc = "A fire-resistant shoulder patch, worn by the men and women of the 173rd Airborne Reconnaissance Platoon." + icon_state = "upppatch" + /obj/item/clothing/accessory/poncho name = "USCM Poncho" desc = "The standard USCM poncho has variations for every climate. Custom fitted to be attached to standard USCM armor variants it is comfortable, warming or cooling as needed, and well-fit. A marine couldn't ask for more. Affectionately referred to as a \"woobie\"." @@ -529,7 +534,7 @@ new /obj/item/device/multitool(src) /obj/item/storage/internal/accessory/surg_vest - storage_slots = 13 + storage_slots = 14 can_hold = list( /obj/item/tool/surgery, /obj/item/stack/medical/advanced/bruise_pack, @@ -569,6 +574,7 @@ new /obj/item/tool/surgery/FixOVein(src) new /obj/item/stack/nanopaste(src) new /obj/item/tool/surgery/surgical_line(src) + new /obj/item/tool/surgery/synthgraft(src) /obj/item/clothing/accessory/storage/surg_vest name = "surgical webbing vest" @@ -593,6 +599,12 @@ icon_state = "vest_knives" hold = /obj/item/storage/internal/accessory/knifeharness +/obj/item/clothing/accessory/storage/knifeharness/attack_hand(mob/user, mods) + if(!mods || !mods["alt"] || !length(hold.contents)) + return ..() + + hold.contents[length(contents)].attack_hand(user, mods) + /obj/item/storage/internal/accessory/knifeharness storage_slots = 5 max_storage_space = 5 @@ -603,6 +615,32 @@ /obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, ) + storage_flags = STORAGE_ALLOW_QUICKDRAW|STORAGE_FLAGS_POUCH + + COOLDOWN_DECLARE(draw_cooldown) + +/obj/item/storage/internal/accessory/knifeharness/fill_preset_inventory() + for(var/i = 1 to storage_slots) + new /obj/item/weapon/throwing_knife(src) + +/obj/item/storage/internal/accessory/knifeharness/attack_hand(mob/user, mods) + . = ..() + + if(!COOLDOWN_FINISHED(src, draw_cooldown)) + to_chat(user, SPAN_WARNING("You need to wait before drawing another knife!")) + return FALSE + + if(length(contents)) + contents[length(contents)].attack_hand(user, mods) + COOLDOWN_START(src, draw_cooldown, BAYONET_DRAW_DELAY) + +/obj/item/storage/internal/accessory/knifeharness/_item_insertion(obj/item/inserted_item, prevent_warning = 0) + ..() + playsound(src, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) + +/obj/item/storage/internal/accessory/knifeharness/_item_removal(obj/item/removed_item, atom/new_location) + ..() + playsound(src, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) /obj/item/clothing/accessory/storage/knifeharness/duelling name = "decorated harness" diff --git a/code/modules/cm_aliens/Ovipositor.dm b/code/modules/cm_aliens/Ovipositor.dm index c52666bcebc2..9758497b7009 100644 --- a/code/modules/cm_aliens/Ovipositor.dm +++ b/code/modules/cm_aliens/Ovipositor.dm @@ -7,31 +7,33 @@ unacidable = TRUE var/begin_decay_time = 0 health = 50 - var/decay_ready = 0 - var/decayed = 0 // This is here so later on we can use the ovpositor molt for research. ~BMC777 - var/destroyed = 0 + var/decayed = FALSE // This is here so later on we can use the ovpositor molt for research. ~BMC777 + var/destroyed = FALSE /obj/ovipositor/Initialize(mapload, ...) . = ..() begin_decay_time = world.timeofday + QUEEN_OVIPOSITOR_DECAY_TIME - process_decay() + START_PROCESSING(SSeffects, src) // Process every second -/obj/ovipositor/proc/process_decay() - set background = 1 +/obj/ovipositor/Destroy() + if(!decayed && !destroyed) + STOP_PROCESSING(SSeffects, src) - spawn while (!decayed && !destroyed) - if (world.timeofday > begin_decay_time) - decayed = 1 - do_decay() + return ..() - if (health < 0) - destroyed = 1 - explode() +/obj/ovipositor/process() + if (health < 0) + explode() + return - sleep(10) // Process every second. + if (world.timeofday > begin_decay_time) + do_decay() /obj/ovipositor/proc/do_decay() + decayed = TRUE + STOP_PROCESSING(SSeffects, src) + icon_state = "ovipositor_molted" flick("ovipositor_decay", src) sleep(15) @@ -43,6 +45,9 @@ qdel(src) /obj/ovipositor/proc/explode() + destroyed = TRUE + STOP_PROCESSING(SSeffects, src) + icon_state = "ovipositor_gibbed" flick("ovipositor_explosion", src) sleep(15) diff --git a/code/modules/cm_aliens/XenoStructures.dm b/code/modules/cm_aliens/XenoStructures.dm index d493761da7be..08e451407989 100644 --- a/code/modules/cm_aliens/XenoStructures.dm +++ b/code/modules/cm_aliens/XenoStructures.dm @@ -154,6 +154,8 @@ if (hive) hivenumber = hive set_hive_data(src, hivenumber) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/resin/sticky/Crossed(atom/movable/AM) . = ..() @@ -166,6 +168,14 @@ X.next_move_slowdown = X.next_move_slowdown + slow_amt return . +/obj/effect/alien/resin/sticky/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /obj/effect/alien/resin/spike name = "resin spike" desc = "A small cluster of bone spikes. Ouch." @@ -193,6 +203,8 @@ hivenumber = hive set_hive_data(src, hivenumber) setDir(pick(alldirs)) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/resin/spike/Crossed(atom/movable/AM) . = ..() @@ -206,6 +218,14 @@ H.apply_armoured_damage(damage, penetration = penetration, def_zone = pick(target_limbs)) H.last_damage_data = construction_data +/obj/effect/alien/resin/spike/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + // Praetorian Sticky Resin spit uses this. /obj/effect/alien/resin/sticky/thin name = "thin sticky resin" @@ -324,6 +344,7 @@ /obj/structure/mineral_door/resin name = "resin door" icon = 'icons/mob/xenos/effects.dmi' + icon_state = "resin" mineralType = "resin" hardness = 1.5 health = HEALTH_DOOR_XENO @@ -347,6 +368,9 @@ set_hive_data(src, hivenumber) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) + /obj/structure/mineral_door/resin/flamer_fire_act(dam = BURN_LEVEL_TIER_1) health -= dam healthcheck() @@ -370,11 +394,13 @@ return attack_hand(user) /obj/structure/mineral_door/resin/TryToSwitchState(atom/user) - if(islarva(user)) - var/mob/living/carbon/xenomorph/larva/L = user - if (L.hivenumber == hivenumber) - L.scuttle(src) - return + if(isxeno(user)) + var/mob/living/carbon/xenomorph/xeno_user = user + if (xeno_user.hivenumber != hivenumber && !xeno_user.ally_of_hivenumber(hivenumber)) + return + if(xeno_user.scuttle(src)) + return + return ..() if(iscarbon(user)) var/mob/living/carbon/C = user if (C.ally_of_hivenumber(hivenumber)) @@ -478,8 +504,16 @@ visible_message(SPAN_NOTICE("[src] collapses from the lack of support.")) qdel(src) +/obj/structure/mineral_door/resin/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) /obj/structure/mineral_door/resin/thick name = "thick resin door" + icon_state = "thick resin" health = HEALTH_DOOR_XENO_THICK hardness = 2 mineralType = "thick resin" @@ -508,29 +542,37 @@ hivenumber = hive set_hive_data(src, hivenumber) START_PROCESSING(SSprocessing, src) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) -/obj/effect/alien/resin/acid_pillar/proc/can_target(mob/living/carbon/C, position_to_get = 0) - if(get_dist(src, C) > range) +/obj/effect/alien/resin/acid_pillar/proc/can_target(mob/living/carbon/current_mob, position_to_get = 0) + /// Is it a friendly xenomorph that is on fire + var/burning_friendly = FALSE + + if(get_dist(src, current_mob) > range) return FALSE - var/check_dead = FALSE - if(C.ally_of_hivenumber(hivenumber)) - if(!C.on_fire || !isxeno(C)) + if(current_mob.ally_of_hivenumber(hivenumber)) + if(!isxeno(current_mob)) + return FALSE + if(!current_mob.on_fire) return FALSE - else if(C.lying || C.is_mob_incapacitated(TRUE)) + burning_friendly = TRUE + + else if(current_mob.lying || current_mob.is_mob_incapacitated(TRUE)) return FALSE - if(!check_dead && C.health < 0) + if(!burning_friendly && current_mob.health < 0) return FALSE - if(check_dead && C.stat == DEAD) + if(current_mob.stat == DEAD) return FALSE var/turf/current_turf var/turf/last_turf = loc var/atom/temp_atom = new acid_type() var/current_pos = 1 - for(var/i in getline(src, C)) + for(var/i in getline(src, current_mob)) current_turf = i if(LinkBlocked(temp_atom, last_turf, current_turf)) qdel(temp_atom) @@ -591,6 +633,12 @@ /obj/effect/alien/resin/acid_pillar/get_projectile_hit_boolean(obj/item/projectile/P) return TRUE +/obj/effect/alien/resin/acid_pillar/proc/forsaken_handling() + SIGNAL_HANDLER + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + if(is_ground_level(z)) + qdel(src) + /obj/effect/alien/resin/acid_pillar/strong name = "acid pillar" desc = "A resin pillar that is oozing with acid." diff --git a/code/modules/cm_aliens/structures/construction_node.dm b/code/modules/cm_aliens/structures/construction_node.dm index 03b35e563676..0fdcd5c5c67a 100644 --- a/code/modules/cm_aliens/structures/construction_node.dm +++ b/code/modules/cm_aliens/structures/construction_node.dm @@ -61,4 +61,5 @@ template.owner = src template.build_loc = get_turf(src) template.hive_ref = linked_hive + template.on_template_creation() update_icon() diff --git a/code/modules/cm_aliens/structures/egg.dm b/code/modules/cm_aliens/structures/egg.dm index 855de1a43b78..cf6fa4e3665e 100644 --- a/code/modules/cm_aliens/structures/egg.dm +++ b/code/modules/cm_aliens/structures/egg.dm @@ -25,11 +25,17 @@ set_hive_data(src, hivenumber) update_icon() - INVOKE_ASYNC(src, PROC_REF(Grow)) + addtimer(CALLBACK(src, PROC_REF(Grow)), rand(EGG_MIN_GROWTH_TIME, EGG_MAX_GROWTH_TIME)) /obj/effect/alien/egg/Destroy() . = ..() - QDEL_NULL_LIST(egg_triggers) + for(var/obj/effect/egg_trigger/trigger as anything in egg_triggers) + trigger.linked_egg = null + trigger.linked_eggmorph = null + qdel(trigger) + if(egg_triggers) + egg_triggers.Cut() + egg_triggers = null /obj/effect/alien/egg/ex_act(severity) Burst(TRUE)//any explosion destroys the egg. @@ -40,6 +46,14 @@ . += "Ctrl + Click egg to retrieve child into your empty hand if you can carry it." /obj/effect/alien/egg/attack_alien(mob/living/carbon/xenomorph/M) + if(status == EGG_BURST || status == EGG_DESTROYED) + M.animation_attack_on(src) + M.visible_message(SPAN_XENONOTICE("[M] clears the hatched egg."), \ + SPAN_XENONOTICE("You clear the hatched egg.")) + playsound(src.loc, "alien_resin_break", 25) + qdel(src) + return XENO_NONCOMBAT_ACTION + if(M.hivenumber != hivenumber) M.animation_attack_on(src) M.visible_message(SPAN_XENOWARNING("[M] crushes \the [src]"), @@ -51,13 +65,6 @@ return attack_hand(M) switch(status) - if(EGG_BURST, EGG_DESTROYED) - M.animation_attack_on(src) - M.visible_message(SPAN_XENONOTICE("\The [M] clears the hatched egg."), \ - SPAN_XENONOTICE("You clear the hatched egg.")) - playsound(src.loc, "alien_resin_break", 25) - qdel(src) - return XENO_NONCOMBAT_ACTION if(EGG_GROWING) to_chat(M, SPAN_XENOWARNING("The child is not developed yet.")) return XENO_NO_DELAY_ACTION @@ -80,9 +87,6 @@ return ..() /obj/effect/alien/egg/proc/Grow() - set waitfor = 0 - update_icon() - sleep(rand(EGG_MIN_GROWTH_TIME, EGG_MAX_GROWTH_TIME)) if(status == EGG_GROWING) icon_state = "Egg" status = EGG_GROWN diff --git a/code/modules/cm_aliens/structures/fruit.dm b/code/modules/cm_aliens/structures/fruit.dm index 307c24ced5c2..bb899a6ff25b 100644 --- a/code/modules/cm_aliens/structures/fruit.dm +++ b/code/modules/cm_aliens/structures/fruit.dm @@ -3,6 +3,7 @@ /obj/effect/alien/resin/fruit name = XENO_FRUIT_LESSER desc = "A fruit that can be eaten to immediately recover health." + icon = 'icons/mob/xenos/fruits.dmi' icon_state = "fruit_lesser_immature" density = FALSE opacity = FALSE @@ -26,6 +27,7 @@ var/gardener_sac_color = "#17991B" var/mob/living/carbon/xenomorph/bound_xeno // Drone linked to this fruit + var/obj/effect/alien/weeds/bound_weed var/fruit_type = /obj/item/reagent_container/food/snacks/resin_fruit /obj/effect/alien/resin/fruit/attack_hand(mob/living/user) @@ -49,6 +51,7 @@ return INITIALIZE_HINT_QDEL bound_xeno = X + bound_weed = W hivenumber = X.hivenumber RegisterSignal(W, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) RegisterSignal(X, COMSIG_PARENT_QDELETING, PROC_REF(handle_xeno_qdel)) @@ -63,6 +66,14 @@ SIGNAL_HANDLER qdel(src) +/obj/effect/alien/resin/fruit/proc/unregister_weed_expiration_signal() + if(bound_weed) + UnregisterSignal(bound_weed, COMSIG_PARENT_QDELETING) + +/obj/effect/alien/resin/fruit/proc/register_weed_expiration_signal(obj/effect/alien/weeds/new_weed) + RegisterSignal(new_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) + bound_weed = new_weed + /obj/effect/alien/resin/fruit/proc/handle_xeno_qdel() SIGNAL_HANDLER bound_xeno = null @@ -139,25 +150,33 @@ update_icon() QDEL_IN(src, 3 SECONDS) -/obj/effect/alien/resin/fruit/attack_alien(mob/living/carbon/xenomorph/X) +/obj/effect/alien/resin/fruit/attack_alien(mob/living/carbon/xenomorph/affected_xeno) if(picked) - to_chat(X, SPAN_XENODANGER("This fruit is already being picked!")) + to_chat(affected_xeno, SPAN_XENODANGER("This fruit is already being picked!")) return - if(X.a_intent != INTENT_HARM && (X.can_not_harm(bound_xeno) || X.hivenumber == hivenumber)) - var/cant_consume = prevent_consume(X) + + if(affected_xeno.a_intent != INTENT_HARM && (affected_xeno.can_not_harm(bound_xeno) || affected_xeno.hivenumber == hivenumber)) + var/cant_consume = prevent_consume(affected_xeno) if(cant_consume) return cant_consume + if(mature) - to_chat(X, SPAN_XENOWARNING("You prepare to consume [name].")) - xeno_noncombat_delay(X) - if(!do_after(X, consume_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY)) + to_chat(affected_xeno, SPAN_XENOWARNING("You prepare to consume [name].")) + xeno_noncombat_delay(affected_xeno) + if(!do_after(affected_xeno, consume_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY)) return XENO_NO_DELAY_ACTION - consume_effect(X) + + cant_consume = prevent_consume(affected_xeno) // Check again after the delay incase they have eaten another fruit + if(cant_consume) + to_chat(affected_xeno, SPAN_XENOWARNING("You can no longer consume [name].")) + return cant_consume + consume_effect(affected_xeno) else - to_chat(X, SPAN_XENOWARNING("[name] isn't ripe yet. You need to wait a little longer.")) - if(X.a_intent == INTENT_HARM && isxeno_builder(X) || (!X.can_not_harm(bound_xeno) && X.hivenumber != hivenumber)) - X.animation_attack_on(src) - X.visible_message(SPAN_XENODANGER("[X] removes [name]!"), + to_chat(affected_xeno, SPAN_XENOWARNING("[name] isn't ripe yet. You need to wait a little longer.")) + + if(affected_xeno.a_intent == INTENT_HARM && isxeno_builder(affected_xeno) || (!affected_xeno.can_not_harm(bound_xeno) && affected_xeno.hivenumber != hivenumber)) + affected_xeno.animation_attack_on(src) + affected_xeno.visible_message(SPAN_XENODANGER("[affected_xeno] removes [name]!"), SPAN_XENODANGER("You remove [name]!")) playsound(loc, "alien_resin_break", 25) qdel(src) @@ -365,30 +384,49 @@ bound_xeno = null // Xenos eating fruit -/obj/item/reagent_container/food/snacks/resin_fruit/attack(mob/living/carbon/xenomorph/X, mob/user) +/obj/item/reagent_container/food/snacks/resin_fruit/attack(mob/living/carbon/xenomorph/affected_xeno, mob/user) if(istype(user, /mob/living/carbon/xenomorph)) // Prevents xenos from feeding capped/dead marines fruit - var/mob/living/carbon/xenomorph/Y = user - if(!Y.can_not_harm(X)) - to_chat(Y, SPAN_WARNING("[X] refuses to eat [src].")) + var/mob/living/carbon/xenomorph/feeding_xeno = user + if(!feeding_xeno.can_not_harm(affected_xeno)) + to_chat(feeding_xeno, SPAN_WARNING("[affected_xeno] refuses to eat [src].")) return - if(!istype(X)) + + if(!istype(affected_xeno)) return ..() - if(X.stat == DEAD) + + if(affected_xeno.stat == DEAD) to_chat(user, SPAN_WARNING("That sister is already dead, they won't benefit from the fruit now...")) return - user.affected_message(X, - SPAN_HELPFUL("You start [user == X ? "eating" : "feeding [X]"] [src]."), - SPAN_HELPFUL("[user] starts feeding you [src]."), - SPAN_NOTICE("[user] starts [user == X ? "eating" : "feeding [X]"] [src].")) - if(!do_after(user, consume_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, X, INTERRUPT_MOVED, BUSY_ICON_MEDICAL)) + + var/obj/effect/alien/resin/fruit/current_fruit = new fruit_type(affected_xeno) + var/cant_consume = current_fruit.prevent_consume(affected_xeno) + if(cant_consume) + user.affected_message(affected_xeno, + SPAN_HELPFUL("You fail to [user == affected_xeno ? "eat" : "feed [affected_xeno]"] [current_fruit]."), + SPAN_HELPFUL("[user] fails to feed you [current_fruit].")) + return + user.affected_message(affected_xeno, + SPAN_HELPFUL("You start [user == affected_xeno ? "eating" : "feeding [affected_xeno]"] [current_fruit]."), + SPAN_HELPFUL("[user] starts feeding you [current_fruit]."), + SPAN_NOTICE("[user] starts [user == affected_xeno ? "eating" : "feeding [affected_xeno]"] [current_fruit].")) + + if(!do_after(user, consume_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, affected_xeno, INTERRUPT_MOVED, BUSY_ICON_MEDICAL)) return FALSE - user.affected_message(X, - SPAN_HELPFUL("You [user == X ? "eat" : "fed [X]"] [src]."), - SPAN_HELPFUL("[user] fed you [src]."), - SPAN_NOTICE("[user] [user == X ? "ate" : "fed [X]"] [src].")) - var/obj/effect/alien/resin/fruit/F = new fruit_type(X) - F.mature = TRUE - F.consume_effect(X) + + cant_consume = current_fruit.prevent_consume(affected_xeno) + if(cant_consume) //Check again after the timer incase they ate another fruit + user.affected_message(affected_xeno, + SPAN_HELPFUL("You fail to [user == affected_xeno ? "eat" : "feed [affected_xeno]"] [current_fruit]."), + SPAN_HELPFUL("[user] fails to feed you [current_fruit].")) + return + + user.affected_message(affected_xeno, + SPAN_HELPFUL("You [user == affected_xeno ? "eat" : "fed [affected_xeno]"] [current_fruit]."), + SPAN_HELPFUL("[user] fed you [current_fruit]."), + SPAN_NOTICE("[user] [user == affected_xeno ? "ate" : "fed [affected_xeno]"] [current_fruit].")) + current_fruit.mature = TRUE + current_fruit.consume_effect(affected_xeno) + //Notify the fruit's bound xeno if they exist if(!QDELETED(bound_xeno)) to_chat(bound_xeno, SPAN_XENOWARNING("One of your picked resin fruits has been consumed.")) diff --git a/code/modules/cm_aliens/structures/special/egg_morpher.dm b/code/modules/cm_aliens/structures/special/egg_morpher.dm index 2e79d6ef1d24..1fd154eb354c 100644 --- a/code/modules/cm_aliens/structures/special/egg_morpher.dm +++ b/code/modules/cm_aliens/structures/special/egg_morpher.dm @@ -148,6 +148,7 @@ var/obj/item/item = A if(item.is_objective && item.unacidable) item.forceMove(get_step(loc, pick(alldirs))) + item.mouse_opacity = initial(item.mouse_opacity) QDEL_NULL(captured_mob) update_icon() diff --git a/code/modules/cm_aliens/structures/special/pred_nest.dm b/code/modules/cm_aliens/structures/special/pred_nest.dm index ef15434c81a8..2d84ced8db61 100644 --- a/code/modules/cm_aliens/structures/special/pred_nest.dm +++ b/code/modules/cm_aliens/structures/special/pred_nest.dm @@ -26,6 +26,7 @@ pred_nest = new /obj/structure/bed/nest/structure(loc, hive, src) // Nest cannot be destroyed unless the structure itself is destroyed + /obj/effect/alien/resin/special/nest/Destroy() . = ..() diff --git a/code/modules/cm_aliens/structures/special/pylon_core.dm b/code/modules/cm_aliens/structures/special/pylon_core.dm index b5648f647fd2..068ffeb659eb 100644 --- a/code/modules/cm_aliens/structures/special/pylon_core.dm +++ b/code/modules/cm_aliens/structures/special/pylon_core.dm @@ -12,6 +12,7 @@ block_range = 0 var/cover_range = WEED_RANGE_PYLON var/node_type = /obj/effect/alien/weeds/node/pylon + var/obj/effect/alien/weeds/node/node var/linked_turfs = list() var/damaged = FALSE @@ -25,7 +26,7 @@ /obj/effect/alien/resin/special/pylon/Initialize(mapload, hive_ref) . = ..() - place_node() + node = place_node() for(var/turf/A in range(round(cover_range*PYLON_COVERAGE_MULT), loc)) LAZYADD(A.linked_pylons, src) linked_turfs += A @@ -34,9 +35,8 @@ for(var/turf/A as anything in linked_turfs) LAZYREMOVE(A.linked_pylons, src) - var/obj/effect/alien/weeds/node/pylon/W = locate() in loc - if(W) - qdel(W) + if(node) + QDEL_NULL(node) . = ..() /obj/effect/alien/resin/special/pylon/attack_alien(mob/living/carbon/xenomorph/M) @@ -87,8 +87,78 @@ playsound(loc, "alien_resin_build", 25) /obj/effect/alien/resin/special/pylon/proc/place_node() - var/obj/effect/alien/weeds/node/pylon/W = new node_type(loc, null, null, linked_hive) - W.resin_parent = src + var/obj/effect/alien/weeds/node/pylon/pylon_node = new node_type(loc, null, null, linked_hive) + pylon_node.resin_parent = src + return pylon_node + +/obj/effect/alien/resin/special/pylon/endgame + cover_range = WEED_RANGE_CORE + var/activated = FALSE + +/obj/effect/alien/resin/special/pylon/endgame/Destroy() + if(activated) + activated = FALSE + + if(hijack_delete) + return ..() + + marine_announcement("ALERT.\n\nEnergy build up around communication relay at [get_area(src)] halted.", "[MAIN_AI_SYSTEM] Biological Scanner") + + for(var/hivenumber in GLOB.hive_datum) + var/datum/hive_status/checked_hive = GLOB.hive_datum[hivenumber] + if(!length(checked_hive.totalXenos)) + continue + + if(checked_hive == linked_hive) + xeno_announcement(SPAN_XENOANNOUNCE("We have lost our control of the tall's communication relay at [get_area(src)]."), hivenumber, XENO_GENERAL_ANNOUNCE) + else + xeno_announcement(SPAN_XENOANNOUNCE("Another hive has lost control of the tall's communication relay at [get_area(src)]."), hivenumber, XENO_GENERAL_ANNOUNCE) + + return ..() + +/// Checks if all comms towers are connected and then starts end game content on all pylons if they are +/obj/effect/alien/resin/special/pylon/endgame/proc/comms_relay_connection() + marine_announcement("ALERT.\n\nIrregular build up of energy around communication relays at [get_area(src)].", "[MAIN_AI_SYSTEM] Biological Scanner") + + for(var/hivenumber in GLOB.hive_datum) + var/datum/hive_status/checked_hive = GLOB.hive_datum[hivenumber] + if(!length(checked_hive.totalXenos)) + continue + + if(checked_hive == linked_hive) + xeno_announcement(SPAN_XENOANNOUNCE("We have harnessed the tall's communication relay at [get_area(src)]. Hold it!"), hivenumber, XENO_GENERAL_ANNOUNCE) + else + xeno_announcement(SPAN_XENOANNOUNCE("Another hive has harnessed the tall's communication relay at [get_area(src)].[linked_hive.faction_is_ally(checked_hive.name) ? "" : " Stop them!"]"), hivenumber, XENO_GENERAL_ANNOUNCE) + + activated = TRUE + addtimer(CALLBACK(src, PROC_REF(give_larva)), XENO_PYLON_ACTIVATION_COOLDOWN, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_LOOP|TIMER_DELETE_ME) + +#define ENDGAME_LARVA_CAP_MULTIPLIER 0.4 +#define LARVA_ADDITION_MULTIPLIER 0.10 + +/// Looped proc via timer to give larva after time +/obj/effect/alien/resin/special/pylon/endgame/proc/give_larva() + if(!activated) + return + + if(!linked_hive.hive_location || !linked_hive.living_xeno_queen) + return + + var/list/hive_xenos = linked_hive.totalXenos + + for(var/mob/living/carbon/xenomorph/xeno in hive_xenos) + if(!xeno.counts_for_slots) + hive_xenos -= xeno + + if(length(hive_xenos) > (length(GLOB.alive_human_list) * ENDGAME_LARVA_CAP_MULTIPLIER)) + return + + linked_hive.partial_larva += length(hive_xenos) * LARVA_ADDITION_MULTIPLIER + linked_hive.convert_partial_larva_to_full_larva() + linked_hive.hive_ui.update_burrowed_larva() + +#undef ENDGAME_LARVA_CAP_MULTIPLIER +#undef LARVA_ADDITION_MULTIPLIER //Hive Core - Generates strong weeds, supports other buildings /obj/effect/alien/resin/special/pylon/core @@ -108,6 +178,7 @@ var/last_healed = 0 var/last_attempt = 0 // logs time of last attempt to prevent spam. if you want to destroy it, you must commit. var/last_larva_time = 0 + var/last_larva_queue_time = 0 var/last_surge_time = 0 var/spawn_cooldown = 30 SECONDS var/surge_cooldown = 90 SECONDS @@ -135,25 +206,40 @@ // Handle spawning larva if core is connected to a hive if(linked_hive) - for(var/mob/living/carbon/xenomorph/larva/L in range(2, src)) - if(!L.ckey && L.burrowable && !QDELETED(L)) - visible_message(SPAN_XENODANGER("[L] quickly burrows into \the [src].")) - linked_hive.stored_larva++ - linked_hive.hive_ui.update_burrowed_larva() - qdel(L) - - if((last_larva_time + spawn_cooldown) < world.time && can_spawn_larva()) // every minute + for(var/mob/living/carbon/xenomorph/larva/worm in range(2, src)) + if((!worm.ckey || worm.stat == DEAD) && worm.burrowable && (worm.hivenumber == linked_hive.hivenumber) && !QDELETED(worm)) + visible_message(SPAN_XENODANGER("[worm] quickly burrows into \the [src].")) + if(!worm.banished) + // Goob job bringing her back home, but no doubling please + linked_hive.stored_larva++ + linked_hive.hive_ui.update_burrowed_larva() + qdel(worm) + + var/spawning_larva = can_spawn_larva() && (last_larva_time + spawn_cooldown) < world.time + if(spawning_larva) last_larva_time = world.time - var/list/players_with_xeno_pref = get_alien_candidates() - if(players_with_xeno_pref && players_with_xeno_pref.len && can_spawn_larva()) - spawn_burrowed_larva(pick(players_with_xeno_pref)) + if(spawning_larva || (last_larva_queue_time + spawn_cooldown * 4) < world.time) + last_larva_queue_time = world.time + var/list/players_with_xeno_pref = get_alien_candidates(linked_hive) + if(players_with_xeno_pref && players_with_xeno_pref.len) + if(spawning_larva && spawn_burrowed_larva(players_with_xeno_pref[1])) + // We were in spawning_larva mode and successfully spawned someone + message_alien_candidates(players_with_xeno_pref, dequeued = 1) + else + // Just time to update everyone their queue status (or the spawn failed) + message_alien_candidates(players_with_xeno_pref, dequeued = 0) if(linked_hive.hijack_burrowed_surge && (last_surge_time + surge_cooldown) < world.time) last_surge_time = world.time linked_hive.stored_larva++ + linked_hive.hijack_burrowed_left-- announce_dchat("The hive has gained another burrowed larva! Use the Join As Xeno verb to take it.", src) if(surge_cooldown > 30 SECONDS) //mostly for sanity purposes surge_cooldown = surge_cooldown - surge_incremental_reduction //ramps up over time + if(linked_hive.hijack_burrowed_left < 1) + linked_hive.hijack_burrowed_surge = FALSE + xeno_message(SPAN_XENOANNOUNCE("The hive's power wanes. You will no longer gain pooled larva over time."), 3, linked_hive.hivenumber) + // Hive core can repair itself over time if(health < maxhealth && last_healed <= world.time) @@ -174,7 +260,7 @@ new_xeno.visible_message(SPAN_XENODANGER("A larva suddenly emerges from [src]!"), SPAN_XENODANGER("You emerge from [src] and awaken from your slumber. For the Hive!")) - msg_admin_niche("[key_name(new_xeno)] emerged from \a [src]. (JMP)") + msg_admin_niche("[key_name(new_xeno)] emerged from \a [src]. [ADMIN_JMP(src)]") playsound(new_xeno, 'sound/effects/xeno_newlarva.ogg', 50, 1) if(!SSticker.mode.transfer_xeno(xeno_candidate, new_xeno)) qdel(new_xeno) @@ -311,5 +397,22 @@ // Tell admins that this condition is reached so they know what has happened if it fails somehow return +/obj/effect/alien/resin/special/pylon/core/proc/spawn_lesser_drone(mob/xeno_candidate) + if(!linked_hive.can_spawn_as_lesser_drone(xeno_candidate)) + return FALSE + + var/mob/living/carbon/xenomorph/lesser_drone/new_drone = new /mob/living/carbon/xenomorph/lesser_drone(loc, null, linked_hive.hivenumber) + xeno_candidate.mind.transfer_to(new_drone, TRUE) + new_drone.visible_message(SPAN_XENODANGER("A lesser drone emerges out of [src]!"), SPAN_XENODANGER("You emerge out of [src] and awaken from your slumber. For the Hive!")) + playsound(new_drone, 'sound/effects/xeno_newlarva.ogg', 25, TRUE) + new_drone.generate_name() + + return TRUE + +/obj/effect/alien/resin/special/pylon/core/attack_ghost(mob/dead/observer/user) + . = ..() + if(SSticker.mode.check_xeno_late_join(user)) + SSticker.mode.attempt_to_join_as_lesser_drone(user) + #undef PYLON_REPAIR_TIME #undef PYLON_WEEDS_REGROWTH_TIME diff --git a/code/modules/cm_aliens/structures/special_structure.dm b/code/modules/cm_aliens/structures/special_structure.dm index 339bec600c4c..69bdcc2438ac 100644 --- a/code/modules/cm_aliens/structures/special_structure.dm +++ b/code/modules/cm_aliens/structures/special_structure.dm @@ -24,6 +24,7 @@ /obj/effect/alien/resin/special name = "Special Resin Structure" icon = 'icons/mob/xenos/structures64x64.dmi' + icon_state = "" pixel_x = -16 pixel_y = -16 health = 200 @@ -38,6 +39,9 @@ plane = FLOOR_PLANE + /// Tells the structure if they are being deleted because of hijack + var/hijack_delete = FALSE + /obj/effect/alien/resin/special/Initialize(mapload, hive_ref) . = ..() maxhealth = health diff --git a/code/modules/cm_aliens/structures/trap.dm b/code/modules/cm_aliens/structures/trap.dm index 1b3d4d414d48..5e1c51538ce6 100644 --- a/code/modules/cm_aliens/structures/trap.dm +++ b/code/modules/cm_aliens/structures/trap.dm @@ -29,6 +29,8 @@ cause_data = create_cause_data("resin trap", X) set_hive_data(src, hivenumber) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/resin/trap/Initialize() . = ..() @@ -53,6 +55,14 @@ if(RESIN_TRAP_ACID1, RESIN_TRAP_ACID2, RESIN_TRAP_ACID3) . += "It's filled with pressurised acid." +/obj/effect/alien/resin/trap/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /obj/effect/alien/resin/trap/proc/facehugger_die() var/obj/item/clothing/mask/facehugger/FH = new (loc) FH.die() @@ -159,6 +169,7 @@ trap_type_name = "hugger" var/obj/item/clothing/mask/facehugger/FH = new (loc) FH.hivenumber = hivenumber + set_hive_data(FH, hivenumber) set_state() visible_message(SPAN_WARNING("[FH] gets out of [src]!")) sleep(15) diff --git a/code/modules/cm_aliens/structures/tunnel.dm b/code/modules/cm_aliens/structures/tunnel.dm index f03e81ccc408..0e1008cfbf12 100644 --- a/code/modules/cm_aliens/structures/tunnel.dm +++ b/code/modules/cm_aliens/structures/tunnel.dm @@ -2,6 +2,8 @@ * Tunnels */ +#define TUNNEL_COLLAPSING_TIME (60 SECONDS) + /obj/structure/tunnel name = "tunnel" desc = "A tunnel entrance. Looks like it was dug by some kind of clawed beast." @@ -83,6 +85,25 @@ /obj/structure/tunnel/attackby(obj/item/W as obj, mob/user as mob) if(!isxeno(user)) + if(istype(W, /obj/item/tool/shovel)) + var/obj/item/tool/shovel/destroying_shovel = W + + if(destroying_shovel.folded) + return + + playsound(user.loc, 'sound/effects/thud.ogg', 40, 1, 6) + + user.visible_message(SPAN_NOTICE("[user] starts to collapse [src]!"), SPAN_NOTICE("You start collapsing [src]!")) + + if(user.action_busy || !do_after(user, TUNNEL_COLLAPSING_TIME * ((100 - destroying_shovel.shovelspeed) * 0.01), INTERRUPT_ALL, BUSY_ICON_BUILD)) + return + + playsound(loc, 'sound/effects/tunnel_collapse.ogg', 50) + + visible_message(SPAN_NOTICE("[src] collapses in on itself.")) + + qdel(src) + return ..() return attack_alien(user) @@ -233,3 +254,12 @@ else to_chat(M, SPAN_WARNING("\The [src] ended unexpectedly, so you return back up.")) return XENO_NO_DELAY_ACTION + +/obj/structure/tunnel/maint_tunnel + name = "\improper Maintenance Hatch" + desc = "An entrance to a maintenance tunnel. You can see bits of slime and resin within. Pieces of debris keep you from getting a closer look." + icon = 'icons/obj/structures/structures.dmi' + icon_state = "hatchclosed" + +/obj/structure/tunnel/maint_tunnel/no_xeno_desc + desc = "An entrance to a maintenance tunnel. Pieces of debris keep you from getting a closer look." diff --git a/code/modules/cm_aliens/weeds.dm b/code/modules/cm_aliens/weeds.dm index 53a76e773e51..01140beae304 100644 --- a/code/modules/cm_aliens/weeds.dm +++ b/code/modules/cm_aliens/weeds.dm @@ -32,8 +32,9 @@ // Which node is responsible for keeping this weed patch alive? var/obj/effect/alien/weeds/node/parent = null -/obj/effect/alien/weeds/Initialize(mapload, obj/effect/alien/weeds/node/node, use_node_strength=TRUE) +/obj/effect/alien/weeds/Initialize(mapload, obj/effect/alien/weeds/node/node, use_node_strength=TRUE, do_spread=TRUE) . = ..() + if(node) linked_hive = node.linked_hive if(use_node_strength) @@ -54,7 +55,7 @@ linked_hive = GLOB.hive_datum[hivenumber] set_hive_data(src, hivenumber) - if(spread_on_semiweedable) + if(spread_on_semiweedable && weed_strength < WEED_LEVEL_HIVE) if(color) var/list/RGB = ReadRGB(color) RGB[1] = Clamp(RGB[1] + 35, 0, 255) @@ -69,18 +70,21 @@ if(node && node.loc) if(get_dist(node, src) >= node.node_range) SEND_SIGNAL(parent, COMSIG_WEEDNODE_GROWTH_COMPLETE) - else if(!hibernate) + else if(!hibernate && do_spread) addtimer(CALLBACK(src, PROC_REF(weed_expand)), WEED_BASE_GROW_SPEED / max(weed_strength, 1)) - var/turf/T = get_turf(src) - if(T) - T.weeds = src - weeded_turf = T + var/turf/turf = get_turf(src) + if(turf) + turf.weeds = src + weeded_turf = turf + SEND_SIGNAL(turf, COMSIG_WEEDNODE_GROWTH) // Currently for weed_food wakeup RegisterSignal(src, list( COMSIG_ATOM_TURF_CHANGE, COMSIG_MOVABLE_TURF_ENTERED ), PROC_REF(set_turf_weeded)) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/weeds/proc/set_turf_weeded(datum/source, turf/T) SIGNAL_HANDLER @@ -89,6 +93,15 @@ T.weeds = src +/obj/effect/alien/weeds/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + linked_hive = GLOB.hive_datum[XENO_HIVE_FORSAKEN] + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /obj/effect/alien/weeds/initialize_pass_flags(datum/pass_flags_container/PF) . = ..() if (PF) @@ -210,6 +223,8 @@ if(!spread_on_semiweedable && is_weedable < FULLY_WEEDABLE) continue + var/obj/effect/alien/resin/fruit/old_fruit + var/obj/effect/alien/weeds/W = locate() in T if(W) if(W.indestructible) @@ -218,19 +233,30 @@ continue else if (W.linked_hive == node.linked_hive && W.weed_strength >= node.weed_strength) continue - qdel(W) - if(istype(T, /turf/closed/wall/resin)) - continue + old_fruit = locate() in T - if(istype(T, /turf/closed/wall) && T.density) - weeds.Add(new /obj/effect/alien/weeds/weedwall(T, node)) - continue + if(old_fruit) + old_fruit.unregister_weed_expiration_signal() + + qdel(W) + + if(!istype(T, /turf/closed/wall/resin) && T.density) + if(istype(T, /turf/closed/wall)) + weeds.Add(new /obj/effect/alien/weeds/weedwall(T, node)) + continue + else if( istype(T, /turf/closed)) + weeds.Add(new /obj/effect/alien/weeds(T, node, TRUE, FALSE)) + continue if(!weed_expand_objects(T, dirn)) continue - weeds.Add(new /obj/effect/alien/weeds(T, node)) + var/obj/effect/alien/weeds/new_weed = new(T, node) + weeds += new_weed + + if(old_fruit) + old_fruit.register_weed_expiration_signal(new_weed) on_weed_expand(src, weeds) if(parent) @@ -327,33 +353,32 @@ return take_damage(severity * WEED_EXPLOSION_DAMAGEMULT) -/obj/effect/alien/weeds/attack_alien(mob/living/carbon/xenomorph/X) - if(!indestructible && !HIVE_ALLIED_TO_HIVE(X.hivenumber, hivenumber)) - X.animation_attack_on(src) - X.visible_message(SPAN_DANGER("\The [X] slashes [src]!"), \ +/obj/effect/alien/weeds/attack_alien(mob/living/carbon/xenomorph/attacking_xeno) + if(!indestructible && !HIVE_ALLIED_TO_HIVE(attacking_xeno.hivenumber, hivenumber)) + attacking_xeno.animation_attack_on(src) + attacking_xeno.visible_message(SPAN_DANGER("\The [attacking_xeno] slashes [src]!"), \ SPAN_DANGER("You slash [src]!"), null, 5) playsound(loc, "alien_resin_break", 25) - take_damage(X.melee_damage_lower*WEED_XENO_DAMAGEMULT) + take_damage(attacking_xeno.melee_damage_lower*WEED_XENO_DAMAGEMULT) return XENO_ATTACK_ACTION - -/obj/effect/alien/weeds/attackby(obj/item/W, mob/living/user) +/obj/effect/alien/weeds/attackby(obj/item/attacking_item, mob/living/user) if(indestructible) return FALSE - if(QDELETED(W) || QDELETED(user) || (W.flags_item & NOBLUDGEON)) + if(QDELETED(attacking_item) || QDELETED(user) || (attacking_item.flags_item & NOBLUDGEON)) return 0 if(istype(src, /obj/effect/alien/weeds/node)) //The pain is real - to_chat(user, SPAN_WARNING("You hit \the [src] with \the [W].")) + to_chat(user, SPAN_WARNING("You hit \the [src] with \the [attacking_item].")) else - to_chat(user, SPAN_WARNING("You cut \the [src] away with \the [W].")) + to_chat(user, SPAN_WARNING("You cut \the [src] away with \the [attacking_item].")) - var/damage = W.force / 3 + var/damage = attacking_item.force / 3 playsound(loc, "alien_resin_break", 25) - if(iswelder(W)) - var/obj/item/tool/weldingtool/WT = W + if(iswelder(attacking_item)) + var/obj/item/tool/weldingtool/WT = attacking_item if(WT.remove_fuel(2)) damage = WEED_HEALTH_STANDARD playsound(loc, 'sound/items/Welder.ogg', 25, 1) @@ -396,6 +421,23 @@ var/list/wall_connections = list("0", "0", "0", "0") hibernate = TRUE +/obj/effect/alien/weeds/weedwall/attackby(obj/item/attacking_item, mob/living/user) + . = ..() + if(isxeno(user) && istype(attacking_item, /obj/item/grab)) + var/obj/item/grab/attacking_grab = attacking_item + var/mob/living/carbon/xenomorph/user_as_xenomorph = user + user_as_xenomorph.do_nesting_host(attacking_grab.grabbed_thing, src) + +/obj/effect/alien/weeds/weedwall/MouseDrop_T(mob/current_mob, mob/user) + . = ..() + + if(!ismob(current_mob)) + return + + if(isxeno(user) && istype(user.get_active_hand(), /obj/item/grab)) + var/mob/living/carbon/xenomorph/user_as_xenomorph = user + user_as_xenomorph.do_nesting_host(current_mob, src) + /obj/effect/alien/weeds/weedwall/update_icon() if(istype(loc, /turf/closed/wall)) var/turf/closed/wall/W = loc @@ -466,20 +508,20 @@ overlay_node = TRUE overlays += staticnode -/obj/effect/alien/weeds/node/Initialize(mapload, obj/effect/alien/weeds/node/node, mob/living/carbon/xenomorph/X, datum/hive_status/hive) +/obj/effect/alien/weeds/node/Initialize(mapload, obj/effect/alien/weeds/node/node, mob/living/carbon/xenomorph/xeno, datum/hive_status/hive) if (istype(hive)) linked_hive = hive - else if (istype(X) && X.hive) - linked_hive = X.hive + else if (istype(xeno) && xeno.hive) + linked_hive = xeno.hive else linked_hive = GLOB.hive_datum[hivenumber] - for(var/obj/effect/alien/weeds/W in loc) - if(W != src) - if(W.weed_strength > WEED_LEVEL_HIVE) + for(var/obj/effect/alien/weeds/weed in loc) + if(weed != src) + if(weed.weed_strength > WEED_LEVEL_HIVE) qdel(src) return - qdel(W) //replaces the previous weed + qdel(weed) //replaces the previous weed break . = ..(mapload, src) @@ -487,15 +529,15 @@ if(!staticnode) staticnode = image('icons/mob/xenos/weeds.dmi', "weednode", ABOVE_OBJ_LAYER) - var/obj/effect/alien/resin/trap/TR = locate() in loc - if(TR) - RegisterSignal(TR, COMSIG_PARENT_PREQDELETED, PROC_REF(trap_destroyed)) + var/obj/effect/alien/resin/trap/trap = locate() in loc + if(trap) + RegisterSignal(trap, COMSIG_PARENT_PREQDELETED, PROC_REF(trap_destroyed)) overlay_node = FALSE overlays -= staticnode - if(X) - add_hiddenprint(X) - weed_strength = X.weed_level + if(xeno) + add_hiddenprint(xeno) + weed_strength = max(weed_strength, xeno.weed_level) if (weed_strength < WEED_LEVEL_STANDARD) weed_strength = WEED_LEVEL_STANDARD @@ -546,9 +588,13 @@ weed_strength = WEED_LEVEL_HIVE node_range = WEED_RANGE_PYLON overlay_node = FALSE + spread_on_semiweedable = TRUE var/obj/effect/alien/resin/special/resin_parent /obj/effect/alien/weeds/node/pylon/proc/set_parent_damaged() + if(!resin_parent) + return + var/obj/effect/alien/resin/special/pylon/parent_pylon = resin_parent parent_pylon.damaged = TRUE @@ -574,7 +620,13 @@ /obj/effect/alien/weeds/node/pylon/acid_spray_act() return +/obj/effect/alien/weeds/node/pylon/cluster + spread_on_semiweedable = FALSE + /obj/effect/alien/weeds/node/pylon/cluster/set_parent_damaged() + if(!resin_parent) + return + var/obj/effect/alien/resin/special/cluster/parent_cluster = resin_parent parent_cluster.damaged = TRUE diff --git a/code/modules/cm_marines/Donor_Items.dm b/code/modules/cm_marines/Donator_Items.dm similarity index 76% rename from code/modules/cm_marines/Donor_Items.dm rename to code/modules/cm_marines/Donator_Items.dm index aa3cbfd1e7a6..58b8d448a92f 100644 --- a/code/modules/cm_marines/Donor_Items.dm +++ b/code/modules/cm_marines/Donator_Items.dm @@ -1,6 +1,65 @@ // SS13 DONATOR CUSTOM ITEM STORAGE ZONE OF MAGICAL HAPPINESS APOPHIS - LAST UPDATE - 14JUN2016 -// EXO-SUITS/ARMORS COSMETICS //////////////////////////////////////////////// +//#######################################################\\ +//###################### TEMPLATES ######################\\ +//#######################################################\\ + +//HEAD TEMPLATE (for Helmets/Hats/Berets) ONLY TAKE NAME, DESC, ICON_STATE, AND ITEM_STATE. Make a copy of those, and put the ckey of the person at the end after fluff +/obj/item/clothing/head/helmet/marine/fluff + name = "ITEM NAME" + desc = "ITEM DESCRIPTION. DONOR ITEM" //Add UNIQUE if Unique + icon_state = null + item_state = null + //DON'T GRAB STUFF BETWEEN THIS LINE + icon = 'icons/obj/items/clothing/hats.dmi' + icon_override = 'icons/mob/humans/onmob/head_0.dmi' + flags_inventory = BLOCKSHARPOBJ + flags_inv_hide = HIDEEARS + flags_atom = NO_NAME_OVERRIDE + min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROT + flags_marine_helmet = NO_FLAGS + +/obj/item/clothing/head/helmet/marine/fluff/verb/toggle_squad_markings() + set src in usr + if(!ishuman(usr)) return + + if(!usr.canmove || usr.stat || usr.is_mob_restrained() || !usr.loc || !isturf(usr.loc)) + to_chat(usr, SPAN_WARNING("Not right now!")) + return + + to_chat(usr, SPAN_NOTICE("You [flags_marine_helmet & HELMET_SQUAD_OVERLAY? "hide" : "show"] the squad markings.")) + flags_marine_helmet ^= HELMET_SQUAD_OVERLAY + usr.update_inv_head() + +/obj/item/clothing/head/helmet/marine/fluff/verb/toggle_garb_overlay() + set src in usr + if(!ishuman(usr)) return + + if(!usr.canmove || usr.stat || usr.is_mob_restrained() || !usr.loc || !isturf(usr.loc)) + to_chat(usr, SPAN_WARNING("Not right now!")) + return + + to_chat(usr, SPAN_NOTICE("You [flags_marine_helmet & HELMET_GARB_OVERLAY? "hide" : "show"] the helmet garb.")) + flags_marine_helmet ^= HELMET_GARB_OVERLAY + update_icon() + + //AND THIS LINE +//END HEAD TEMPLATE + +//MASK TEMPLATE (for masks) ONLY TAKE NAME, DESC, ICON_STATE, ITEM_STATE, AND ITEM_COLOR. Make a copy of those, and put the ckey of the person at the end after fluff +/obj/item/clothing/mask/fluff + name = "ITEM NAME" + desc = "ITEM DESCRIPTION. DONOR ITEM" //Add UNIQUE if Unique + icon_state = null + item_state = null + //DON'T GRAB STUFF BETWEEN THIS LINE + flags_inventory = ALLOWREBREATH + flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE + flags_cold_protection = BODY_FLAG_HEAD + min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROT + //AND THIS LINE + +//END MASK TEMPLATE //SUIT TEMPLATE (for armor/exosuit) ONLY TAKE NAME, DESC, ICON_STATE, AND ITEM_STATE. Make a copy of those, and put the ckey of the person at the end after fluff /obj/item/clothing/suit/storage/marine/fluff @@ -43,13 +102,84 @@ //AND THIS LINE //END SUIT TEMPLATE -/obj/item/clothing/suit/storage/marine/fluff/santa +//FEET TEMPLATE (for shoes) ONLY TAKE NAME, DESC, ICON_STATE, ITEM_STATE, AND ITEM_COLOR. Make a copy of those, and put the ckey of the person at the end after fluff +/obj/item/clothing/shoes/marine/fluff + name = "ITEM NAME" + desc = "ITEM DESCRIPTION. DONOR ITEM" //Add UNIQUE if Unique + icon_state = null + item_state = null +//END FEET TEMPLATE + +/obj/item/storage/backpack/marine/fluff + xeno_types = null + +/obj/item/clothing/gloves/marine/fluff //MARINE GLOVES TEMPLATE + name = "ITEM NAME" + desc = "ITEM DESCRIPTION. DONOR ITEM" //Add UNIQUE if Unique + icon_state = null + item_state = null + +/obj/item/clothing/glasses/fluff + flags_inventory = COVEREYES + + +//#######################################################\\ +//#################### GENERIC SET(S) ###################\\ +//#######################################################\\ + +/obj/item/clothing/head/helmet/marine/fluff/standard_helmet //GENERIC DONOR + name = "Omega Team Helmet" + desc = "Helmet worn by Omega Team. DONOR ITEM" + icon_state = "standard_helmet" + item_state = "standard_helmet" + flags_inventory = BLOCKSHARPOBJ + flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR + +/obj/item/clothing/suit/storage/marine/fluff/standard_armor //GENERIC DONOR + name = "Omega Team Armor" + desc = "Armor worn by the Omega Team. DONOR ITEM" + icon_state = "standard_armor" + item_state = "standard_armor" + +/obj/item/clothing/under/marine/fluff/standard_jumpsuit //GENERIC DONOR + name = "Omega Team Uniform" + desc = "Uniform worn by Omega Team. DONOR ITEM" + icon_state = "standard_jumpsuit" + worn_state = "standard_jumpsuit" + flags_jumpsuit = FALSE + +/obj/item/clothing/under/marine/fluff/turtleneck //GENERIC DONOR + name = "Black Ops Turtleneck" + desc = "A $900 black turtleneck woven from only the purest Azerbaijani cashmere wool. DONOR ITEM" + icon_state = "syndicate" + item_state = "bl_suit" + worn_state = "syndicate" + flags_jumpsuit = FALSE + + +/obj/item/clothing/mask/fluff/balaclava //GENERIC DONOR + name = "Balaclava" + desc = "A black Balaclava used for hiding your face. DISCLAIMER: May not actually hide your face... DONOR ITEM" + item_state = "balaclava" + icon_state = "balaclava" + flags_inventory = COVERMOUTH|ALLOWREBREATH + flags_inv_hide = HIDEEARS|HIDEFACE|HIDEALLHAIR + +/obj/item/clothing/glasses/fluff/eyepatch //GENERIC DONOR + name = "An Eyepatch" + desc = "Badass +10. Donor Item" + icon_state = "eyepatch" + item_state = "eyepatch" + +// EXO-SUITS/ARMORS COSMETICS //////////////////////////////////////////////// + +/obj/item/clothing/suit/storage/marine/fluff/santa //CKEY=tophatpenguin name = "Santa's suit" desc = "Festive! DONOR ITEM" icon_state = "santa" item_state = "santa" -/obj/item/clothing/suit/storage/marine/fluff/armorammo +/obj/item/clothing/suit/storage/marine/fluff/commandercookies //CKEY=commandercookies name = "marine armor w/ ammo" desc = "A marine combat vest with ammunition on it. DONOR ITEM" icon_state = "bulletproofammo" @@ -61,118 +191,118 @@ icon_state = "cia" item_state = "cia" -/obj/item/clothing/suit/storage/marine/fluff/obey +/obj/item/clothing/suit/storage/marine/fluff/obey //CKEY=obeystylez (UNIQUE) name = "Black Ops Ablative Armor Vest" desc = "Some fancy looking armor. DONOR ITEM" icon_state = "armor_reflec" item_state = "armor_reflec" -/obj/item/clothing/suit/storage/marine/fluff/sas5 +/obj/item/clothing/suit/storage/marine/fluff/sas_juggernaut //CKEY=sasoperative (UNIQUE) name = "Juggernaut Armor" desc = "Some fancy looking armor. DONOR ITEM" icon_state = "rig-syndi" item_state = "syndie_hardsuit" -/obj/item/clothing/suit/storage/marine/fluff/penguin +/obj/item/clothing/suit/storage/marine/fluff/penguin //CKEY=tophatpenguin name = "Trenchcoat" desc = "An 18th-century trenchcoat. Someone who wears this means serious business. DONOR ITEM" icon_state = "detective" item_state = "det_suit" blood_overlay_type = "coat" -/obj/item/clothing/suit/storage/marine/fluff/wright +/obj/item/clothing/suit/storage/marine/fluff/wright //CKEY=wrightthewrong name = "Swat Armor" desc = "Some fancy looking armor. DONOR ITEM" icon_state = "deathsquad" item_state = "swat_suit" -/obj/item/clothing/suit/storage/marine/fluff/tyran +/obj/item/clothing/suit/storage/marine/fluff/tyran //CKEY=tyran68 name = "Swat Armor" desc = "Some fancy looking armor. DONOR ITEM" icon_state = "deathsquad" item_state = "swat_suit" -/obj/item/clothing/suit/storage/marine/fluff/tristan +/obj/item/clothing/suit/storage/marine/fluff/tristan //CKEY=tristan63 name = "Sciency Teleport Armor" desc = "Some fancy looking armor, with lots of lights and buttons. DONOR ITEM" icon_state = "reactive" item_state = "reactive" blood_overlay_type = "armor" -/obj/item/clothing/suit/storage/marine/fluff/SAS +/obj/item/clothing/suit/storage/marine/fluff/sas_legion //CKEY=sasoperative (UNIQUE) name = "Legion Armor" desc = "This armor was custom-made to resemble the small growing Legion within the galaxy started by one man slowly making its way to becoming a larger Corporation. DONOR ITEM." item_state = "ncrjacket" icon_state = "ncrjacket" -/obj/item/clothing/suit/storage/marine/fluff/mycroft +/obj/item/clothing/suit/storage/marine/fluff/feodrich //CKEY=feodrich (UNIQUE) name = "Doom Armor" desc = "A uniform, of a famous Earth warrior... Donor Item" item_state = "doom_armor" icon_state = "doom_armor" -/obj/item/clothing/suit/storage/marine/fluff/LEO +/obj/item/clothing/suit/storage/marine/fluff/totalanarchy //CKEY=totalanarchy name = "Leo's Armor" desc = "Used Mercenary armor. DONOR ITEM." item_state = "merc_armor" icon_state = "merc_armor" -/obj/item/clothing/suit/storage/marine/fluff/Sado +/obj/item/clothing/suit/storage/marine/fluff/sadokist2 //CKEY=sadokist name = "Heavy Security Hardsuit" desc = "Heavily armored security hardsuit. DONOR ITEM" icon_state = "rig-secTG" item_state = "rig-secTG" -/obj/item/clothing/suit/storage/marine/fluff/Vintage +/obj/item/clothing/suit/storage/marine/fluff/vintage //CKEY=vintagepalmer name = "Vintage armor with ripples." desc = "A vintage DONOR ITEM" icon_state = "bulletproof" item_state = "bulletproof" -/obj/item/clothing/suit/storage/marine/fluff/john56 +/obj/item/clothing/suit/storage/marine/fluff/john56 //CKEY=johnkilla56 name = "A red trenchcoat" desc = "A special trenchcoat made famous for instilling fear into greytide everywhere. DONOR ITEM" icon_state = "hos" item_state = "hos" blood_overlay_type = "coat" -/obj/item/clothing/suit/storage/marine/fluff/biolock +/obj/item/clothing/suit/storage/marine/fluff/biolock //CKEY=biolock name = "Medic Armor" desc = "Medical armor, designed to protect medics from things that hurt medics. DONOR ITEM." item_state = "medarmor" icon_state = "medarmor" -/obj/item/clothing/suit/storage/marine/fluff/sas3 //UNIQUE +/obj/item/clothing/suit/storage/marine/fluff/sas_elite //CKEY=sasoperative (UNIQUE) name = "Elite Combat Armor" desc = "A combat armor with blood stains on it from previous battles. UNIQUE DONOR ITEM" icon_state = "hecuarmor_u" item_state = "hecuarmor_u" -/obj/item/clothing/suit/storage/marine/fluff/limo +/obj/item/clothing/suit/storage/marine/fluff/limo //CKEY=limodish (UNIQUE) name = "Blood-Red Hardsuit" desc = "Looks like a hardsuit. Unique DONOR ITEM" icon_state = "syndicate" item_state = "syndicate" -/obj/item/clothing/suit/storage/marine/fluff/Zynax +/obj/item/clothing/suit/storage/marine/fluff/Zynax //CKEY=zynax name = "Gorka Vest" desc = "Russian Camo Vest. Unique DONOR ITEM" icon_state = "gorkavest_u" item_state = "gorkavest_u" -/obj/item/clothing/suit/storage/marine/fluff/BWO +/obj/item/clothing/suit/storage/marine/fluff/bwoincognito //CKEY=bwoincognito name = "Fallout Jacket" desc = "The Jacket of an ancient wastelander... Unique DONOR ITEM" icon_state = "riotjacket_u" item_state = "riotjacket_u" -/obj/item/clothing/suit/storage/marine/fluff/vrai +/obj/item/clothing/suit/storage/marine/fluff/adjective name = "HOS Trenchcoat" desc = "A trenchcoat of authority. DONOR ITEM" icon_state = "jensencoat" item_state = "jensencoat" -/obj/item/clothing/suit/storage/marine/fluff/fick +/obj/item/clothing/suit/storage/marine/fluff/fickmacher //CKEY=fickmacher (UNIQUE) name = "Selena's Trenchcoat" desc = "A trenchcoat of authority. DONOR ITEM" icon_state = "jensencoat" @@ -196,26 +326,26 @@ icon_state = "hawkeye_jacket_u" item_state = "hawkeye_jacket_u" -/obj/item/clothing/suit/storage/marine/fluff/chimera +/obj/item/clothing/suit/storage/marine/fluff/chimera //CKEY=theultimatechimera name = "Brett's Trenchcoat" desc = "A trenchcoat of authority. DONOR ITEM" icon_state = "hos" item_state = "hos" -/obj/item/clothing/suit/storage/marine/fluff/devil +/obj/item/clothing/suit/storage/marine/fluff/devilzhand name = "Tank's Trenchcoat" desc = "A trenchcoat of authority. DONOR ITEM" icon_state = "jensencoat" item_state = "jensencoat" -/obj/item/clothing/suit/storage/marine/fluff/pink +/obj/item/clothing/suit/storage/marine/fluff/feweh //CKEY=feweh name = "Pink's Ablative Armor Vest" desc = "The fanciest bullet proof vest you've ever seen. DONOR ITEM" icon_state = "armor_reflec" item_state = "armor_reflec" -/obj/item/clothing/suit/storage/marine/fluff/tye +/obj/item/clothing/suit/storage/marine/fluff/crazyh206 name = "Templar Armor" desc = "Some strange holy armor you don't recognize... DONOR ITEM" //Add UNIQUE if Unique icon_state = "templar" @@ -227,31 +357,31 @@ item_state = "solo_jumpsuit_u" icon_state = "solo_jumpsuit_u" -/obj/item/clothing/suit/storage/marine/fluff/oneonethreeeight +/obj/item/clothing/suit/storage/marine/fluff/oneonethreeeight //CKEY=oneonethreeeight name = "Camouflage Armor" desc = "Woodland Camouflage Armor. DONOR ITEM" //Add UNIQUE if Unique icon_state = "camo_armor" item_state = "camo_armor" -/obj/item/clothing/suit/storage/marine/fluff/dino +/obj/item/clothing/suit/storage/marine/fluff/dino //CKEY=dinobubba7 name = "Sneaking Suit" desc = "An old suit, used by a famous spy. Smells like cigarettes... DONOR ITEM" icon_state = "snakesuit" item_state = "snakesuit" -/obj/item/clothing/suit/storage/marine/fluff/fick2 +/obj/item/clothing/suit/storage/marine/fluff/fickmacher2 //CKEY=fickmacher (UNIQUE) name = "Corporal Hart's Armor" desc = "It looks like the left arm is Robotic, wait what? DONOR ITEM" icon_state = "hartarmor" item_state = "hartarmor" -/obj/item/clothing/suit/storage/marine/fluff/paradox +/obj/item/clothing/suit/storage/marine/fluff/paradox //CKEY=paradox1i7 name = "Templar Armor" desc = "Ancient holy armor of heroes long passed... DONOR ITEM" icon_state = "templar2" item_state = "templar2" -/obj/item/clothing/suit/storage/marine/fluff/roswell +/obj/item/clothing/suit/storage/marine/fluff/chris1464 //CKEY=chris1464 name = "Mercenary Armor" desc = "Armor from an old Mercenary Company, you hope it still holds up... DONOR ITEM" icon_state = "merc_vest" @@ -263,74 +393,68 @@ icon_state = "boba_armor" item_state = "boba_armor" -/obj/item/clothing/suit/storage/marine/fluff/stobarico +/obj/item/clothing/suit/storage/marine/fluff/stobarico //CKEY=stobarico (UNIQUE) name = "British Admiral Uniform" desc = "An ancient uniform of an Admiral. DONOR ITEM" icon_state = "lordadmiral" item_state = "lordadmiral" -/obj/item/clothing/suit/storage/marine/fluff/starscream +/obj/item/clothing/suit/storage/marine/fluff/starscream //CKEY=starscream123 (NOT UNIQUE) name = "Kardar Hussein's Armor" desc = "Slightly worn and torn. DONOR ITEM" icon_state = "merc_armor" item_state = "merc_armor" -/obj/item/clothing/suit/storage/marine/fluff/steelpoint +/obj/item/clothing/suit/storage/marine/fluff/steelpoint //CKEY=steelpoint (UNIQUE) name = "M4X Armor" desc = "Armor to the M4X!!!! DONOR ITEM" icon_state = "steelpoint_armor" item_state = "steelpoint_armor" -/obj/item/clothing/suit/storage/marine/fluff/valentine +/obj/item/clothing/suit/storage/marine/fluff/valentine //CKEY=markvalentine name = "Shocky's Armor" desc = "Shockingly good armor. DONOR ITEM" icon_state = "ertarmor_sec" item_state = "ertarmor_sec" -/obj/item/clothing/suit/storage/marine/fluff/nickiscool +/obj/item/clothing/suit/storage/marine/fluff/nickiskool //CKEY=nickiskool name = "Starlord's Jacket" desc = "Who? DONOR ITEM" icon_state = "star_jacket" item_state = "star_jacker" -/obj/item/clothing/suit/storage/marine/fluff/Sado2 +/obj/item/clothing/suit/storage/marine/fluff/sadokist //CKEY=sadokist name = "T15 spec ops armor" desc = "A suit of tightly woven armor crafted for a special forces operator, meant to be flexible and protective against small arms fire. Seems to be custom fit for a very specific user, as the collar has the name 'Tanya' stamped on it. DONOR ITEM" icon_state = "sadokist_armor" item_state = "sadokist_armor" -/obj/item/clothing/suit/storage/marine/fluff/Fairedan +/obj/item/clothing/suit/storage/marine/fluff/fairedan //CKEY=fairedan (UNIQUE) name = "Freighter Crew Flight Jacket" desc = "Standard Issue Jacket for crew that serve on Lockmart CM-88B Bison starfreighters. It has the number 1809246 on the inside tag... DONOR ITEM" icon_state = "Fairedan_vest" item_state = "Fairedan_vest" -/obj/item/clothing/suit/storage/marine/fluff/Jack +/obj/item/clothing/suit/storage/marine/fluff/jackmcintyre //CKEY=jackmcintyre (UNIQUE) name = "Exo-Suit Jackert" desc = "Some sort of strange Exo-suit jacket. It has the letters USCM stamped over a faded word that appears to be ATLAS... UNIQUE DONOR ITEM" icon_state = "Adam_jacket_u" item_state = "Adam_jacket_u" -/obj/item/clothing/suit/storage/marine/fluff/commisar_armor +/obj/item/clothing/suit/storage/marine/fluff/commissar //used by both ckeys 'hycinth' and 'technokat' (UNIQUE) name = "Omega Commissar Armor" desc = "Armor worn by the feared and respected Comissars of Omega Team. UNIQUE DONOR ITEM" icon_state = "commisar_armor_u" item_state = "commisar_armor_u" -/obj/item/clothing/suit/storage/marine/fluff/medicae_armor +/obj/item/clothing/suit/storage/marine/fluff/medicae_armor //CKEY=graciegrace0 (UNIQUE) name = "Omega Medicae Armor" desc = "Armor worn by the Omega Team Medical Corps. UNIQUE DONOR ITEM" icon_state = "medicae_armor_u" item_state = "medicae_armor_u" -/obj/item/clothing/suit/storage/marine/fluff/standard_armor - name = "Omega Team Armor" - desc = "Armor worn by the Omega Team. DONOR ITEM" - icon_state = "standard_armor" - item_state = "standard_armor" - /obj/item/clothing/suit/storage/marine/fluff/Sanctum_heavy name = "Sanctum Founder Armor" desc = "Personal Armor of the Founder of Sanctum Team. It looks more like a Exosuit. Unique DONOR ITEM" //Add UNIQUE if Unique @@ -343,26 +467,27 @@ icon_state = "Sanctum_Medium_u" item_state = "Sanctum_Medium_u" -/obj/item/clothing/suit/storage/marine/fluff/AlexLemire +/obj/item/clothing/suit/storage/marine/fluff/dudewithatude name = "Rainbow Coat" desc = "Powered by the magic of FRIENDSHIP. (Can be toggled opened or closed) UNIQUE DONOR ITEM" icon_state = "AlexLermire_u" item_state = "AlexLermire_u" - var/open = 0 -/obj/item/clothing/suit/storage/marine/fluff/AlexLemire/verb/verb_toggleopen() + var/open = FALSE + +/obj/item/clothing/suit/storage/marine/fluff/dudewithatude/verb/verb_toggleopen() set src in usr set category = "Object" set name = "Toggle Open" - if(open ==0) + if(!open) icon_state = "AlexLermire_on_u" item_state = "AlexLermire_on_u" - open = 1 + open = TRUE else - open = 0 + open = FALSE icon_state = "AlexLermire_u" item_state = "AlexLermire_u" update_icon() - return + usr.update_inv_wear_suit() /obj/item/clothing/suit/storage/marine/fluff/titus name = "ODST Armor" @@ -370,13 +495,13 @@ icon_state = "leviathan13_u" item_state = "leviathan13_u" -/obj/item/clothing/suit/storage/marine/fluff/blackdrago +/obj/item/clothing/suit/storage/marine/fluff/trblackdragon //CKEY=trblackdragon name = "Strange Looking Armor" desc = "Looks like it's from another time and place... UNIQUE DONOR ITEM" icon_state = "TR-Donor_u" item_state = "TR-Donor_u" -/obj/item/clothing/suit/storage/marine/fluff/zegara +/obj/item/clothing/suit/storage/marine/fluff/zegara //CKEY=zegara name = "Black and Pink armor" desc = "Shiny black armor with pink accents... UNIQUE DONOR ITEM" icon_state = "zegara_armor_u" @@ -387,6 +512,22 @@ desc = "You can't take the sky from me... DONOR ITEM" icon_state = "Eonoc_coat" item_state = "Eonoc_coat" + var/open = FALSE + +/obj/item/clothing/suit/storage/marine/fluff/eonoc/verb/verb_toggleopen() + set src in usr + set category = "Object" + set name = "Toggle Open" + if(!open) + icon_state = "Eonoc_coat_o" + item_state = "Eonoc_coat_o" + open = TRUE + else + open = FALSE + icon_state = "Eonoc_coat" + item_state = "Eonoc_coat" + update_icon() + usr.update_inv_wear_suit() /obj/item/clothing/suit/storage/marine/fluff/kaila name = "Custom Engineering Armor" @@ -394,7 +535,7 @@ icon_state = "kailas_armor" item_state = "kailas_armor" -/obj/item/clothing/suit/storage/marine/fluff/reznor +/obj/item/clothing/suit/storage/marine/fluff/fridrich name = "Solid Black Labcoat" desc = "Very stylish. DONOR ITEM" icon_state = "Reznoriam" @@ -412,7 +553,7 @@ icon_state = "laser243" item_state = "laser243" -/obj/item/clothing/suit/storage/marine/fluff/killaninja +/obj/item/clothing/suit/storage/marine/fluff/killaninja12 name = "space cowboy armor" desc = "Some people call you the space cowboy, some people call you the gangster of love... UNIQUE DONOR ITEM." icon_state = "killaninja12_u" @@ -428,123 +569,80 @@ // HELMETS/HATS/BERETS COSMETICS //////////////////////////////////////////////// - -//HEAD TEMPLATE (for Helmets/Hats/Berets) ONLY TAKE NAME, DESC, ICON_STATE, AND ITEM_STATE. Make a copy of those, and put the ckey of the person at the end after fluff -/obj/item/clothing/head/helmet/marine/fluff - name = "ITEM NAME" - desc = "ITEM DESCRIPTION. DONOR ITEM" //Add UNIQUE if Unique - icon_state = null - item_state = null - //DON'T GRAB STUFF BETWEEN THIS LINE - icon = 'icons/obj/items/clothing/hats.dmi' - icon_override = 'icons/mob/humans/onmob/head_0.dmi' - flags_inventory = BLOCKSHARPOBJ - flags_inv_hide = HIDEEARS - flags_atom = NO_NAME_OVERRIDE - min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROT - flags_marine_helmet = NO_FLAGS - -/obj/item/clothing/head/helmet/marine/fluff/verb/toggle_squad_markings() - set src in usr - if(!ishuman(usr)) return - - if(!usr.canmove || usr.stat || usr.is_mob_restrained() || !usr.loc || !isturf(usr.loc)) - to_chat(usr, SPAN_WARNING("Not right now!")) - return - - to_chat(usr, SPAN_NOTICE("You [flags_marine_helmet & HELMET_SQUAD_OVERLAY? "hide" : "show"] the squad markings.")) - flags_marine_helmet ^= HELMET_SQUAD_OVERLAY - usr.update_inv_head() - -/obj/item/clothing/head/helmet/marine/fluff/verb/toggle_garb_overlay() - set src in usr - if(!ishuman(usr)) return - - if(!usr.canmove || usr.stat || usr.is_mob_restrained() || !usr.loc || !isturf(usr.loc)) - to_chat(usr, SPAN_WARNING("Not right now!")) - return - - to_chat(usr, SPAN_NOTICE("You [flags_marine_helmet & HELMET_GARB_OVERLAY? "hide" : "show"] the helmet garb.")) - flags_marine_helmet ^= HELMET_GARB_OVERLAY - update_icon() - - //AND THIS LINE -//END HEAD TEMPLATE - -/obj/item/clothing/head/helmet/marine/fluff/santahat +/obj/item/clothing/head/helmet/marine/fluff/santahat //CKEY=tophatpenguin name = "Santa's hat" desc = "Ho ho ho. Merrry X-mas!" icon_state = "santahat" flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/sas +/obj/item/clothing/head/helmet/marine/fluff/sas_juggernaut //CKEY=sasoperative (UNIQUE) name = "Juggernaut Helmet" icon_state = "rig0-syndi" desc = "A red helmet, for pairing with JuggerNaut Armor. DONOR ITEM" -/obj/item/clothing/head/helmet/marine/fluff/tristan +/obj/item/clothing/head/helmet/marine/fluff/tristan //CKEY=tristan63 name = "Fancy Helmet" desc = "That's not red paint. That's real blood. DONOR ITEM" icon_state = "syndicate" flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/penguin +/obj/item/clothing/head/helmet/marine/fluff/penguin //CKEY=tophatpenguin name = "Top Penguin Hat" icon_state = "petehat" desc = "A hat for a penguin, maybe even the TOP Penguin... DONOR ITEM" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/mycroft +/obj/item/clothing/head/helmet/marine/fluff/feodrich //CKEY=feodrich (UNIQUE) name = "Doom Helmet" icon_state = "doom_helmet" desc = "A Helmet, of a famous Earth warrior... Donor Item" flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/sas2 +/obj/item/clothing/head/helmet/marine/fluff/sas_juggernaut_alt //CKEY=sasoperative (UNIQUE) name = "Juggernaut Helmet" icon_state = "ncrhelmet" desc = "A red helmet, for pairing with JuggerNaut Armor. DONOR ITEM" flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/Sado +/obj/item/clothing/head/helmet/marine/fluff/sadokist //CKEY=sadokist name = "Tanya's Beret" desc = "A bright red beret, owned by Tanya Edenia." icon_state = "beret_badge" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/Robin +/obj/item/clothing/head/helmet/marine/fluff/robin //CKEY=robin63 name = "Robin Low's Beret" desc = "A bright red beret, owned by Robin Low." icon_state = "beret_badge" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/Vintage +/obj/item/clothing/head/helmet/marine/fluff/vintage //CKEY=vintagepalmer name = "Vintage Pimp Hat" icon_state = "petehat" desc = "A pimp hat, for the classic pimp. DONOR ITEM" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/john56 +/obj/item/clothing/head/helmet/marine/fluff/john56 //CKEY=johnkilla56 name = "Priest hood" icon_state = "chaplain_hood" desc = "Thought I walk through the valley in the shadow of death... Donor Item" -/obj/item/clothing/head/helmet/marine/fluff/biolock +/obj/item/clothing/head/helmet/marine/fluff/biolock //CKEY=biolock name = "Medic Helmet" desc = "Medical Helmet designed to protect the head of a medic. DONOR ITEM" icon_state = "helmetm" -/obj/item/clothing/head/helmet/marine/fluff/haveatya +/obj/item/clothing/head/helmet/marine/fluff/haveatya //CKEY=haveatya name = "Pararescue Beret" desc = "A Pararescue Beret, issued only to the very best. DONOR ITEM" icon_state = "beret_badge" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/sas3 +/obj/item/clothing/head/helmet/marine/fluff/sas_elite //CKEY=sasoperative (UNIQUE) name = "Elite Combat Helmet" icon_state = "hecuhelm_u" desc = "A combat helmet, bearing the scars of many battles. UNIQUE DONOR ITEM" @@ -555,7 +653,7 @@ icon_state = "beret_badge" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/anthonycarmine +/obj/item/clothing/head/helmet/marine/fluff/ningajai name = "Anthony's helmet" desc = "COG helmet owned by Anthony Carmine" icon_state = "anthonycarmine" @@ -574,7 +672,7 @@ icon_state = "gtberet" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/elliotberet +/obj/item/clothing/head/helmet/marine/fluff/commandercookies //CKEY=commandercookies name = "Elliots Beret" desc = "A dark maroon beret" icon_state = "eberet" @@ -587,7 +685,7 @@ item_state = "detective" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/limo +/obj/item/clothing/head/helmet/marine/fluff/limo //CKEY=limodish (UNIQUE) name = "Blood Red Hardsuit" desc = "It looks like a costume hardsuit helmet. DONOR ITEM" icon_state = "syndicate" @@ -595,7 +693,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/devil +/obj/item/clothing/head/helmet/marine/fluff/devilzhand name = "MICH Helmet" desc = "A fancy combat helmet. DONOR ITEM" icon_state = "mich" @@ -609,7 +707,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEEYES -/obj/item/clothing/head/helmet/marine/fluff/BWO +/obj/item/clothing/head/helmet/marine/fluff/bwoincognito //CKEY=bwoincognito name = "Fallout Helmet" desc = "A helmet from an ancient wastelander... UNIQUE DONOR ITEM" icon_state = "riothelm_u" @@ -624,7 +722,7 @@ item_state = "beret_badge" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/fick +/obj/item/clothing/head/helmet/marine/fluff/fickmacher //CKEY=fickmacher (UNIQUE) name = "Selena's hat" desc = "A fancy beret. DONOR ITEM" icon_state = "hosberet" @@ -638,21 +736,21 @@ item_state = "hosberet" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/chimera +/obj/item/clothing/head/helmet/marine/fluff/chimera //CKEY=theultimatechimera name = "Brett's hat" desc = "A fancy beret. DONOR ITEM" icon_state = "hosberet" item_state = "hosberet" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/lostmix +/obj/item/clothing/head/helmet/marine/fluff/lostmixup name = "Infinite Ammo Bandanna" desc = "Disclaimer: Probably doesn't provide infinite ammo. UNIQUE DONOR ITEM" icon_state = "headband_u" item_state = "headband_u" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/LEO +/obj/item/clothing/head/helmet/marine/fluff/totalanarchy //CKEY=totalanarchy name = "Leo's Helm" desc = "An old mercenary helmet. DONOR ITEM" icon_state = "merc_helm" @@ -660,20 +758,20 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDELOWHAIR -/obj/item/clothing/head/helmet/marine/fluff/oneonethreeeight +/obj/item/clothing/head/helmet/marine/fluff/oneonethreeeight //CKEY=oneonethreeeight name = "Camouflage Helmet" desc = "Woodland Camouflage helmet. DONOR ITEM" icon_state = "camo_helm" item_state = "camo_helm" -/obj/item/clothing/head/helmet/marine/fluff/dino +/obj/item/clothing/head/helmet/marine/fluff/dino //CKEY=dinobubba7 name = "Snake's Bandana" desc = "Property of The Boss. DONOR ITEM" icon_state = "snakeheadband" item_state = "snakeheadband" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/paradox +/obj/item/clothing/head/helmet/marine/fluff/paradox //CKEY=paradox1i7 name = "Templar Helmet" desc = "The helm of a once powerful order. DONOR ITEM" icon_state = "templar_helm" @@ -688,7 +786,7 @@ item_state = "beret_badge" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/roswell +/obj/item/clothing/head/helmet/marine/fluff/chris1464 //CKEY=chris1464 name = "Merc Beret" desc = "Beret from a Mercenary Company. DONOR ITEM" icon_state = "cargosoft" @@ -703,7 +801,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/coleMercer +/obj/item/clothing/head/helmet/marine/fluff/whiteblood17 //CKEY=whiteblood17 name = "Black Ops Helmet" desc = "You're not authorized to look at it. DONOR ITEM" icon_state = "syndicate-helm-black" @@ -711,14 +809,14 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/leondark +/obj/item/clothing/head/helmet/marine/fluff/leondark //CKEY=leondark16 name = "Hunter's USCM Cap" desc = "A well-worn cap with the name 'Barrientos' written on the inside. DONOR ITEM" icon_state = "USCM_cap" item_state = "USCM_cap" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/starscream +/obj/item/clothing/head/helmet/marine/fluff/starscream //CKEY=starscream123 (UNIQUE) name = "Kardar Hussein's Helmet" desc = "Slightly worn and torn. DONOR ITEM" icon_state = "asset_protect" @@ -726,7 +824,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/blackdragon +/obj/item/clothing/head/helmet/marine/fluff/trblackdragon //CKEY=trblackdragon name = "Spartan Helmet" desc = "SPARTANS, WHAT IS YOUR PROFESSION? DONOR ITEM" icon_state = "blackdragon_helmet_u" //UNIQUE @@ -734,7 +832,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/steelpoint +/obj/item/clothing/head/helmet/marine/fluff/steelpoint //CKEY=steelpoint (UNIQUE) name = "M4X Helmet" desc = "Helmets to the M4X!!! DONOR ITEM" icon_state = "steelpoint_helmet" @@ -742,7 +840,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/valentine +/obj/item/clothing/head/helmet/marine/fluff/valentine //CKEY=markvalentine name = "Shocky's Helmet" desc = "Shockingly good helmet. DONOR ITEM" icon_state = "syndicate-helm-black" @@ -750,14 +848,14 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/Jdobbin49 +/obj/item/clothing/head/helmet/marine/fluff/jdobbin49 //CKEY=jdobbin49 name = "Phillip's Beret" desc = "Beret owned by Phillip Greenwall. DONOR ITEM" icon_state = "berettan" item_state = "berettan" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/nickiscool +/obj/item/clothing/head/helmet/marine/fluff/nickiskool //CKEY=nickiskool name = "Starlord Mask" desc = "Just in case someone might recognize you... DONOR ITEM" icon_state = "star_mask" @@ -765,7 +863,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/Bibblesless +/obj/item/clothing/head/helmet/marine/fluff/bibblesless name = "Yellow ERT Helmet" desc = "Standard Emergency Helmet, yellow variety.... DONOR ITEM" icon_state = "rig0-ert_engineer" @@ -773,7 +871,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/FernKiller +/obj/item/clothing/head/helmet/marine/fluff/fernkiller name = "White ERT Helmet" desc = "Standard Emergency Helmet, white variety.... DONOR ITEM" icon_state = "rig0-ert_medical" @@ -781,14 +879,14 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/Jack +/obj/item/clothing/head/helmet/marine/fluff/jackmcintyre //CKEY=jackmcintyre (UNIQUE) name = "USCM Ball Cap" desc = "USCM Cold Weather Ball Cap... DONOR ITEM" icon_state = "Adam_hat" item_state = "Adam_hat" flags_inventory = BLOCKSHARPOBJ -/obj/item/clothing/head/helmet/marine/fluff/commissar_helmet +/obj/item/clothing/head/helmet/marine/fluff/commissar //used by both ckeys 'hycinth' and 'technokat' (UNIQUE) name = "Omega Commissar Helmet" desc = "Helmet worn by the Comissars of Omega Team. UNIQUE DONOR ITEM" icon_state = "commissar_helmet_u" @@ -796,7 +894,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/medicae_helmet +/obj/item/clothing/head/helmet/marine/fluff/medicae_helmet //CKEY=graciegrace0 (UNIQUE) name = "Omega Medicae Helmet" desc = "Helmet worn by the Medical Corps of Omega Team. UNIQUE DONOR ITEM" icon_state = "medicae_helmet_u" @@ -804,14 +902,6 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/standard_helmet - name = "Omega Team Helmet" - desc = "Helmet worn by Omega Team. DONOR ITEM" //Add UNIQUE if Unique - icon_state = "standard_helmet" - item_state = "standard_helmet" - flags_inventory = BLOCKSHARPOBJ - flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR - /obj/item/clothing/head/helmet/marine/fluff/Sanctum_helmet name = "Sanctum Combat Helmet" desc = " The Standard Issue helmet of Sanctum Team. DONOR ITEM" //Add UNIQUE if Unique @@ -820,7 +910,7 @@ flags_inventory = BLOCKSHARPOBJ flags_inv_hide = HIDEEARS|HIDEMASK|HIDEEYES|HIDEALLHAIR -/obj/item/clothing/head/helmet/marine/fluff/DingleDangle +/obj/item/clothing/head/helmet/marine/fluff/dingledangle name = "Rusty's Cap" desc = "A little old and shabby. The color has slightly faded over time. DONOR ITEM" icon_state = "bluesoft" @@ -876,97 +966,89 @@ //AND THIS LINE //END UNIFORM TEMPLATE -/obj/item/clothing/under/marine/fluff/marinemedic +/obj/item/clothing/under/marine/fluff/marinemedic //UNUSED name = "Marine Medic jumpsuit" desc = "A standard quilted Colonial Marine jumpsuit. Weaved with armored plates to protect against low-caliber rounds and light impacts. Has medical markings. " icon_state = "marine_medic" worn_state = "marine_medic" -/obj/item/clothing/under/marine/fluff/marineengineer +/obj/item/clothing/under/marine/fluff/marineengineer //UNUSED name = "Marine Technician jumpsuit" desc = "A standard quilted Colonial Marine jumpsuit. Weaved with armored plates to protect against low-caliber rounds and light impacts. Has engineer markings. " icon_state = "marine_engineer" worn_state = "marine_engineer" -/obj/item/clothing/under/marine/fluff/turtleneck - name = "Black Ops Turtleneck" - desc = "A $900 black turtleneck woven from only the purest Azerbaijani cashmere wool. DONOR ITEM" - icon_state = "syndicate" - item_state = "bl_suit" - worn_state = "syndicate" - flags_jumpsuit = FALSE - -/obj/item/clothing/under/marine/fluff/tristan +/obj/item/clothing/under/marine/fluff/tristan //CKEY=tristan63 desc = "It's a blue jumpsuit with some gold markings denoting the rank of \"Captain\"." name = "captain's jumpsuit" icon_state = "camojump" worn_state = "camojump" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/SAS +/obj/item/clothing/under/marine/fluff/sas_legion //CKEY=sasoperative (UNIQUE) name = "Legion Suit" desc = "This armor was custom-made to resemble the small growing Legion within the galaxy started by one man slowly making its way to becoming a larger Corporation. DONOR ITEM." icon_state = "ncr_uni" worn_state = "ncr_uni" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/mycroft +/obj/item/clothing/under/marine/fluff/feodrich //CKEY=feodrich (UNIQUE) name = "Doom Uniform" desc = "A uniform, of a famous Earth warrior... Donor Item" icon_state = "doom_suit" worn_state = "doom_suit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/LEO +/obj/item/clothing/under/marine/fluff/totalanarchy //CKEY=totalanarchy name = "Mercenary Jumpsuit Suit" desc = "A uniform from a band of mercenaries... DONOR ITEM." icon_state = "merc_jumpsuit" worn_state = "merc_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/john56 +/obj/item/clothing/under/marine/fluff/john56 //CKEY=johnkilla56 name = "Pink Pride Jumpsuit" desc = "A jumpsuit for showing your pride in pink... Donor Item" icon_state = "pink" worn_state = "pink" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/sas3 //UNIQUE +/obj/item/clothing/under/marine/fluff/sas_elite //CKEY=sasoperative (UNIQUE) name = "Black Fatigues" desc = "Black camo Fatigues usually used on Night Operations. UNIQUE DONOR ITEM." icon_state = "hecu_u" worn_state = "hecu_u" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/leeeverett +/obj/item/clothing/under/marine/fluff/leeeverett //CKEY=theflagbearer (UNIQUE) name = "Rugged Outfit" desc = "It's covered in blood and smells terrible. Who died in this?" icon_state = "rugged" worn_state = "rugged" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/Vintage +/obj/item/clothing/under/marine/fluff/vintage //CKEY=vintagepalmer name = "Vintage Pink Jumpsuit" desc = "A jumpsuit that was either once red, or once white and washed with a load of colors... Donor Item" icon_state = "pink" worn_state = "pink" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/wooki +/obj/item/clothing/under/marine/fluff/wooki //CKEY=tophatpenguin (UNIQUE) name = "Fancy Uniform" desc = "Wooki's fancy blue suit. UNIQUE DONOR ITEM" icon_state = "wooki_u" worn_state = "wooki_u" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/Zynax +/obj/item/clothing/under/marine/fluff/Zynax //CKEY=zynax name = "Gorka Suit" desc = "Russian Gamo. DONOR ITEM" icon_state = "gorkasuit" worn_state = "gorkasuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/BWO +/obj/item/clothing/under/marine/fluff/bwoincognito //CKEY=bwoincognito name = "Fallout Suit" desc = "A suit from an ancient group of wastelanders... UNIQUE DONOR ITEM" icon_state = "riot_u" @@ -980,7 +1062,7 @@ worn_state = "hos_corporate" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/fick +/obj/item/clothing/under/marine/fluff/fickmacher //CKEY=fickmacher (UNIQUE) name = "Selena's Tactical Suit" desc = "A strange looking black jumpsuit. DONOR ITEM" icon_state = "robotics" @@ -993,35 +1075,35 @@ worn_state = "hawkeye_jumpsuit_u" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/pink +/obj/item/clothing/under/marine/fluff/feweh //CKEY=feweh name = "Pink Fatigues" desc = "For fighting breast cancer. With bullets. Donor Item" icon_state = "pink2" worn_state = "pink2" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/oneonethreeeight +/obj/item/clothing/under/marine/fluff/oneonethreeeight //CKEY=oneonethreeeight name = "Camouflage Jumpsuit" desc = "Woodland Camouflage Jumpsuit. DONOR ITEM" icon_state = "camo_jumpsuit" worn_state = "camo_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/fick2 +/obj/item/clothing/under/marine/fluff/fickmacher2 //CKEY=fickmacher (UNIQUE) name = "Hart's Suit" desc = "It looks like the Right Arm is robotic. DONOR ITEM" icon_state = "hart_jumpsuit" worn_state = "hart_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/paradox +/obj/item/clothing/under/marine/fluff/paradox //CKEY=paradox1i7 name = "Templar Jumpsuit" desc = "The interface components, for Templar Armor. DONOR ITEM" icon_state = "templar_jumpsuit" worn_state = "templar_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/roswell +/obj/item/clothing/under/marine/fluff/chris1464 //CKEY=chris1464 name = "Merc Jumpsuit" desc = "Jumpsuit from a super shady mercenary company. DONOR ITEM" icon_state = "merc_jumpsuit" @@ -1035,35 +1117,35 @@ worn_state = "boba_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/jackmcintyre +/obj/item/clothing/under/marine/fluff/jackmcintyre_alt //CKEY=jackmcintyre name = "Dress Uniform" desc = "A Dress uniform, worn by standard marines. DONOR ITEM" icon_state = "BO_jumpsuit" worn_state = "BO_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/starscream +/obj/item/clothing/under/marine/fluff/starscream //CKEY=starscream123 (UNIQUE) name = "Kardar Hussein's Jumpsuit" desc = "Slightly worn and torn. DONOR ITEM" icon_state = "merc_jumpsuit2" worn_state = "merc_jumpsuit2" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/allan +/obj/item/clothing/under/marine/fluff/allan1234 name = "Commander Jumpsuit" desc = "Jumpsuit worn by a space commander... DONOR ITEM" icon_state = "henrick_jumpsuit" worn_state = "henrick_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/steelpoint +/obj/item/clothing/under/marine/fluff/steelpoint //CKEY=steelpoint (UNIQUE) name = "M4X Jumpsuit" desc = "Jumpsuit to the M4X!!! DONOR ITEM" icon_state = "steelpoint_jumpsuit" worn_state = "steelpoint_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/valentine +/obj/item/clothing/under/marine/fluff/valentine //CKEY=markvalentine name = "Shocky's Jumpsuit" desc = "Shockingly good Jumpsuit. DONOR ITEM" icon_state = "jensen" @@ -1077,70 +1159,63 @@ worn_state = "samus_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/nickiscool +/obj/item/clothing/under/marine/fluff/nickiskool //CKEY=nickiskool name = "Starlords Jumpsuit" desc = "Designed to show off your manly muscles for all the ladies. DONOR ITEM" icon_state = "star_jumpsuit" worn_state = "star_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/Jack +/obj/item/clothing/under/marine/fluff/jackmcintyre //CKEY=jackmcintyre (UNIQUE) name = "White shirt and black Pants" desc = "Perfect for formal dress, or going to a combat zone in Style. UNIQUE DONOR ITEM" icon_state = "Adam_jumpsuit_u" worn_state = "Adam_jumpsuit_u" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/Fairedan +/obj/item/clothing/under/marine/fluff/fairedan //CKEY=fairedan (UNIQUE) name = "Starfreighter Jumpsuit" desc = "Standard Issue Jumpsuit for crew that serve on Lockmart CM-88B Bison starfreighters. It has the number 1809246 on the inside tag.... DONOR ITEM" icon_state = "Fairedan_jumpsuit" worn_state = "Fairedan_jumpsuit" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/commisar_jumpsuit +/obj/item/clothing/under/marine/fluff/commissar //used by both ckeys 'hycinth' and 'technokat' (UNIQUE) name = "Omega Commissar Uniform" desc = "Uniform worn by the Comissars of Omega Team. UNIQUE DONOR ITEM" icon_state = "commisar_jumpsuit_u" worn_state = "commisar_jumpsuit_u" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/medicae_jumpsuit +/obj/item/clothing/under/marine/fluff/medicae_jumpsuit //CKEY=graciegrace0 (UNIQUE) name = "Omega Medicae Uniform" desc = "Uniform work by the Medical Corps of Omega Team. UNIQUE DONOR ITEM" icon_state = "medicae_jumpsuit_u" worn_state = "medicae_jumpsuit_u" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/standard_jumpsuit - name = "Omega Team Uniform" - desc = "Uniform worn by Omega Team. DONOR ITEM" - icon_state = "standard_jumpsuit" - worn_state = "standard_jumpsuit" - flags_jumpsuit = FALSE - -/obj/item/clothing/under/marine/fluff/Sanctum_uniform +/obj/item/clothing/under/marine/fluff/sanctum_uniform //NO USER name = "Sanctum Fatigues" desc = "Fatigues with Kevlar fibers for a bit more protection than most clothing. UNIQUE DONOR ITEM" icon_state = "Sanctum_u" worn_state = "Sanctum_u" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/sailorDave +/obj/item/clothing/under/marine/fluff/sailordave //CKEY=sailordave name = "Eden USCM uniform" desc = "An older model USCM uniform. UNIQUE DONOR ITEM" icon_state = "syndicate" worn_state = "syndicate" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/coleMercer +/obj/item/clothing/under/marine/fluff/whiteblood17 //CKEY=whiteblood17 name = "Black Ops uniform" desc = "Way above your pay grade... DONOR ITEM" icon_state = "jensen" worn_state = "jensen" flags_jumpsuit = FALSE -/obj/item/clothing/under/marine/fluff/mileswolfe +/obj/item/clothing/under/marine/fluff/mileswolfe //CKEY=mileswolfe name = "tiger striped combat fatigues" desc = "Combat Fatigues that appear to have tiger stripes on them. UNIQUE DONOR ITEM" icon_state = "mileswolfe_u" @@ -1150,35 +1225,14 @@ // MASK COSMETICS //////////////////////////////////////////////// -//MASK TEMPLATE (for masks) ONLY TAKE NAME, DESC, ICON_STATE, ITEM_STATE, AND ITEM_COLOR. Make a copy of those, and put the ckey of the person at the end after fluff -/obj/item/clothing/mask/fluff - name = "ITEM NAME" - desc = "ITEM DESCRIPTION. DONOR ITEM" //Add UNIQUE if Unique - icon_state = null - item_state = null - //DON'T GRAB STUFF BETWEEN THIS LINE - flags_inventory = ALLOWREBREATH - flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE - //AND THIS LINE - -//END MASK TEMPLATE - - -/obj/item/clothing/mask/fluff/john56 +/obj/item/clothing/mask/fluff/john56 //CKEY=johnkilla56 name = "Revan Mask" desc = "A mask from a famous sith... Wait what? DONOR ITEM." item_state = "revanmask" icon_state = "revanmask" -/obj/item/clothing/mask/fluff/balaclava - name = "Balaclava" - desc = "A black Balaclava used for hiding your face. DISCLAIMER: May not actually hide your face... DONOR ITEM" - item_state = "balaclava" - icon_state = "balaclava" - flags_inventory = COVERMOUTH|ALLOWREBREATH - flags_inv_hide = HIDEEARS|HIDEFACE|HIDEALLHAIR -/obj/item/clothing/mask/fluff/SAS +/obj/item/clothing/mask/fluff/sas_legion //CKEY=sasoperative (UNIQUE) name = "Legion Mask" desc = "This armor was custom-made to resemble the small growing Legion within the galaxy started by one man slowly making its way to becoming a larger Corporation. DONOR ITEM." icon_override = 'icons/mob/humans/onmob/mask.dmi' @@ -1187,7 +1241,7 @@ flags_inventory = COVERMOUTH|ALLOWREBREATH flags_inv_hide = HIDEEARS|HIDEFACE|HIDEALLHAIR -/obj/item/clothing/mask/fluff/LEO +/obj/item/clothing/mask/fluff/totalanarchy //CKEY=totalanarchy name = "PMC Mask" desc = "A white colored PMC Mask. DONOR ITEM." icon_override = 'icons/mob/humans/onmob/mask.dmi' @@ -1196,13 +1250,13 @@ flags_inventory = COVERMOUTH|ALLOWREBREATH flags_inv_hide = HIDEEARS|HIDEFACE|HIDEALLHAIR -/obj/item/clothing/mask/fluff/sas3 //UNIQUE +/obj/item/clothing/mask/fluff/sas_elite //CKEY=sasoperative (UNIQUE) name = "Compact Gas Mask" desc = "A compact Gas Mask with a pure red tint to it. UNIQUE DONOR ITEM." item_state = "hecumask_u" icon_state = "hecumask_u" -/obj/item/clothing/mask/fluff/limo +/obj/item/clothing/mask/fluff/limo //CKEY=limodish name = "Swat Mask" desc = "Swat Gas Mask. DONOR ITEM" icon_state = "swat" @@ -1210,7 +1264,7 @@ flags_inventory = ALLOWREBREATH flags_inv_hide = HIDEEYES|HIDEFACE -/obj/item/clothing/mask/fluff/pink +/obj/item/clothing/mask/fluff/feweh //CKEY=feweh name = "Pink's Gas Mask" desc = "A standard issue gas mask. DONOR ITEM" icon_state = "swat" @@ -1218,7 +1272,7 @@ flags_inventory = ALLOWREBREATH flags_inv_hide = HIDEEYES|HIDEFACE -/obj/item/clothing/mask/fluff/fick2 +/obj/item/clothing/mask/fluff/fickmacher2 //CKEY=fickmacher (UNIQUE) name = "Corporal Hart's Mask" desc = "A robotic looking Armored mask. DONOR ITEM" icon_state = "hartmask" @@ -1226,7 +1280,7 @@ flags_inventory = ALLOWREBREATH flags_inv_hide = HIDEFACE -/obj/item/clothing/mask/fluff/starscream +/obj/item/clothing/mask/fluff/starscream //CKEY=starscream123 (UNIQUE) name = "Kardar Hussein's mask" desc = "Slightly worn and torn. DONOR ITEM" icon_state = "merc_mask" @@ -1234,7 +1288,7 @@ flags_inventory = ALLOWREBREATH flags_inv_hide = HIDEFACE -/obj/item/clothing/mask/fluff/lostmix +/obj/item/clothing/mask/fluff/lostmixup name = "Phantom Cigar" desc = "It's a g-g-g-g-g-ghost cigar. DONOR ITEM" //Add UNIQUE if Unique icon_state = "cigar_on" @@ -1243,28 +1297,19 @@ flags_inv_hide = HIDEFACE // BOOTS/SHOES COSMETICS //////////////////////////////////////////////// - -//FEET TEMPLATE (for masks) ONLY TAKE NAME, DESC, ICON_STATE, ITEM_STATE, AND ITEM_COLOR. Make a copy of those, and put the ckey of the person at the end after fluff -/obj/item/clothing/shoes/marine/fluff - name = "ITEM NAME" - desc = "ITEM DESCRIPTION. DONOR ITEM" //Add UNIQUE if Unique - icon_state = null - item_state = null -//END FEET TEMPLATE - -/obj/item/clothing/shoes/marine/fluff/Vintage +/obj/item/clothing/shoes/marine/fluff/vintage //CKEY=vintagepalmer name = "Vintage Sandals" desc = "Vintage Sandals, suitable for only the highest class of hipster. DONOR ITEM" icon_state = "wizard" item_state = "wizard" -/obj/item/clothing/shoes/marine/fluff/mycroft +/obj/item/clothing/shoes/marine/fluff/feodrich //CKEY=feodrich (UNIQUE) name = "Doom Shoes" desc = "A uniform, of a famous Earth warrior... Donor Item" icon_state = "doom_boots" item_state = "doom_boots" -/obj/item/clothing/shoes/marine/fluff/steelpoint +/obj/item/clothing/shoes/marine/fluff/steelpoint //CKEY=steelpoint (UNIQUE) name = "M4X Boot" desc = "Boots to the M4X. DONOR ITEM" icon_state = "jackboots" @@ -1272,47 +1317,31 @@ //GENERIC GLASSES, GLOVES, AND MISC //////////////////// -/obj/item/clothing/gloves/marine/fluff //MARINE GLOVES TEMPLATE - name = "ITEM NAME" - desc = "ITEM DESCRIPTION. DONOR ITEM" //Add UNIQUE if Unique - icon_state = null - item_state = null - -/obj/item/clothing/glasses/fluff - flags_inventory = COVEREYES - -/obj/item/clothing/glasses/fluff/eyepatch - name = "An Eyepatch" - desc = "Badass +10. Donor Item" - icon_state = "eyepatch" - item_state = "eyepatch" - -/obj/item/clothing/glasses/fluff/wright +/obj/item/clothing/glasses/fluff/wright //CKEY=wrightthewrong name = "eyepatch" desc = "Yarr, this be a Donor Item, YARR!" icon_state = "eyepatch" item_state = "eyepatch" -/obj/item/clothing/glasses/fluff/sado +/obj/item/clothing/glasses/fluff/sadokist //CKEY=sadokist name = "Tanya's Optics" desc = "Custom Optics, owned by Tanya Edenia" icon_state = "thermal" item_state = "glasses" -/obj/item/clothing/glasses/fluff/haveatya +/obj/item/clothing/glasses/fluff/haveatya //CKEY=haveatya name = "Special Nightvision Goggles" desc = "Disclaimer: May not provide Night Vision. DONOR ITEM" icon_state = "night" item_state = "glasses" -/obj/item/clothing/gloves/black/obey +/obj/item/clothing/gloves/black/obey //CKEY=obeystylez (UNIQUE) desc = "Black gloves, favored by Special Operations teams. DONOR ITEM" name = "Black Ops Black Gloves" -/obj/item/storage/backpack/marine/fluff - xeno_types = null +//BACKPACKS -/obj/item/storage/backpack/marine/fluff/Sado +/obj/item/storage/backpack/marine/fluff/sadokist //CKEY=sadokist name = "Tanya's Backpack" desc = "A large backpack, used by Tanya Edenia. DONOR ITEM" icon_state = "securitypack" @@ -1324,32 +1353,32 @@ icon_state = "securitypack" item_state = "securitypack" -/obj/item/clothing/glasses/fluff/alexwar +/obj/item/clothing/glasses/fluff/alexwarhammer name = "Black Jack's Dank Shades" desc = "+20 Badass points. Donor item" icon_state = "sun" item_state = "sun" -/obj/item/clothing/gloves/marine/fluff/jedijas +/obj/item/clothing/gloves/marine/fluff/jedijas //CKEY=jedijasun (UNIQUE) name = "Fists of Mandalore" desc = "If Mandalore was a person, these would be it's fists... DONOR ITEM" icon_state = "marine_white" item_state = "marine_wgloves" -/obj/item/storage/belt/marine/fluff/swordbelt +/obj/item/storage/belt/marine/fluff/commissar //used by both ckeys 'hycinth' and 'technokat' (UNIQUE) name = "Omega Sword Belt" desc = "Belt worn by the dreaded Commissars of Omega Team. UNIQUE DONOR ITEM" icon_state = "swordbelt_u" item_state = "swordbelt_u" //CUSTOM ITEMS - NO TEMPLATES - ALL UNIQUE //////////////////////// -/obj/item/tool/lighter/zippo/fluff/ghost - name = "Gold zippo lighter" - desc = "A Golden Zippo lighter, engraved with the name John Donable... UNIQUE DONOR ITEM." +/obj/item/tool/lighter/zippo/fluff/ghostdex //CKEY=ghostdex + name = "purple zippo lighter" + desc = "A Purple Zippo lighter, engraved with the name John Donable... UNIQUE DONOR ITEM." icon = 'icons/obj/items/items.dmi' icon_state = "bluezippo" -/obj/item/clothing/mask/cigarette/fluff/ghost +/obj/item/clothing/mask/cigarette/fluff/ghostdex //CKEY=ghostdex name = "XXX's custom Cigar" desc = "A custom rolled giant, made specifically for John Donable in the best, hottest, and most abusive of Cuban sweat shops. UNIQUE DONOR ITEM." icon_state = "cigar2_off" @@ -1361,8 +1390,8 @@ //GHOST CIGAR CODE -/obj/item/clothing/mask/cigarette/cigar/fluff/ghost/attackby(obj/item/W as obj, mob/user as mob) - if(istype(W, /obj/item/tool/lighter/zippo/fluff/ghost)) +/obj/item/clothing/mask/cigarette/cigar/fluff/ghostdex/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/tool/lighter/zippo/fluff/ghostdex)) ..() else to_chat(user, SPAN_NOTICE("\The [src] straight out REFUSES to be lit by anything other than a purple zippo.")) diff --git a/code/modules/cm_marines/Donator_Kits.dm b/code/modules/cm_marines/Donator_Kits.dm new file mode 100644 index 000000000000..2576732736aa --- /dev/null +++ b/code/modules/cm_marines/Donator_Kits.dm @@ -0,0 +1,588 @@ +/obj/item/storage/box/donator_kit + name = "donated box" + desc = "A cardboard box stamped with a dollar sign and filled with trinkets. Appears to have been donated by a wealthy sponsor." + icon_state = "donator_kit" + item_state = "giftbag" + var/list/donor_gear = list() + var/donor_key = "GENERIC" //Key the kit is assigned to. If GENERIC, not tied to particular donor. + var/kit_variant + max_w_class = SIZE_TINY + +/obj/item/storage/box/donator_kit/New() + if(kit_variant) + name = "[name] ([kit_variant])" + ..() + +/obj/item/storage/box/donator_kit/fill_preset_inventory() + for(var/donor_item in donor_gear) + new donor_item(src) + +/obj/item/storage/box/donator_kit/open(mob/user) + if((donor_key != "GENERIC") && (donor_key != user.ckey)) + to_chat(user, SPAN_BOLDWARNING("You cannot open a donator kit you do not own!")) + return FALSE + ..() + +/obj/item/storage/box/donator_kit/verb/destroy_kit() + set name = "Destroy Kit" + set category = "Object" + set src in oview(1) + + var/mob/user = usr + + if((donor_key != "GENERIC") && (donor_key != user.ckey)) + to_chat(user, SPAN_BOLDWARNING("You cannot destroy a donator kit you do not own!")) + return FALSE + + log_admin("[key_name(user)] deleted a donator kit.") + qdel(src) + +/obj/item/storage/box/donator_kit/generic_omega //Generic set given to various donors + kit_variant = "Team Omega (G)" + donor_gear = list( + /obj/item/clothing/under/marine/fluff/standard_jumpsuit, + /obj/item/clothing/suit/storage/marine/fluff/standard_armor, + /obj/item/clothing/head/helmet/marine/fluff/standard_helmet, + ) + +//Unless specified in comments as otherwise, subtype of box/donator_kit/ is CKEY of the donator (example: /obj/item/storage/box/donator_kit/sasoperative) +/obj/item/storage/box/donator_kit/adjective + donor_key = "adjective" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/adjective) + +/obj/item/storage/box/donator_kit/alexwarhammer + donor_key = "alexwarhammer" + donor_gear = list(/obj/item/clothing/glasses/fluff/alexwarhammer) + +/obj/item/storage/box/donator_kit/allan1234 + donor_key = "allan1234" + donor_gear = list(/obj/item/clothing/under/marine/fluff/allan1234) + +/obj/item/storage/box/donator_kit/arachnidnexus + donor_key = "arachnidnexus" + donor_gear = list(/obj/item/clothing/under/marine/fluff/arach) + +/obj/item/storage/box/donator_kit/bibblesless + donor_key = "bibblesless" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/bibblesless) + +/obj/item/storage/box/donator_kit/biolock + donor_key = "biolock" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/biolock, + /obj/item/clothing/suit/storage/marine/fluff/biolock, + ) + +/obj/item/storage/box/donator_kit/bunny232 + donor_key = "bunny232" + donor_gear = list(/obj/item/clothing/glasses/fluff/eyepatch) + +/obj/item/storage/box/donator_kit/bwoincognito + donor_key = "bwoincognito" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/bwoincognito, + /obj/item/clothing/suit/storage/marine/fluff/bwoincognito, + /obj/item/clothing/under/marine/fluff/bwoincognito, + ) + +/obj/item/storage/box/donator_kit/chris1464 + donor_key = "chris1464" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/chris1464, + /obj/item/clothing/suit/storage/marine/fluff/chris1464, + /obj/item/clothing/under/marine/fluff/chris1464, + ) + +/obj/item/storage/box/donator_kit/commandercookies + donor_key = "commandercookies" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/commandercookies, + /obj/item/clothing/suit/storage/marine/fluff/commandercookies, + ) + +/obj/item/storage/box/donator_kit/commissar //used by both ckeys 'hycinth' and 'technokat' + donor_key = "hycinth" + kit_variant = "Commissar" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/commissar, + /obj/item/clothing/suit/storage/marine/fluff/commissar, + /obj/item/clothing/under/marine/fluff/commissar, + /obj/item/storage/belt/marine/fluff/commissar, + ) + +/obj/item/storage/box/donator_kit/commissar/technokat + donor_key = "technokat" + +/obj/item/storage/box/donator_kit/crazyh206 + donor_key = "crazyh206" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/crazyh206) + +/obj/item/storage/box/donator_kit/devilzhand + donor_key = "devilzhand" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/devilzhand, + /obj/item/clothing/suit/storage/marine/fluff/devilzhand, + ) + +/obj/item/storage/box/donator_kit/dingledangle + donor_key = "dingledangle" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/dingledangle) + +/obj/item/storage/box/donator_kit/dinobubba7 + donor_key = "dinobubba7" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/dino, + /obj/item/clothing/suit/storage/marine/fluff/dino, + ) + +/obj/item/storage/box/donator_kit/docdemo + donor_key = "docdemo" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/goldtrimberet) + +/obj/item/storage/box/donator_kit/dudewithatude + donor_key = "dudewithatude" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/dudewithatude) + +/obj/item/storage/box/donator_kit/eastgermanstasi + donor_key = "eastgermanstasi" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/eastgerman) + +/obj/item/storage/box/donator_kit/edgelord + donor_key = "edgelord" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/edgelord) + +/obj/item/storage/box/donator_kit/eonoc + donor_key = "eonoc" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/eonoc) + +/obj/item/storage/box/donator_kit/fairedan + donor_key = "fairedan" + donor_gear = list( + /obj/item/clothing/suit/storage/marine/fluff/fairedan, + /obj/item/clothing/under/marine/fluff/fairedan, + ) + +/obj/item/storage/box/donator_kit/feodrich + donor_key = "feodrich" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/feodrich, + /obj/item/clothing/shoes/marine/fluff/feodrich, + /obj/item/clothing/suit/storage/marine/fluff/feodrich, + /obj/item/clothing/under/marine/fluff/feodrich, + ) + +/obj/item/storage/box/donator_kit/fernkiller + donor_key = "fernkiller" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/fernkiller) + +/obj/item/storage/box/donator_kit/feweh + donor_key = "feweh" + donor_gear = list( + /obj/item/clothing/mask/fluff/feweh, + /obj/item/clothing/suit/storage/marine/fluff/feweh, + /obj/item/clothing/under/marine/fluff/feweh, + ) + +/obj/item/storage/box/donator_kit/fickmacher_selena //ckey fickmacher has two sets + donor_key = "fickmacher" + kit_variant = "Selena" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/fickmacher, + /obj/item/clothing/suit/storage/marine/fluff/fickmacher, + /obj/item/clothing/under/marine/fluff/fickmacher, + ) + +/obj/item/storage/box/donator_kit/fickmacher_hart + donor_key = "fickmacher" + kit_variant = "Hart" + donor_gear = list( + /obj/item/clothing/mask/fluff/fickmacher2, + /obj/item/clothing/suit/storage/marine/fluff/fickmacher2, + /obj/item/clothing/under/marine/fluff/fickmacher2, + ) + +/obj/item/storage/box/donator_kit/fridrich + donor_key = "fridrich" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/fridrich) + +/obj/item/storage/box/donator_kit/ghostdex + donor_key = "ghostdex" + donor_gear = list( + /obj/item/clothing/mask/cigarette/fluff/ghostdex, + /obj/item/tool/lighter/zippo/fluff/ghostdex, + ) + +/obj/item/storage/box/donator_kit/graciegrace0 + donor_key = "graciegrace0" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/medicae_helmet, + /obj/item/clothing/suit/storage/marine/fluff/medicae_armor, + /obj/item/clothing/under/marine/fluff/medicae_jumpsuit, + ) + +/obj/item/storage/box/donator_kit/gromoi + donor_key = "gromoi" + donor_gear = list( + /obj/item/clothing/suit/storage/marine/fluff/gromi, + /obj/item/clothing/under/marine/fluff/gromi, + ) + +/obj/item/storage/box/donator_kit/haveatya + donor_key = "haveatya" + donor_gear = list( + /obj/item/clothing/glasses/fluff/haveatya, + /obj/item/clothing/head/helmet/marine/fluff/haveatya, + /obj/item/clothing/under/marine/fluff/turtleneck, //generic item + ) + +/obj/item/storage/box/donator_kit/jackmcintyre + donor_key = "jackmcintyre" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/jackmcintyre, + /obj/item/clothing/suit/storage/marine/fluff/jackmcintyre, + /obj/item/clothing/under/marine/fluff/jackmcintyre, + /obj/item/clothing/under/marine/fluff/jackmcintyre_alt, + ) + +/obj/item/storage/box/donator_kit/jdobbin49 + donor_key = "jdobbin49" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/jdobbin49) + +/obj/item/storage/box/donator_kit/jedijasun + donor_key = "jedijasun" + donor_gear = list(/obj/item/clothing/gloves/marine/fluff/jedijas) + +/obj/item/storage/box/donator_kit/johnkilla56 + donor_key = "johnkilla56" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/john56, + /obj/item/clothing/mask/fluff/john56, + /obj/item/clothing/suit/storage/marine/fluff/john56, + /obj/item/clothing/under/marine/fluff/john56, + ) + +/obj/item/storage/box/donator_kit/juninho77 + donor_key = "juninho77" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/juniho, + /obj/item/clothing/suit/storage/marine/fluff/juninho, + /obj/item/clothing/under/marine/fluff/juninho, + ) + +/obj/item/storage/box/donator_kit/kilinger + donor_key = "kilinger" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/goldshieldberet) + +/obj/item/storage/box/donator_kit/kyrac + donor_key = "kyrac" + donor_gear = list( + /obj/item/clothing/under/marine/fluff/turtleneck, + /obj/item/clothing/glasses/fluff/eyepatch, + ) + +/obj/item/storage/box/donator_kit/laser243 + donor_key = "laser243" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/laser243, + /obj/item/clothing/suit/storage/marine/fluff/laser243, + ) + +/obj/item/storage/box/donator_kit/leondark16 + donor_key = "leondark16" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/leondark) + +/obj/item/storage/box/donator_kit/lestatanderson + donor_key = "lestatanderson" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/cia) + +/obj/item/storage/box/donator_kit/limodish + donor_key = "limodish" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/limo, + /obj/item/clothing/mask/fluff/limo, + /obj/item/clothing/suit/storage/marine/fluff/limo, + /obj/item/clothing/under/marine/fluff/turtleneck, //generic item + ) + +/obj/item/storage/box/donator_kit/lostmixup + donor_key = "lostmixup" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/lostmixup, + /obj/item/clothing/mask/fluff/lostmixup, + /obj/item/clothing/suit/storage/marine/fluff/lostmixup, + ) + +/obj/item/storage/box/donator_kit/markvalentine + donor_key = "markvalentine" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/valentine, + /obj/item/clothing/suit/storage/marine/fluff/valentine, + /obj/item/clothing/under/marine/fluff/valentine, + ) + +/obj/item/storage/box/donator_kit/mitii + donor_key = "mitii" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/mitii, + /obj/item/clothing/suit/storage/marine/fluff/mitii, + /obj/item/storage/backpack/marine/fluff/mitii, + ) + +/obj/item/storage/box/donator_kit/mrbark45 + donor_key = "mrbark45" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/bark) + +/obj/item/storage/box/donator_kit/nickiskool + donor_key = "nickiskool" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/nickiskool, + /obj/item/clothing/suit/storage/marine/fluff/nickiskool, + /obj/item/clothing/under/marine/fluff/nickiskool, + ) + +/obj/item/storage/box/donator_kit/ningajai + donor_key = "ningajai" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/ningajai) + +/obj/item/storage/box/donator_kit/obeystylez + donor_key = "obeystylez" + donor_gear = list( + /obj/item/clothing/gloves/black/obey, + /obj/item/clothing/mask/fluff/balaclava, //generic item + /obj/item/clothing/suit/storage/marine/fluff/obey, + /obj/item/clothing/under/marine/fluff/turtleneck, //generic item + ) + +/obj/item/storage/box/donator_kit/officialjake + donor_key = "officialjake" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/officialjake) + +/obj/item/storage/box/donator_kit/oneonethreeeight + donor_key = "oneonethreeeight" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/oneonethreeeight, + /obj/item/clothing/suit/storage/marine/fluff/oneonethreeeight, + /obj/item/clothing/under/marine/fluff/oneonethreeeight, + ) + +/obj/item/storage/box/donator_kit/paradox1i7 + donor_key = "paradox1i7" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/paradox, + /obj/item/clothing/suit/storage/marine/fluff/paradox, + /obj/item/clothing/under/marine/fluff/paradox, + ) + +/obj/item/storage/box/donator_kit/poops_buttly + donor_key = "poops_buttly" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/kaila, + /obj/item/clothing/suit/storage/marine/fluff/kaila, + ) + +/obj/item/storage/box/donator_kit/radicalscorpion + donor_key = "radicalscorpion" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/radical, + /obj/item/clothing/mask/fluff/balaclava, //generic item + /obj/item/clothing/suit/storage/marine/fluff/radical, + /obj/item/clothing/under/marine/fluff/radical, + ) + +/obj/item/storage/box/donator_kit/robin63 + donor_key = "robin63" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/robin) + +/obj/item/storage/box/donator_kit/rogue1131 + donor_key = "rogue1131" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/titus, + /obj/item/clothing/suit/storage/marine/fluff/titus, + ) + +/obj/item/storage/box/donator_kit/sadokist + donor_key = "sadokist" + donor_gear = list( + /obj/item/clothing/glasses/fluff/sadokist, + /obj/item/clothing/head/helmet/marine/fluff/sadokist, + /obj/item/clothing/suit/storage/marine/fluff/sadokist, + /obj/item/storage/backpack/marine/fluff/sadokist, + ) + +/obj/item/storage/box/donator_kit/sailordave + donor_key = "sailordave" + donor_gear = list(/obj/item/clothing/under/marine/fluff/sailordave) + +/obj/item/storage/box/donator_kit/sasoperative_elite //sasoperative has several sets + donor_key = "sasoperative" + kit_variant = "Elite" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/sas_elite, + /obj/item/clothing/mask/fluff/sas_elite, + /obj/item/clothing/suit/storage/marine/fluff/sas_elite, + /obj/item/clothing/under/marine/fluff/sas_elite, + ) + +/obj/item/storage/box/donator_kit/sasoperative_juggernaut + donor_key = "sasoperative" + kit_variant = "Juggernaut" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/sas_juggernaut_alt, + /obj/item/clothing/head/helmet/marine/fluff/sas_juggernaut, + /obj/item/clothing/suit/storage/marine/fluff/sas_juggernaut, + ) + +/obj/item/storage/box/donator_kit/sasoperative_legion + donor_key = "sasoperative" + kit_variant = "Legion" + donor_gear = list( + /obj/item/clothing/suit/storage/marine/fluff/sas_legion, + /obj/item/clothing/under/marine/fluff/sas_legion, + /obj/item/clothing/mask/fluff/sas_legion, + ) + +/obj/item/storage/box/donator_kit/seloc_aferah + donor_key = "seloc_aferah" + donor_gear = list(/obj/item/clothing/head/helmet/marine/fluff/deejay) + +/obj/item/storage/box/donator_kit/starscream123 + donor_key = "starscream123" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/starscream, + /obj/item/clothing/mask/fluff/starscream, + /obj/item/clothing/suit/storage/marine/fluff/starscream, + /obj/item/clothing/under/marine/fluff/starscream, + ) + +/obj/item/storage/box/donator_kit/steelpoint + donor_key = "steelpoint" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/steelpoint, + /obj/item/clothing/shoes/marine/fluff/steelpoint, + /obj/item/clothing/suit/storage/marine/fluff/steelpoint, + /obj/item/clothing/under/marine/fluff/steelpoint, + ) + +/obj/item/storage/box/donator_kit/stobarico + donor_key = "stobarico" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/stobarico) + +/obj/item/storage/box/donator_kit/theflagbearer + donor_key = "theflagbearer" + donor_gear = list(/obj/item/clothing/under/marine/fluff/leeeverett) + +/obj/item/storage/box/donator_kit/theultimatechimera + donor_key = "theultimatechimera" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/chimera, + /obj/item/clothing/suit/storage/marine/fluff/chimera, + ) + +/obj/item/storage/box/donator_kit/tophatpenguin_wooki //ckey tophatpenguin has two sets + donor_key = "tophatpenguin" + kit_variant = "Wooki" + donor_gear = list( + /obj/item/clothing/suit/storage/marine/fluff/penguin, + /obj/item/clothing/under/marine/fluff/wooki, + /obj/item/clothing/head/helmet/marine/fluff/penguin, + ) + +/obj/item/storage/box/donator_kit/tophatpenguin_santa + donor_key = "tophatpenguin" + kit_variant = "Santa" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/santahat, + /obj/item/clothing/suit/storage/marine/fluff/santa, + ) + +/obj/item/storage/box/donator_kit/totalanarchy + donor_key = "totalanarchy" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/totalanarchy, + /obj/item/clothing/mask/fluff/totalanarchy, + /obj/item/clothing/suit/storage/marine/fluff/totalanarchy, + /obj/item/clothing/under/marine/fluff/totalanarchy, + ) + +/obj/item/storage/box/donator_kit/tranquill + donor_key = "tranquill" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/tranquill) + +/obj/item/storage/box/donator_kit/trblackdragon + donor_key = "trblackdragon" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/trblackdragon, + /obj/item/clothing/suit/storage/marine/fluff/trblackdragon, + ) + +/obj/item/storage/box/donator_kit/tristan63 + donor_key = "tristan63" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/tristan, + /obj/item/clothing/suit/storage/marine/fluff/tristan, + /obj/item/clothing/under/marine/fluff/tristan, + ) + +/obj/item/storage/box/donator_kit/tyran68 + donor_key = "tyran68" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/tyran) + +/obj/item/storage/box/donator_kit/shotgunbill + donor_key = "shotgunbill" + donor_gear = list(/obj/item/clothing/head/collectable/petehat) + +/obj/item/storage/box/donator_kit/vintagepalmer + donor_key = "vintagepalmer" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/vintage, + /obj/item/clothing/shoes/marine/fluff/vintage, + /obj/item/clothing/suit/storage/marine/fluff/vintage, + /obj/item/clothing/under/marine/fluff/vintage, + ) + +/obj/item/storage/box/donator_kit/whiteblood17 + donor_key = "whiteblood17" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/whiteblood17, + /obj/item/clothing/under/marine/fluff/whiteblood17, + ) + +/obj/item/storage/box/donator_kit/wrightthewrong + donor_key = "wrightthewrong" + donor_gear = list( + /obj/item/clothing/glasses/fluff/wright, + /obj/item/clothing/suit/storage/marine/fluff/wright, + /obj/item/clothing/under/marine/fluff/turtleneck, //generic item + ) + +/obj/item/storage/box/donator_kit/zegara + donor_key = "zegara" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/zegara) + +/obj/item/storage/box/donator_kit/zynax + donor_key = "zynax" + donor_gear = list( + /obj/item/clothing/mask/fluff/balaclava, //generic item + /obj/item/clothing/suit/storage/marine/fluff/Zynax, + /obj/item/clothing/under/marine/fluff/turtleneck, //generic item + /obj/item/clothing/under/marine/fluff/Zynax, + ) + +/obj/item/storage/box/donator_kit/mileswolfe + donor_key = "mileswolfe" + donor_gear = list(/obj/item/clothing/under/marine/fluff/mileswolfe) + +/obj/item/storage/box/donator_kit/killaninja12 + donor_key = "killaninja12" + donor_gear = list( + /obj/item/clothing/head/helmet/marine/fluff/killaninja12, + /obj/item/clothing/suit/storage/marine/fluff/killaninja12, + ) + +/obj/item/storage/box/donator_kit/noize + donor_key = "noize" + donor_gear = list(/obj/item/clothing/suit/storage/marine/fluff/forwardslashn) + +/obj/item/storage/box/donator_kit/deanthelis + donor_key = "deanthelis" + donor_gear = list(/obj/item/clothing/head/beret/marine/techofficer) diff --git a/code/modules/cm_marines/altitude_control_console.dm b/code/modules/cm_marines/altitude_control_console.dm index 15d3dbae4ebd..a8281806be10 100644 --- a/code/modules/cm_marines/altitude_control_console.dm +++ b/code/modules/cm_marines/altitude_control_console.dm @@ -38,6 +38,10 @@ GLOBAL_VAR_INIT(ship_alt, SHIP_ALT_MED) . = ..() START_PROCESSING(SSslowobj, src) +/obj/structure/machinery/computer/altitude_control_console/Destroy() + STOP_PROCESSING(SSslowobj, src) + return ..() + /obj/structure/machinery/computer/altitude_control_console/process() . = ..() var/temperature_change diff --git a/code/modules/cm_marines/anti_air.dm b/code/modules/cm_marines/anti_air.dm index cdc610982a18..fc67f9a2018d 100644 --- a/code/modules/cm_marines/anti_air.dm +++ b/code/modules/cm_marines/anti_air.dm @@ -23,6 +23,12 @@ var/obj/structure/anti_air_cannon/almayer_aa_cannon if(!almayer_aa_cannon) almayer_aa_cannon = src +/obj/structure/anti_air_cannon/Destroy() + . = ..() + if(almayer_aa_cannon == src) + almayer_aa_cannon = null + message_admins("Reference to almayer_aa_cannon is lost!") + /obj/structure/anti_air_cannon/ex_act() return @@ -37,6 +43,8 @@ var/obj/structure/anti_air_cannon/almayer_aa_cannon flags_atom = ON_BORDER|CONDUCT|FPRINT req_one_access = list(ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_COMMAND) + unacidable = TRUE + unslashable = TRUE /obj/structure/machinery/computer/aa_console/initialize_pass_flags(datum/pass_flags_container/PF) ..() @@ -94,6 +102,7 @@ var/obj/structure/anti_air_cannon/almayer_aa_cannon if(!almayer_aa_cannon) return + var/datum/ares_link/link = GLOB.ares_link switch(action) if("protect") almayer_aa_cannon.protecting_section = params["section_id"] @@ -101,10 +110,12 @@ var/obj/structure/anti_air_cannon/almayer_aa_cannon almayer_aa_cannon.protecting_section = "" return message_admins("[key_name(usr)] has set the AA to [html_encode(almayer_aa_cannon.protecting_section)].") + link.log_ares_antiair(usr, "Set AA to cover [html_encode(almayer_aa_cannon.protecting_section)].") . = TRUE if("deactivate") almayer_aa_cannon.protecting_section = "" message_admins("[key_name(usr)] has deactivated the AA cannon.") + link.log_ares_antiair(usr, "Deactivated Anti Air systems.") . = TRUE add_fingerprint(usr) diff --git a/code/modules/cm_marines/dropship_ammo.dm b/code/modules/cm_marines/dropship_ammo.dm index 42a7d2a9cfaf..d3d0266e5982 100644 --- a/code/modules/cm_marines/dropship_ammo.dm +++ b/code/modules/cm_marines/dropship_ammo.dm @@ -39,6 +39,15 @@ var/mob/source_mob var/combat_equipment = TRUE +/obj/structure/ship_ammo/attack_alien(mob/living/carbon/xenomorph/current_xenomorph) + if(unslashable) + return XENO_NO_DELAY_ACTION + current_xenomorph.animation_attack_on(src) + playsound(src, 'sound/effects/metalhit.ogg', 25, 1) + current_xenomorph.visible_message(SPAN_DANGER("[current_xenomorph] slashes at [src]!"), + SPAN_DANGER("You slash at [src]!"), null, 5, CHAT_TYPE_XENO_COMBAT) + update_health(rand(current_xenomorph.melee_damage_lower, current_xenomorph.melee_damage_upper)) + return XENO_ATTACK_ACTION /obj/structure/ship_ammo/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/powerloader_clamp)) @@ -278,9 +287,8 @@ /obj/structure/ship_ammo/rocket/widowmaker/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 300, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) //Your standard HE splash damage rocket. Good damage, good range, good speed, it's an all rounder - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 300, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Your standard HE splash damage rocket. Good damage, good range, good speed, it's an all rounder + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/banshee name = "\improper AGM-227 'Banshee'" @@ -292,10 +300,9 @@ /obj/structure/ship_ammo/rocket/banshee/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 175, 20, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) //Small explosive power with a small fall off for a big explosion range - fire_spread(impact, create_cause_data(initial(name), source_mob), 4, 15, 50, "#00b8ff") //Very intense but the fire doesn't last very long - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 175, 20, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Small explosive power with a small fall off for a big explosion range + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fire_spread), impact, create_cause_data(initial(name), source_mob), 4, 15, 50, "#00b8ff"), 0.5 SECONDS) //Very intense but the fire doesn't last very long + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/keeper name = "\improper GBU-67 'Keeper II'" @@ -308,9 +315,8 @@ /obj/structure/ship_ammo/rocket/keeper/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 450, 100, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, create_cause_data(initial(name), source_mob)) //Insane fall off combined with insane damage makes the Keeper useful for single targets, but very bad against multiple. - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 450, 100, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Insane fall off combined with insane damage makes the Keeper useful for single targets, but very bad against multiple. + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/harpoon name = "\improper AGM-84 'Harpoon'" @@ -324,9 +330,8 @@ //Looks kinda OP but all it can actually do is just to blow windows and some of other things out, cant do much damage. /obj/structure/ship_ammo/rocket/harpoon/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 150, 16, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 150, 16, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/napalm name = "\improper XN-99 'Napalm'" @@ -338,11 +343,25 @@ /obj/structure/ship_ammo/rocket/napalm/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 200, 25, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) - fire_spread(impact, create_cause_data(initial(name), source_mob), 6, 60, 30, "#EE6515") //Color changed into napalm's color to better convey how intense the fire actually is. - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 200, 25, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fire_spread), impact, create_cause_data(initial(name), source_mob), 6, 60, 30, "#EE6515"), 0.5 SECONDS) //Color changed into napalm's color to better convey how intense the fire actually is. + QDEL_IN(src, 0.5 SECONDS) + +/obj/structure/ship_ammo/rocket/thermobaric + name = "\improper BLU-200 'Dragons Breath'" + desc = "The BLU-200 Dragons Breath a thermobaric fuel-air bomb. The aerosolized fuel mixture creates a vacuum when ignited causing serious damage to those in its way." + icon_state = "fatty" + ammo_id = "f" + travelling_time = 50 + point_cost = 300 + fire_mission_delay = 4 +/obj/structure/ship_ammo/rocket/thermobaric/detonate_on(turf/impact) + impact.ceiling_debris_check(3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fire_spread), impact, create_cause_data(initial(name), source_mob), 4, 25, 50, "#c96500"), 0.5 SECONDS) //Very intense but the fire doesn't last very long + for(var/mob/living/carbon/victim in orange(5, impact)) + victim.throw_atom(impact, 3, 15, src, TRUE) // Implosion throws affected towards center of vacuum + QDEL_IN(src, 0.5 SECONDS) //minirockets diff --git a/code/modules/cm_marines/dropship_equipment.dm b/code/modules/cm_marines/dropship_equipment.dm index 66a632df99a5..3568f001c977 100644 --- a/code/modules/cm_marines/dropship_equipment.dm +++ b/code/modules/cm_marines/dropship_equipment.dm @@ -33,6 +33,16 @@ linked_console = null . = ..() +/obj/structure/dropship_equipment/attack_alien(mob/living/carbon/xenomorph/current_xenomorph) + if(unslashable) + return XENO_NO_DELAY_ACTION + current_xenomorph.animation_attack_on(src) + playsound(src, 'sound/effects/metalhit.ogg', 25, 1) + current_xenomorph.visible_message(SPAN_DANGER("[current_xenomorph] slashes at [src]!"), + SPAN_DANGER("You slash at [src]!"), null, 5, CHAT_TYPE_XENO_COMBAT) + update_health(rand(current_xenomorph.melee_damage_lower, current_xenomorph.melee_damage_upper)) + return XENO_ATTACK_ACTION + /obj/structure/dropship_equipment/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/powerloader_clamp)) var/obj/item/powerloader_clamp/PC = I @@ -246,6 +256,13 @@ deployed_turret.start_processing() deployed_turret.set_range() + deployed_turret.linked_cam = new(deployed_turret.loc, "[capitalize_first_letters(ship_base.name)] [capitalize_first_letters(name)]") + if (linked_shuttle.id == DROPSHIP_ALAMO) + deployed_turret.linked_cam.network = list(CAMERA_NET_ALAMO) + else if (linked_shuttle.id == DROPSHIP_NORMANDY) + deployed_turret.linked_cam.network = list(CAMERA_NET_NORMANDY) + + /obj/structure/dropship_equipment/sentry_holder/proc/undeploy_sentry() if(!deployed_turret) return @@ -257,8 +274,12 @@ deployed_turret.stop_processing() deployed_turret.unset_range() icon_state = "sentry_system_installed" + QDEL_NULL(deployed_turret.linked_cam) - +/obj/structure/dropship_equipment/sentry_holder/Destroy() + if(deployed_turret) + QDEL_NULL(deployed_turret.linked_cam) + . = ..() /// Holder for the dropship mannable machinegun system @@ -268,7 +289,7 @@ density = FALSE equip_categories = list(DROPSHIP_WEAPON, DROPSHIP_CREW_WEAPON) icon_state = "mg_system" - point_cost = 300 + point_cost = 50 var/deployment_cooldown var/obj/structure/machinery/m56d_hmg/mg_turret/dropship/deployed_mg combat_equipment = FALSE @@ -428,7 +449,7 @@ icon_state = "spotlights" desc = "A set of high-powered spotlights to illuminate large areas. Fits on electronics attach points of dropships. Moving this will require a powerloader." is_interactable = TRUE - point_cost = 300 + point_cost = 50 var/spotlights_cooldown var/brightness = 11 @@ -492,7 +513,7 @@ name = "\improper LZ detector" desc = "An electronic device linked to the dropship's camera system that lets you observe your landing zone mid-flight." icon_state = "lz_detector" - point_cost = 400 + point_cost = 50 var/obj/structure/machinery/computer/cameras/dropship/linked_cam_console /obj/structure/dropship_equipment/electronics/landing_zone_detector/update_equipment() @@ -620,7 +641,7 @@ ammo_travelling_time = max(ammo_travelling_time - 20, 10) break - msg_admin_niche("[key_name(user)] is direct-firing [SA] onto [selected_target] at ([target_turf.x],[target_turf.y],[target_turf.z]) (JMP LOC)") + msg_admin_niche("[key_name(user)] is direct-firing [SA] onto [selected_target] at ([target_turf.x],[target_turf.y],[target_turf.z]) [ADMIN_JMP(target_turf)]") if(ammo_travelling_time) var/total_seconds = max(round(ammo_travelling_time/10),1) for(var/i = 0 to total_seconds) @@ -899,7 +920,6 @@ - //on arrival we break any link /obj/structure/dropship_equipment/medevac_system/on_arrival() if(linked_stretcher) @@ -912,7 +932,7 @@ return if(!ship_base) //not installed return - if(!skillcheck(user, SKILL_PILOT, SKILL_PILOT_TRAINED)) + if(!skillcheck(user, SKILL_PILOT, SKILL_PILOT_TRAINED) && !skillcheck(user, SKILL_MEDICAL, SKILL_MEDICAL_DOCTOR)) to_chat(user, SPAN_WARNING(" You don't know how to use [src].")) return @@ -928,7 +948,7 @@ return if(!linked_stretcher) - to_chat(user, SPAN_WARNING("There seems to be no medevac stretcher connected to [src].")) + equipment_interact(user) return if(!is_ground_level(linked_stretcher.z)) @@ -943,7 +963,6 @@ activate_winch(user) - /obj/structure/dropship_equipment/medevac_system/proc/activate_winch(mob/user) set waitfor = 0 var/old_stretcher = linked_stretcher @@ -991,7 +1010,7 @@ flick("winched_stretcher", linked_stretcher) linked_stretcher.visible_message(SPAN_NOTICE("A winch hook falls from the sky and starts lifting [linked_stretcher] up.")) - medevac_cooldown = world.time + 600 + medevac_cooldown = world.time + DROPSHIP_MEDEVAC_COOLDOWN linked_stretcher.linked_medevac = null linked_stretcher = null @@ -1118,7 +1137,7 @@ name = "rappel deployment system" equip_categories = list(DROPSHIP_CREW_WEAPON) icon_state = "rappel_module_packaged" - point_cost = 500 + point_cost = 50 combat_equipment = FALSE var/harness = /obj/item/rappel_harness @@ -1237,3 +1256,25 @@ return FALSE return TRUE + +// used in the simulation room for cas runs, removed the sound and ammo depletion methods. +// copying code is definitely bad, but adding an unnecessary sim or not sim boolean check in the open_fire_firemission just doesn't seem right. +/obj/structure/dropship_equipment/weapon/proc/open_simulated_fire_firemission(obj/selected_target, mob/user = usr) + set waitfor = FALSE + var/turf/target_turf = get_turf(selected_target) + var/obj/structure/ship_ammo/SA = ammo_equipped //necessary because we nullify ammo_equipped when firing big rockets + var/ammo_accuracy_range = SA.accuracy_range + // no warning sound and no travel time + last_fired = world.time + + if(locate(/obj/structure/dropship_equipment/electronics/targeting_system) in linked_shuttle.equipments) ammo_accuracy_range = max(ammo_accuracy_range - 2, 0) + + ammo_accuracy_range /= 2 //buff for basically pointblanking the ground + + var/list/possible_turfs = list() + for(var/turf/TU in range(ammo_accuracy_range, target_turf)) + possible_turfs += TU + var/turf/impact = pick(possible_turfs) + sleep(3) + SA.source_mob = user + SA.detonate_on(impact) diff --git a/code/modules/cm_marines/equipment/gear.dm b/code/modules/cm_marines/equipment/gear.dm index 98e7dbcf49df..ff6c715b520b 100644 --- a/code/modules/cm_marines/equipment/gear.dm +++ b/code/modules/cm_marines/equipment/gear.dm @@ -58,6 +58,8 @@ var/is_animating = FALSE var/first_open = TRUE exit_stun = 0 + /// used to implement a delay before tarp can be entered again after opened (anti-exploit) + COOLDOWN_DECLARE(toggle_delay) /obj/structure/closet/bodybag/tarp/snow icon_state = "snowtarp_closed" @@ -91,9 +93,9 @@ exit_stun = 1 can_store_dead = TRUE -/obj/structure/closet/bodybag/tarp/reactive/scout/close() +/obj/structure/closet/bodybag/tarp/reactive/scout/close(mob/user) if(!skillcheck(usr, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL) && usr.skills.get_skill_level(SKILL_SPEC_WEAPONS) != SKILL_SPEC_SCOUT) - to_chat(usr, SPAN_WARNING("You don't seem to know how to use [src]...")) + to_chat(user, SPAN_WARNING("You don't seem to know how to use [src]...")) return . = ..() @@ -137,10 +139,14 @@ return /obj/structure/closet/bodybag/tarp/open() + COOLDOWN_START(src, toggle_delay, 3 SECONDS) //3 seconds must pass before tarp can be closed . = ..() handle_cloaking() -/obj/structure/closet/bodybag/tarp/close() +/obj/structure/closet/bodybag/tarp/close(mob/user) + if(!COOLDOWN_FINISHED(src, toggle_delay)) + to_chat(user, SPAN_WARNING("It is too soon to close [src]!")) + return FALSE . = ..() handle_cloaking() diff --git a/code/modules/cm_marines/equipment/guncases.dm b/code/modules/cm_marines/equipment/guncases.dm index ff4d8397be26..a9a3855a53e4 100644 --- a/code/modules/cm_marines/equipment/guncases.dm +++ b/code/modules/cm_marines/equipment/guncases.dm @@ -58,13 +58,15 @@ /obj/item/storage/box/guncase/lmg name = "\improper M41AE2 heavy pulse rifle case" desc = "A gun case containing the M41AE2 heavy pulse rifle. You can get additional ammunition at requisitions." - storage_slots = 3 + storage_slots = 5 can_hold = list(/obj/item/weapon/gun/rifle/lmg, /obj/item/ammo_magazine/rifle/lmg) /obj/item/storage/box/guncase/lmg/fill_preset_inventory() new /obj/item/weapon/gun/rifle/lmg(src) new /obj/item/ammo_magazine/rifle/lmg(src) new /obj/item/ammo_magazine/rifle/lmg/holo_target(src) + new /obj/item/attachable/flashlight + new /obj/item/attachable/bipod //------------ /obj/item/storage/box/guncase/m41aMK1 @@ -293,3 +295,47 @@ new /obj/item/weapon/gun/shotgun/double/cane(src) new /obj/item/ammo_magazine/handful/revolver/marksman/six_rounds(src) new /obj/item/ammo_magazine/handful/revolver/marksman/six_rounds(src) + +//Handgun case for Military police vendor three mag , a railflashligh and the handgun. + +//88 Mod 4 Combat Pistol +/obj/item/storage/box/guncase/mod88 + name = "\improper 88 Mod 4 Combat Pistol case" + desc = "A gun case containing an 88 Mod 4 Combat Pistol." + storage_slots = 5 + can_hold = list(/obj/item/attachable/flashlight, /obj/item/weapon/gun/pistol/mod88, /obj/item/ammo_magazine/pistol/mod88) + +/obj/item/storage/box/guncase/mod88/fill_preset_inventory() + new /obj/item/attachable/flashlight(src) + new /obj/item/weapon/gun/pistol/mod88(src) + new /obj/item/ammo_magazine/pistol/mod88(src) + new /obj/item/ammo_magazine/pistol/mod88(src) + new /obj/item/ammo_magazine/pistol/mod88(src) + +//M44 Combat Revolver +/obj/item/storage/box/guncase/m44 + name = "\improper M44 Combat Revolver case" + desc = "A gun case containing an M44 Combat Revolver." + storage_slots = 5 + can_hold = list(/obj/item/attachable/flashlight, /obj/item/weapon/gun/revolver/m44, /obj/item/ammo_magazine/revolver) + +/obj/item/storage/box/guncase/m44/fill_preset_inventory() + new /obj/item/attachable/flashlight(src) + new /obj/item/weapon/gun/revolver/m44(src) + new /obj/item/ammo_magazine/revolver(src) + new /obj/item/ammo_magazine/revolver(src) + new /obj/item/ammo_magazine/revolver(src) + +//M4A3 Service Pistol +/obj/item/storage/box/guncase/m4a3 + name = "\improper M4A3 Service Pistol case" + desc = "A gun case containing an M4A3 Service Pistol." + storage_slots = 5 + can_hold = list(/obj/item/attachable/flashlight, /obj/item/weapon/gun/pistol/m4a3, /obj/item/ammo_magazine/pistol) + +/obj/item/storage/box/guncase/m4a3/fill_preset_inventory() + new /obj/item/attachable/flashlight(src) + new /obj/item/weapon/gun/pistol/m4a3(src) + new /obj/item/ammo_magazine/pistol(src) + new /obj/item/ammo_magazine/pistol(src) + new /obj/item/ammo_magazine/pistol(src) diff --git a/code/modules/cm_marines/equipment/kit_boxes.dm b/code/modules/cm_marines/equipment/kit_boxes.dm index 611c90f04644..a552b8eb0927 100644 --- a/code/modules/cm_marines/equipment/kit_boxes.dm +++ b/code/modules/cm_marines/equipment/kit_boxes.dm @@ -161,10 +161,16 @@ icon_state = "spec_kit" var/list/allowed_roles_list = list(JOB_SQUAD_SPECIALIST, JOB_WO_SQUAD_SPECIALIST, JOB_WO_CREWMAN) + ///Used for cryo specs who already have "foxtrot" appended to their ID assignments + var/squad_assignment_update = TRUE + //this one is delivered via ASRS as a reward for DEFCON/techwebs/whatever else we will have /obj/item/spec_kit/asrs allowed_roles_list = list(JOB_SQUAD_MARINE, JOB_WO_SQUAD_MARINE) +/obj/item/spec_kit/cryo + squad_assignment_update = FALSE + /obj/item/spec_kit/get_examine_text(mob/user) . = ..() if(!ishuman(user) && !isobserver(user)) @@ -201,7 +207,7 @@ for(var/allowed_role in allowed_roles_list) if(user.job == allowed_role) - if(!skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_DEFAULT) && !skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL)) + if(!skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_TRAINED) && !skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL)) to_chat(user, SPAN_WARNING("You already have specialization, give this kit to someone else!")) return FALSE return TRUE @@ -210,7 +216,7 @@ var/selection = tgui_input_list(user, "Pick your specialist equipment type.", "Specialist Kit Selection", available_specialist_kit_boxes) if(!selection || QDELETED(src)) return FALSE - if(!skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_DEFAULT) && !skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL)) + if(!skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_TRAINED) && !skillcheckexplicit(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL)) to_chat(user, SPAN_WARNING("You already unwrapped your [name], give this one to someone else!")) return if(!available_specialist_kit_boxes[selection] || available_specialist_kit_boxes[selection] <= 0) @@ -252,7 +258,7 @@ user.skills.set_skill(SKILL_ENGINEER, SKILL_ENGINEER_TRAINED) if(specialist_assignment) user.put_in_hands(spec_box) - ID.set_assignment((user.assigned_squad ? (user.assigned_squad.name + " ") : "") + ID.assignment + " ([specialist_assignment])") + ID.set_assignment((user.assigned_squad && squad_assignment_update ? (user.assigned_squad.name + " ") : "") + ID.assignment + " ([specialist_assignment])") GLOB.data_core.manifest_modify(user.real_name, WEAKREF(user), ID.assignment) return TRUE return FALSE @@ -360,6 +366,17 @@ new /obj/item/ammo_magazine/rifle/m4ra/ap(src) new /obj/item/ammo_magazine/rifle/m4ra/ap(src) +/obj/item/storage/box/kit/m41a_kit + name = "\improper M41A Rifle Kit" + pro_case_overlay = "pursuit" + +/obj/item/storage/box/kit/m41a_kit/fill_preset_inventory() + new /obj/item/weapon/gun/rifle/m41a(src) + new /obj/item/attachable/angledgrip(src) + new /obj/item/attachable/suppressor(src) + new /obj/item/attachable/extended_barrel(src) + new /obj/item/ammo_magazine/rifle/ap(src) + new /obj/item/ammo_magazine/rifle/ap(src) /obj/item/storage/box/kit/heavy_support name = "\improper Forward HPR Shield Kit" @@ -427,8 +444,6 @@ new /obj/item/storage/box/m94/signal(src) new /obj/item/device/binoculars/range/designator(src) new /obj/item/device/encryptionkey/jtac(src) - new /obj/item/storage/backpack/marine/satchel/rto/small(src) - /obj/item/storage/box/kit/mini_intel name = "\improper Field Intelligence Support Kit" diff --git a/code/modules/cm_marines/equipment/maps.dm b/code/modules/cm_marines/equipment/maps.dm index 7f84d3843251..f41c8d6f971b 100644 --- a/code/modules/cm_marines/equipment/maps.dm +++ b/code/modules/cm_marines/equipment/maps.dm @@ -23,8 +23,11 @@ var/wikiurl = CONFIG_GET(string/wikiurl) if(wikiurl) dat = {" + + +