diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000000..34b663112cc2 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,43 @@ +Kilo Station: + - changed-files: + - any-glob-to-any-file: '_maps/map_files/KiloStation/KiloStation.dmm' + +Lima Station: + - changed-files: + - any-glob-to-any-file: '_maps/map_files/LimaStation/LimaStation.dmm' + +Pubby Station: + - changed-files: + - any-glob-to-any-file: '_maps/map_files/PubbyStation/PubbyStation.dmm' + +Map: + - changed-files: + - any-glob-to-any-file: '_maps/**' + +Non-Module Code: + - changed-files: + - any-glob-to-any-file: 'code/**' + +Modularity Suggested: + - changed-files: + - any-glob-to-any-file: 'icons/**' + +Sprites: + - changed-files: + - any-glob-to-any-file: ['maplestation_modules/icons/**', 'sprites/**'] + +Sounds: + - changed-files: + - any-glob-to-any-file: ['maplestation_modules/sounds/**', 'sounds/**'] + +Story Content: + - changed-files: + - any-glob-to-any-file: 'maplestation_modules/story_content/**' + +Maintenance: + - changed-files: + - any-glob-to-any-file: ['.github/**', 'tools/**', '.vscode/**'] + +Cherry Picked: + - changed-files: + - any-glob-to-any-file: 'tgstation.dme' diff --git a/.github/workflows/auto_changelog.yml b/.github/workflows/auto_changelog.yml index 13b580547011..f47c2936980f 100644 --- a/.github/workflows/auto_changelog.yml +++ b/.github/workflows/auto_changelog.yml @@ -14,7 +14,7 @@ jobs: if: github.event.pull_request.merged == true steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run auto changelog uses: actions/github-script@v6 with: diff --git a/.github/workflows/autowiki.yml b/.github/workflows/autowiki.yml index 91ab12cdb19f..82d164e0c7c2 100644 --- a/.github/workflows/autowiki.yml +++ b/.github/workflows/autowiki.yml @@ -20,10 +20,10 @@ jobs: echo "SECRETS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT - name: Checkout if: steps.secrets_set.outputs.SECRETS_ENABLED - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Restore BYOND cache if: steps.secrets_set.outputs.SECRETS_ENABLED - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/BYOND key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }} diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index c676c446b843..8fbe05fa94dc 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -22,44 +22,44 @@ jobs: group: run_linters-${{ github.head_ref || github.run_id }} cancel-in-progress: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Restore SpacemanDMM cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/SpacemanDMM key: ${{ runner.os }}-spacemandmm-${{ hashFiles('dependencies.sh') }} restore-keys: | ${{ runner.os }}-spacemandmm- - name: Restore Yarn cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: tgui/.yarn/cache key: ${{ runner.os }}-yarn-${{ hashFiles('tgui/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- - name: Restore Node cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.nvm key: ${{ runner.os }}-node-${{ hashFiles('dependencies.sh') }} restore-keys: | ${{ runner.os }}-node- - name: Restore Bootstrap cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: tools/bootstrap/.cache key: ${{ runner.os }}-bootstrap-${{ hashFiles('tools/requirements.txt') }} restore-keys: | ${{ runner.os }}-bootstrap- - name: Restore Rust cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cargo key: ${{ runner.os }}-rust-${{ hashFiles('tools/ci/ci_dependencies.sh')}} restore-keys: | ${{ runner.os }}-rust- - name: Restore Cutter cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: tools/icon_cutter/cache key: ${{ runner.os }}-cutter-${{ hashFiles('dependencies.sh') }} @@ -127,9 +127,9 @@ jobs: group: compile_all_maps-${{ github.head_ref || github.run_id }} cancel-in-progress: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Restore BYOND cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/BYOND key: ${{ runner.os }}-byond @@ -156,7 +156,7 @@ jobs: group: find_all_maps-${{ github.head_ref || github.run_id }} cancel-in-progress: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Find Maps id: map_finder run: | @@ -223,10 +223,12 @@ jobs: name: Compare Screenshot Tests runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - name: Setup directory + run: mkdir -p artifacts # If we ever add more artifacts, this is going to break, but it'll be obvious. - name: Download screenshot tests - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts - name: ls -R @@ -247,7 +249,7 @@ jobs: echo ${{ github.event.pull_request.number }} > artifacts/screenshot_comparisons/pull_request_number.txt - name: Upload bad screenshots if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bad-screenshots path: artifacts/screenshot_comparisons @@ -261,9 +263,9 @@ jobs: group: test_windows-${{ github.head_ref || github.run_id }} cancel-in-progress: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Restore Yarn cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: tgui/.yarn/cache key: ${{ runner.os }}-yarn-${{ hashFiles('tgui/yarn.lock') }} diff --git a/.github/workflows/codeowner_reviews.yml b/.github/workflows/codeowner_reviews.yml index ed06f9b8a99d..cffab706d610 100644 --- a/.github/workflows/codeowner_reviews.yml +++ b/.github/workflows/codeowner_reviews.yml @@ -12,7 +12,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so the job can access it - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 #Parse the Codeowner file on non draft PRs - name: CodeOwnersParser diff --git a/.github/workflows/compile_changelogs.yml b/.github/workflows/compile_changelogs.yml index 64d4968ec88a..e1b8774905f1 100644 --- a/.github/workflows/compile_changelogs.yml +++ b/.github/workflows/compile_changelogs.yml @@ -31,7 +31,7 @@ jobs: sudo apt-get install dos2unix - name: "Checkout" if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 25 persist-credentials: false diff --git a/.github/workflows/docker_publish.yml b/.github/workflows/docker_publish.yml index c9d30e846f93..6daec1ded105 100644 --- a/.github/workflows/docker_publish.yml +++ b/.github/workflows/docker_publish.yml @@ -8,7 +8,7 @@ jobs: if: ( !contains(github.event.head_commit.message, '[ci skip]') ) runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build and Publish Docker Image to Registry uses: elgohr/Publish-Docker-Github-Action@v5 diff --git a/.github/workflows/gbp.yml b/.github/workflows/gbp.yml index ef782f398143..221d0462e257 100644 --- a/.github/workflows/gbp.yml +++ b/.github/workflows/gbp.yml @@ -16,7 +16,7 @@ jobs: echo "ACTIONS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT - name: Checkout if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup git if: steps.value_holder.outputs.ACTIONS_ENABLED run: | @@ -24,7 +24,7 @@ jobs: git config --global user.email "<>" - name: Checkout alternate branch if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: "gbp-balances" # The branch name path: gbp-balances diff --git a/.github/workflows/gbp_collect.yml b/.github/workflows/gbp_collect.yml index a180cb9b8ef4..4dd327abecd6 100644 --- a/.github/workflows/gbp_collect.yml +++ b/.github/workflows/gbp_collect.yml @@ -18,7 +18,7 @@ jobs: echo "ACTIONS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT - name: Checkout if: steps.value_holder.outputs.ACTIONS_ENABLED - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup git if: steps.value_holder.outputs.ACTIONS_ENABLED run: | @@ -26,7 +26,7 @@ jobs: 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 + uses: actions/checkout@v4 with: ref: "gbp-balances" # The branch name path: gbp-balances diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml index b8d0dd372f5e..2ffef7221838 100644 --- a/.github/workflows/generate_documentation.yml +++ b/.github/workflows/generate_documentation.yml @@ -13,9 +13,9 @@ jobs: runs-on: ubuntu-22.04 concurrency: gen-docs steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/SpacemanDMM key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }} diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000000..65b8c6c66dd7 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,13 @@ +name: "Pull Request Labeler" +on: + pull_request_target: + types: [opened, synchronize] + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 diff --git a/.github/workflows/remove_guide_comments.yml b/.github/workflows/remove_guide_comments.yml index d5d405909e21..e3a4ac3feda0 100644 --- a/.github/workflows/remove_guide_comments.yml +++ b/.github/workflows/remove_guide_comments.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Remove guide comments uses: actions/github-script@v6 with: diff --git a/.github/workflows/rerun_flaky_tests.yml b/.github/workflows/rerun_flaky_tests.yml index 24c3ec95197d..7f498de14430 100644 --- a/.github/workflows/rerun_flaky_tests.yml +++ b/.github/workflows/rerun_flaky_tests.yml @@ -10,7 +10,7 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.run_attempt == 1 }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Rerun flaky tests uses: actions/github-script@v6 with: @@ -22,7 +22,7 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.run_attempt == 2 }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Report flaky tests uses: actions/github-script@v6 with: diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index f77dfd14de49..9bf2140d7601 100644 --- a/.github/workflows/run_integration_tests.yml +++ b/.github/workflows/run_integration_tests.yml @@ -28,9 +28,9 @@ jobs: - 3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Restore BYOND cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/BYOND key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }} @@ -64,9 +64,9 @@ jobs: bash tools/ci/run_server.sh ${{ inputs.map }} - name: Upload screenshot tests if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: test_artifacts_${{ inputs.map }} + name: test_artifacts_${{ inputs.map }}_${{ inputs.major }}_${{ inputs.minor }} path: data/screenshots_new/ retention-days: 1 - name: Check client Compatibility diff --git a/.github/workflows/show_screenshot_test_results.yml b/.github/workflows/show_screenshot_test_results.yml index f1f1dec2649d..c61d09fa8905 100644 --- a/.github/workflows/show_screenshot_test_results.yml +++ b/.github/workflows/show_screenshot_test_results.yml @@ -25,7 +25,7 @@ jobs: echo "SECRETS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT - name: Checkout if: steps.secrets_set.outputs.SECRETS_ENABLED - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Prepare module if: steps.secrets_set.outputs.SECRETS_ENABLED run: | diff --git a/.github/workflows/test_merge_bot.yml b/.github/workflows/test_merge_bot.yml index 4eb62752c065..c77e50779441 100644 --- a/.github/workflows/test_merge_bot.yml +++ b/.github/workflows/test_merge_bot.yml @@ -23,7 +23,7 @@ jobs: echo "GET_TEST_MERGES_URL=$SECRET_EXISTS" >> $GITHUB_OUTPUT - name: Checkout if: steps.secrets_set.outputs.GET_TEST_MERGES_URL - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Prepare module if: steps.secrets_set.outputs.GET_TEST_MERGES_URL run: | diff --git a/.github/workflows/tgs_test.yml b/.github/workflows/tgs_test.yml index 6a9316f493a1..bd538307aa3f 100644 --- a/.github/workflows/tgs_test.yml +++ b/.github/workflows/tgs_test.yml @@ -62,7 +62,7 @@ jobs: dotnet-version: 8.0.x - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Test TGS Integration run: dotnet run -c Release --project tools/tgs_test ${{ github.repository }} /tgs_instances/tgstation ${{ env.TGS_API_PORT }} ${{ github.event.pull_request.head.sha || github.sha }} ${{ secrets.GITHUB_TOKEN }} ${{ env.PR_NUMBER }} diff --git a/.github/workflows/update_tgs_dmapi.yml b/.github/workflows/update_tgs_dmapi.yml index aae81f7e0d87..15d45b7935f0 100644 --- a/.github/workflows/update_tgs_dmapi.yml +++ b/.github/workflows/update_tgs_dmapi.yml @@ -11,7 +11,7 @@ jobs: name: Update the TGS DMAPI steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Branch run: | diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index d1c19e29440d..c388e407b116 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -133,6 +133,7 @@ #define SPEECH_FILTERPROOF 8 #define SPEECH_RANGE 9 #define SPEECH_SAYMODE 10 + #define SPEECH_MODS 11 ///from /mob/say_dead(): (mob/speaker, message) #define COMSIG_MOB_DEADSAY "mob_deadsay" @@ -239,3 +240,6 @@ /// from /mob/proc/slip(): (knockdown_amonut, obj/slipped_on, lube_flags [mobs.dm], paralyze, force_drop) #define COMSIG_MOB_SLIPPED "mob_slipped" + +/// from /obj/item/reagent_containers/dropper/interact_with_atom(atom/target, mob/living/user, list/modifiers): (mob/living/user, atom/dropper, datum/reagents/reagents, fraction) +#define COMSIG_MOB_REAGENTS_DROPPED_INTO_EYES "mob_reagents_drop_into_eyes" diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm index c8b89b082a49..aadf760cd2f2 100644 --- a/code/__DEFINES/footsteps.dm +++ b/code/__DEFINES/footsteps.dm @@ -1,5 +1,6 @@ #define FOOTSTEP_WOOD "wood" #define FOOTSTEP_FLOOR "floor" +#define FOOTSTEP_TILES "tiles" #define FOOTSTEP_PLATING "plating" #define FOOTSTEP_CARPET "carpet" #define FOOTSTEP_SAND "sand" @@ -37,174 +38,327 @@ ///the name of the index key for priority #define STEP_SOUND_PRIORITY "step_sound_priority" -/* - -id = list( -list(sounds), -base volume, -extra range addition -) - - -*/ +// Indexes for footstep data +#define FOOTSTEP_SOUNDS 1 +#define FOOTSTEP_VOLUME 2 +#define FOOTSTEP_RANGE 3 GLOBAL_LIST_INIT(footstep, list( - FOOTSTEP_WOOD = list(list( - 'sound/effects/footstep/wood1.ogg', - 'sound/effects/footstep/wood2.ogg', - 'sound/effects/footstep/wood3.ogg', - 'sound/effects/footstep/wood4.ogg', - 'sound/effects/footstep/wood5.ogg'), 100, 0), - FOOTSTEP_FLOOR = list(list( - 'sound/effects/footstep/floor1.ogg', - 'sound/effects/footstep/floor2.ogg', - 'sound/effects/footstep/floor3.ogg', - 'sound/effects/footstep/floor4.ogg', - 'sound/effects/footstep/floor5.ogg'), 75, -1), - FOOTSTEP_PLATING = list(list( - 'sound/effects/footstep/plating1.ogg', - 'sound/effects/footstep/plating2.ogg', - 'sound/effects/footstep/plating3.ogg', - 'sound/effects/footstep/plating4.ogg', - 'sound/effects/footstep/plating5.ogg'), 100, 1), - FOOTSTEP_CARPET = list(list( - 'sound/effects/footstep/carpet1.ogg', - 'sound/effects/footstep/carpet2.ogg', - 'sound/effects/footstep/carpet3.ogg', - 'sound/effects/footstep/carpet4.ogg', - 'sound/effects/footstep/carpet5.ogg'), 75, -1), - FOOTSTEP_SAND = list(list( - 'sound/effects/footstep/asteroid1.ogg', - 'sound/effects/footstep/asteroid2.ogg', - 'sound/effects/footstep/asteroid3.ogg', - 'sound/effects/footstep/asteroid4.ogg', - 'sound/effects/footstep/asteroid5.ogg'), 75, 0), - FOOTSTEP_GRASS = list(list( - 'sound/effects/footstep/grass1.ogg', - 'sound/effects/footstep/grass2.ogg', - 'sound/effects/footstep/grass3.ogg', - 'sound/effects/footstep/grass4.ogg'), 75, 0), - FOOTSTEP_WATER = list(list( - 'sound/effects/footstep/water1.ogg', - 'sound/effects/footstep/water2.ogg', - 'sound/effects/footstep/water3.ogg', - 'sound/effects/footstep/water4.ogg'), 100, 1), - FOOTSTEP_LAVA = list(list( - 'sound/effects/footstep/lava1.ogg', - 'sound/effects/footstep/lava2.ogg', - 'sound/effects/footstep/lava3.ogg'), 100, 0), - FOOTSTEP_MEAT = list(list( - 'sound/effects/meatslap.ogg'), 100, 0), - FOOTSTEP_CATWALK = list(list( - 'sound/effects/footstep/catwalk1.ogg', - 'sound/effects/footstep/catwalk2.ogg', - 'sound/effects/footstep/catwalk3.ogg', - 'sound/effects/footstep/catwalk4.ogg', - 'sound/effects/footstep/catwalk5.ogg'), 100, 1), + FOOTSTEP_WOOD = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/wood1.ogg' = 1, + 'sound/effects/footstep/wood2.ogg' = 1, + 'sound/effects/footstep/wood3.ogg' = 1, + 'sound/effects/footstep/wood4.ogg' = 1, + 'sound/effects/footstep/wood5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_FLOOR = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/floor1.ogg' = 1, + 'sound/effects/footstep/floor2.ogg' = 1, + 'sound/effects/footstep/floor3.ogg' = 1, + 'sound/effects/footstep/floor4.ogg' = 1, + 'sound/effects/footstep/floor5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE -1, + ), + FOOTSTEP_PLATING = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/plating1.ogg' = 1, + 'sound/effects/footstep/plating2.ogg' = 1, + 'sound/effects/footstep/plating3.ogg' = 1, + 'sound/effects/footstep/plating4.ogg' = 1, + 'sound/effects/footstep/plating5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 1, + ), + FOOTSTEP_CARPET = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/carpet1.ogg' = 1, + 'sound/effects/footstep/carpet2.ogg' = 1, + 'sound/effects/footstep/carpet3.ogg' = 1, + 'sound/effects/footstep/carpet4.ogg' = 1, + 'sound/effects/footstep/carpet5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = -1, + ), + FOOTSTEP_SAND = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/asteroid1.ogg' = 1, + 'sound/effects/footstep/asteroid2.ogg' = 1, + 'sound/effects/footstep/asteroid3.ogg' = 1, + 'sound/effects/footstep/asteroid4.ogg' = 1, + 'sound/effects/footstep/asteroid5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_GRASS = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/grass1.ogg' = 1, + 'sound/effects/footstep/grass2.ogg' = 1, + 'sound/effects/footstep/grass3.ogg' = 1, + 'sound/effects/footstep/grass4.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_WATER = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/water1.ogg' = 1, + 'sound/effects/footstep/water2.ogg' = 1, + 'sound/effects/footstep/water3.ogg' = 1, + 'sound/effects/footstep/water4.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 1, + ), + FOOTSTEP_LAVA = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/lava1.ogg' = 1, + 'sound/effects/footstep/lava2.ogg' = 1, + 'sound/effects/footstep/lava3.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_MEAT = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/meatslap.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_CATWALK = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/catwalk1.ogg' = 1, + 'sound/effects/footstep/catwalk2.ogg' = 1, + 'sound/effects/footstep/catwalk3.ogg' = 1, + 'sound/effects/footstep/catwalk4.ogg' = 1, + 'sound/effects/footstep/catwalk5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 1, + ), + FOOTSTEP_TILES = list( + FOOTSTEP_SOUNDS = list( + 'maplestation_modules/sound/footstep/tile1.ogg' = 6, + 'maplestation_modules/sound/footstep/tile2.ogg' = 6, + 'maplestation_modules/sound/footstep/tile3.ogg' = 6, + 'maplestation_modules/sound/footstep/tile4.ogg' = 1, + ), + FOOTSTEP_VOLUME = 25, + FOOTSTEP_RANGE = 1, + ), )) //bare footsteps lists GLOBAL_LIST_INIT(barefootstep, list( - FOOTSTEP_WOOD_BAREFOOT = list(list( - 'sound/effects/footstep/woodbarefoot1.ogg', - 'sound/effects/footstep/woodbarefoot2.ogg', - 'sound/effects/footstep/woodbarefoot3.ogg', - 'sound/effects/footstep/woodbarefoot4.ogg', - 'sound/effects/footstep/woodbarefoot5.ogg'), 80, -1), - FOOTSTEP_HARD_BAREFOOT = list(list( - 'sound/effects/footstep/hardbarefoot1.ogg', - 'sound/effects/footstep/hardbarefoot2.ogg', - 'sound/effects/footstep/hardbarefoot3.ogg', - 'sound/effects/footstep/hardbarefoot4.ogg', - 'sound/effects/footstep/hardbarefoot5.ogg'), 80, -1), - FOOTSTEP_CARPET_BAREFOOT = list(list( - 'sound/effects/footstep/carpetbarefoot1.ogg', - 'sound/effects/footstep/carpetbarefoot2.ogg', - 'sound/effects/footstep/carpetbarefoot3.ogg', - 'sound/effects/footstep/carpetbarefoot4.ogg', - 'sound/effects/footstep/carpetbarefoot5.ogg'), 75, -2), - FOOTSTEP_SAND = list(list( - 'sound/effects/footstep/asteroid1.ogg', - 'sound/effects/footstep/asteroid2.ogg', - 'sound/effects/footstep/asteroid3.ogg', - 'sound/effects/footstep/asteroid4.ogg', - 'sound/effects/footstep/asteroid5.ogg'), 75, 0), - FOOTSTEP_GRASS = list(list( - 'sound/effects/footstep/grass1.ogg', - 'sound/effects/footstep/grass2.ogg', - 'sound/effects/footstep/grass3.ogg', - 'sound/effects/footstep/grass4.ogg'), 75, 0), - FOOTSTEP_WATER = list(list( - 'sound/effects/footstep/water1.ogg', - 'sound/effects/footstep/water2.ogg', - 'sound/effects/footstep/water3.ogg', - 'sound/effects/footstep/water4.ogg'), 100, 1), - FOOTSTEP_LAVA = list(list( - 'sound/effects/footstep/lava1.ogg', - 'sound/effects/footstep/lava2.ogg', - 'sound/effects/footstep/lava3.ogg'), 100, 0), - FOOTSTEP_MEAT = list(list( - 'sound/effects/meatslap.ogg'), 100, 0), + FOOTSTEP_WOOD_BAREFOOT = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/woodbarefoot1.ogg' = 1, + 'sound/effects/footstep/woodbarefoot2.ogg' = 1, + 'sound/effects/footstep/woodbarefoot3.ogg' = 1, + 'sound/effects/footstep/woodbarefoot4.ogg' = 1, + 'sound/effects/footstep/woodbarefoot5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 80, + FOOTSTEP_RANGE = -1, + ), + FOOTSTEP_HARD_BAREFOOT = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/hardbarefoot1.ogg' = 1, + 'sound/effects/footstep/hardbarefoot2.ogg' = 1, + 'sound/effects/footstep/hardbarefoot3.ogg' = 1, + 'sound/effects/footstep/hardbarefoot4.ogg' = 1, + 'sound/effects/footstep/hardbarefoot5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 80, + FOOTSTEP_RANGE = -1, + ), + FOOTSTEP_CARPET_BAREFOOT = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/carpetbarefoot1.ogg' = 1, + 'sound/effects/footstep/carpetbarefoot2.ogg' = 1, + 'sound/effects/footstep/carpetbarefoot3.ogg' = 1, + 'sound/effects/footstep/carpetbarefoot4.ogg' = 1, + 'sound/effects/footstep/carpetbarefoot5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = -2, + ), + FOOTSTEP_SAND = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/asteroid1.ogg' = 1, + 'sound/effects/footstep/asteroid2.ogg' = 1, + 'sound/effects/footstep/asteroid3.ogg' = 1, + 'sound/effects/footstep/asteroid4.ogg' = 1, + 'sound/effects/footstep/asteroid5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_GRASS = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/grass1.ogg' = 1, + 'sound/effects/footstep/grass2.ogg' = 1, + 'sound/effects/footstep/grass3.ogg' = 1, + 'sound/effects/footstep/grass4.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_WATER = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/water1.ogg' = 1, + 'sound/effects/footstep/water2.ogg' = 1, + 'sound/effects/footstep/water3.ogg' = 1, + 'sound/effects/footstep/water4.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 1, + ), + FOOTSTEP_LAVA = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/lava1.ogg' = 1, + 'sound/effects/footstep/lava2.ogg' = 1, + 'sound/effects/footstep/lava3.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_MEAT = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/meatslap.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0, + ), )) //claw footsteps lists GLOBAL_LIST_INIT(clawfootstep, list( - FOOTSTEP_WOOD_CLAW = list(list( - 'sound/effects/footstep/woodclaw1.ogg', - 'sound/effects/footstep/woodclaw2.ogg', - 'sound/effects/footstep/woodclaw3.ogg', - 'sound/effects/footstep/woodclaw2.ogg', - 'sound/effects/footstep/woodclaw1.ogg'), 90, 1), - FOOTSTEP_HARD_CLAW = list(list( - 'sound/effects/footstep/hardclaw1.ogg', - 'sound/effects/footstep/hardclaw2.ogg', - 'sound/effects/footstep/hardclaw3.ogg', - 'sound/effects/footstep/hardclaw4.ogg', - 'sound/effects/footstep/hardclaw1.ogg'), 90, 1), - FOOTSTEP_CARPET_BAREFOOT = list(list( - 'sound/effects/footstep/carpetbarefoot1.ogg', - 'sound/effects/footstep/carpetbarefoot2.ogg', - 'sound/effects/footstep/carpetbarefoot3.ogg', - 'sound/effects/footstep/carpetbarefoot4.ogg', - 'sound/effects/footstep/carpetbarefoot5.ogg'), 75, -2), - FOOTSTEP_SAND = list(list( - 'sound/effects/footstep/asteroid1.ogg', - 'sound/effects/footstep/asteroid2.ogg', - 'sound/effects/footstep/asteroid3.ogg', - 'sound/effects/footstep/asteroid4.ogg', - 'sound/effects/footstep/asteroid5.ogg'), 75, 0), - FOOTSTEP_GRASS = list(list( - 'sound/effects/footstep/grass1.ogg', - 'sound/effects/footstep/grass2.ogg', - 'sound/effects/footstep/grass3.ogg', - 'sound/effects/footstep/grass4.ogg'), 75, 0), - FOOTSTEP_WATER = list(list( - 'sound/effects/footstep/water1.ogg', - 'sound/effects/footstep/water2.ogg', - 'sound/effects/footstep/water3.ogg', - 'sound/effects/footstep/water4.ogg'), 100, 1), - FOOTSTEP_LAVA = list(list( - 'sound/effects/footstep/lava1.ogg', - 'sound/effects/footstep/lava2.ogg', - 'sound/effects/footstep/lava3.ogg'), 100, 0), - FOOTSTEP_MEAT = list(list( - 'sound/effects/meatslap.ogg'), 100, 0), + FOOTSTEP_WOOD_CLAW = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/woodclaw1.ogg' = 1, + 'sound/effects/footstep/woodclaw2.ogg' = 1, + 'sound/effects/footstep/woodclaw3.ogg' = 1, + 'sound/effects/footstep/woodclaw2.ogg' = 1, + 'sound/effects/footstep/woodclaw1.ogg' = 1, + ), + FOOTSTEP_VOLUME = 90, + FOOTSTEP_RANGE = 1, + ), + FOOTSTEP_HARD_CLAW = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/hardclaw1.ogg' = 1, + 'sound/effects/footstep/hardclaw2.ogg' = 1, + 'sound/effects/footstep/hardclaw3.ogg' = 1, + 'sound/effects/footstep/hardclaw4.ogg' = 1, + 'sound/effects/footstep/hardclaw1.ogg' = 1, + ), + FOOTSTEP_VOLUME = 90, + FOOTSTEP_RANGE = 1, + ), + FOOTSTEP_CARPET_BAREFOOT = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/carpetbarefoot1.ogg' = 1, + 'sound/effects/footstep/carpetbarefoot2.ogg' = 1, + 'sound/effects/footstep/carpetbarefoot3.ogg' = 1, + 'sound/effects/footstep/carpetbarefoot4.ogg' = 1, + 'sound/effects/footstep/carpetbarefoot5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = -2, + ), + FOOTSTEP_SAND = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/asteroid1.ogg' = 1, + 'sound/effects/footstep/asteroid2.ogg' = 1, + 'sound/effects/footstep/asteroid3.ogg' = 1, + 'sound/effects/footstep/asteroid4.ogg' = 1, + 'sound/effects/footstep/asteroid5.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_GRASS = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/grass1.ogg' = 1, + 'sound/effects/footstep/grass2.ogg' = 1, + 'sound/effects/footstep/grass3.ogg' = 1, + 'sound/effects/footstep/grass4.ogg' = 1, + ), + FOOTSTEP_VOLUME = 75, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_WATER = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/water1.ogg' = 1, + 'sound/effects/footstep/water2.ogg' = 1, + 'sound/effects/footstep/water3.ogg' = 1, + 'sound/effects/footstep/water4.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 1, + ), + FOOTSTEP_LAVA = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/lava1.ogg' = 1, + 'sound/effects/footstep/lava2.ogg' = 1, + 'sound/effects/footstep/lava3.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0), + , + FOOTSTEP_MEAT = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/meatslap.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0, + ), )) //heavy footsteps list GLOBAL_LIST_INIT(heavyfootstep, list( - FOOTSTEP_GENERIC_HEAVY = list(list( - 'sound/effects/footstep/heavy1.ogg', - 'sound/effects/footstep/heavy2.ogg'), 100, 2), - FOOTSTEP_WATER = list(list( - 'sound/effects/footstep/water1.ogg', - 'sound/effects/footstep/water2.ogg', - 'sound/effects/footstep/water3.ogg', - 'sound/effects/footstep/water4.ogg'), 100, 2), - FOOTSTEP_LAVA = list(list( - 'sound/effects/footstep/lava1.ogg', - 'sound/effects/footstep/lava2.ogg', - 'sound/effects/footstep/lava3.ogg'), 100, 0), - FOOTSTEP_MEAT = list(list( - 'sound/effects/meatslap.ogg'), 100, 0), + FOOTSTEP_GENERIC_HEAVY = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/heavy1.ogg' = 1, + 'sound/effects/footstep/heavy2.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 2, + ), + FOOTSTEP_WATER = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/water1.ogg' = 1, + 'sound/effects/footstep/water2.ogg' = 1, + 'sound/effects/footstep/water3.ogg' = 1, + 'sound/effects/footstep/water4.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 2, + ), + FOOTSTEP_LAVA = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/footstep/lava1.ogg' = 1, + 'sound/effects/footstep/lava2.ogg' = 1, + 'sound/effects/footstep/lava3.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0, + ), + FOOTSTEP_MEAT = list( + FOOTSTEP_SOUNDS = list( + 'sound/effects/meatslap.ogg' = 1, + ), + FOOTSTEP_VOLUME = 100, + FOOTSTEP_RANGE = 0, + ), )) - diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 1bd1d57a7c6b..0bd4afaf4c36 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -156,3 +156,8 @@ #define INFO_RESKIN "reskin" /// Handles which layer the item will be on, for accessories #define INFO_LAYER "layer" + +// Lipstick styles +#define UPPER_LIP "Upper" +#define MIDDLE_LIP "Middle" +#define LOWER_LIP "Lower" diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm index e870e9de7a64..d00eb55eb868 100644 --- a/code/__DEFINES/skills.dm +++ b/code/__DEFINES/skills.dm @@ -43,3 +43,9 @@ #define FISHING_SKILL_DIFFIULTY_EXP_MULT 0.015 ///How much exp one would gain per spent playing the fishing minigame at minimum difficulty. the time is multiplied by 0.1 because deciseconds... #define FISHING_SKILL_EXP_PER_SECOND (SKILL_EXP_LEGENDARY / (15 MINUTES * 0.1)) + +// Skillchip categories +//Various skillchip categories. Use these when setting which categories a skillchip restricts being paired with +//while using the SKILLCHIP_RESTRICTED_CATEGORIES flag +/// General related skillchip category +#define SKILLCHIP_CATEGORY_GENERAL "general" diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index 0eac83cf05cf..97a3eb392563 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -181,3 +181,9 @@ GLOBAL_LIST_INIT(announcer_keys, list( #define SFX_PORTAL_CREATED "portal_created" #define SFX_SCREECH "screech" #define SFX_MUFFLED_SPEECH "muffspeech" +#define SFX_LIQUID_POUR "liquid_pour" +#define SFX_SNORE_FEMALE "snore_female" +#define SFX_SNORE_MALE "snore_male" +#define SFX_MALE_SIGH "male_sigh" +#define SFX_FEMALE_SIGH "female_sigh" +#define SFX_WRITING_PEN "writing_pen" diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm index c303eebbcdc5..28cc90b5b331 100644 --- a/code/__DEFINES/text.dm +++ b/code/__DEFINES/text.dm @@ -108,3 +108,7 @@ #define SPLASH_FILE "splashes.json" ///File location for mother hallucination lines #define MOTHER_FILE "mother.json" + +#define ALPHABET list("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z") +#define VOWELS list("a", "e", "i", "o", "u") +#define CONSONANTS (ALPHABET - VOWELS) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index ba4a97fee6c9..0890ec3c380b 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1060,4 +1060,13 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait which means whatever has this is dancing by a dance machine #define TRAIT_DISCO_DANCER "disco_dancer" +/// Humans with this trait do not blink +#define TRAIT_PREVENT_BLINKING "prevent_blinking" + +/// Prevents animations for blinking from looping +#define TRAIT_PREVENT_BLINK_LOOPS "prevent_blink_loops" + +/// Mob doesn't get closed eyelids overlay when it gets knocked out cold or dies +#define TRAIT_NO_EYELIDS "no_eyelids" + // END TRAIT DEFINES diff --git a/code/__DEFINES/turfs.dm b/code/__DEFINES/turfs.dm index 7b972abc20cb..4f5b9215a783 100644 --- a/code/__DEFINES/turfs.dm +++ b/code/__DEFINES/turfs.dm @@ -110,3 +110,13 @@ * Finds the midpoint of two given turfs. */ #define TURF_MIDPOINT(a, b) (locate(((a.x + b.x) * 0.5), (a.y + b.y) * 0.5, (a.z + b.z) * 0.5)) + +/// Makes the set turf transparent +#define ADD_TURF_TRANSPARENCY(modturf, source) \ + if(!HAS_TRAIT(modturf, TURF_Z_TRANSPARENT_TRAIT)) { modturf.AddElement(/datum/element/turf_z_transparency) }; \ + ADD_TRAIT(modturf, TURF_Z_TRANSPARENT_TRAIT, (source)) + +/// Removes the transparency from the set turf +#define REMOVE_TURF_TRANSPARENCY(modturf, source) \ + REMOVE_TRAIT(modturf, TURF_Z_TRANSPARENT_TRAIT, (source)); \ + if(!HAS_TRAIT(modturf, TURF_Z_TRANSPARENT_TRAIT)) { modturf.RemoveElement(/datum/element/turf_z_transparency) } diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 36e2f6e08cd1..894d07987f71 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -1117,8 +1117,8 @@ GLOBAL_LIST_INIT(binary, list("0","1")) return word var/first_letter = copytext(word, 1, 2) var/first_two_letters = copytext(word, 1, 3) - var/first_word_is_vowel = (first_letter in list("a", "e", "i", "o", "u")) - var/second_word_is_vowel = (copytext(word, 2, 3) in list("a", "e", "i", "o", "u")) + var/first_word_is_vowel = (first_letter in VOWELS) + var/second_word_is_vowel = (copytext(word, 2, 3) in VOWELS) //If a word starts with a vowel add the word "way" at the end of the word. if(first_word_is_vowel) return word + pick("yay", "way", "hay") //in cultures around the world it's different, so heck lets have fun and make it random. should still be readable diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index a0a09cb5fe5d..646ea2c4c369 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -475,6 +475,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_XRAY_HEARING" = TRAIT_XRAY_HEARING, "TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION, "TRAIT_DISCO_DANCER" = TRAIT_DISCO_DANCER, + "TRAIT_PREVENT_BLINKING" = TRAIT_PREVENT_BLINKING, + "TRAIT_PREVENT_BLINK_LOOPS" = TRAIT_PREVENT_BLINK_LOOPS, + "TRAIT_NO_EYELIDS" = TRAIT_NO_EYELIDS, ), /obj/item = list( "TRAIT_APC_SHOCKING" = TRAIT_APC_SHOCKING, diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm index 533e8f1e8dd4..28b4e7d8dee6 100644 --- a/code/_onclick/hud/action_button.dm +++ b/code/_onclick/hud/action_button.dm @@ -3,6 +3,7 @@ var/datum/hud/our_hud var/actiontooltipstyle = "" screen_loc = null + mouse_over_pointer = MOUSE_HAND_POINTER /// The icon state of our active overlay, used to prevent re-applying identical overlays var/active_overlay_icon_state @@ -245,6 +246,7 @@ icon = 'icons/hud/64x16_actions.dmi' icon_state = "screen_gen_palette" screen_loc = ui_action_palette + mouse_over_pointer = MOUSE_HAND_POINTER var/datum/hud/our_hud var/expanded = FALSE /// Id of any currently running timers that set our color matrix @@ -370,6 +372,7 @@ GLOBAL_LIST_INIT(palette_removed_matrix, list(1.4,0,0,0, 0.7,0.4,0,0, 0.4,0,0.6, /atom/movable/screen/palette_scroll icon = 'icons/hud/screen_gen.dmi' screen_loc = ui_palette_scroll + mouse_over_pointer = MOUSE_HAND_POINTER /// How should we move the palette's actions? /// Positive scrolls down the list, negative scrolls back var/scroll_direction = 0 diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 5f687d196428..b565f4655d30 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -1,5 +1,6 @@ /atom/movable/screen/ai icon = 'icons/hud/screen_ai.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/ai/Click() if(isobserver(usr) || usr.incapacitated()) @@ -80,6 +81,7 @@ /atom/movable/screen/ai/alerts name = "Show Alerts" icon_state = "alerts" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/ai/alerts/Click() if(..()) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 33408dc80499..f307b67ec8e5 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -276,6 +276,7 @@ name = "Mind Control" desc = "Your mind has been hijacked! Click to view the mind control command." icon_state = ALERT_MIND_CONTROL + mouse_over_pointer = MOUSE_HAND_POINTER var/command /atom/movable/screen/alert/mind_control/Click() @@ -289,6 +290,7 @@ desc = "Something got lodged into your flesh and is causing major bleeding. It might fall out with time, but surgery is the safest way. \ If you're feeling frisky, examine yourself and click the underlined item to pull the object out." icon_state = ALERT_EMBEDDED_OBJECT + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/embeddedobject/Click() . = ..() @@ -326,6 +328,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." name = "On Fire" desc = "You're on fire. Stop, drop and roll to put the fire out or move to a vacuum area." icon_state = "fire" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/fire/Click() . = ..() @@ -344,6 +347,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /atom/movable/screen/alert/give // information set when the give alert is made icon_state = "default" + mouse_over_pointer = MOUSE_HAND_POINTER /// The offer we're linked to, yes this is suspiciously like a status effect alert var/datum/status_effect/offering/offer /// Additional text displayed in the description of the alert. @@ -515,6 +519,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." name = "Succumb" desc = "Shuffle off this mortal coil." icon_state = ALERT_SUCCUMB + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/succumb/Click() . = ..() @@ -803,6 +808,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." additional processing time to unlock more malfunction abilities." icon_state = ALERT_HACKING_APC timeout = 60 SECONDS + mouse_over_pointer = MOUSE_HAND_POINTER var/atom/target = null /atom/movable/screen/alert/hackingapc/Click() @@ -830,6 +836,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." desc = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!" icon_state = "template" timeout = 300 + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/revival/Click() . = ..() @@ -843,6 +850,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." desc = "This can be clicked on to perform an action." icon_state = "template" timeout = 30 SECONDS + mouse_over_pointer = MOUSE_HAND_POINTER /// Weakref to the target atom to use the action on var/datum/weakref/target_ref /// If we want to interact on click rather than jump/orbit @@ -868,6 +876,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." icon_state = "template" timeout = 30 SECONDS ghost_screentips = TRUE + mouse_over_pointer = MOUSE_HAND_POINTER /// If true you need to call START_PROCESSING manually var/show_time_left = FALSE /// MA for maptext showing time left for poll @@ -1018,6 +1027,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." name = "Buckled" desc = "You've been buckled to something. Click the alert to unbuckle unless you're handcuffed." icon_state = ALERT_BUCKLED + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/restrained/handcuffed name = "Handcuffed" @@ -1028,6 +1038,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." name = "Legcuffed" desc = "You're legcuffed, which slows you down considerably. Click the alert to free yourself." click_master = FALSE + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/restrained/Click() . = ..() @@ -1065,6 +1076,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." name = "Knotted Shoes" desc = "Someone tied your shoelaces together! Click the alert or your shoes to undo the knot." icon_state = ALERT_SHOES_KNOT + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/shoes/Click() . = ..() @@ -1083,6 +1095,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." name = "Unpossess" desc = "You are possessing an object. Click this alert to unpossess it." icon_state = "buckled" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/unpossess_object/Click() . = ..() diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm index be860caa1f02..81db71b0bee3 100644 --- a/code/_onclick/hud/blob_overmind.dm +++ b/code/_onclick/hud/blob_overmind.dm @@ -1,6 +1,7 @@ /atom/movable/screen/blob icon = 'icons/hud/blob.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/blob/MouseEntered(location,control,params) . = ..() diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index 99b04df90687..fa0a4732e6c2 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -1,5 +1,6 @@ /atom/movable/screen/ghost icon = 'icons/hud/screen_ghost.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/ghost/MouseEntered(location, control, params) . = ..() @@ -108,4 +109,3 @@ if (istype(O) && O.observetarget) return . = ..() - diff --git a/code/_onclick/hud/guardian.dm b/code/_onclick/hud/guardian.dm index ba1d8f4565e6..da2aae7e603c 100644 --- a/code/_onclick/hud/guardian.dm +++ b/code/_onclick/hud/guardian.dm @@ -101,6 +101,7 @@ /atom/movable/screen/guardian icon = 'icons/hud/guardian.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/guardian/manifest icon_state = "manifest" diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 2f6c0cca1f95..ebf8d03df51a 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -4,6 +4,7 @@ /atom/movable/screen/human/toggle name = "toggle" icon_state = "toggle" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/human/toggle/Click() @@ -26,6 +27,7 @@ /atom/movable/screen/human/equip name = "equip" icon_state = "act_equip" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/human/equip/Click() if(ismecha(usr.loc)) // stops inventory actions in a mech @@ -45,6 +47,7 @@ name = "current sting" screen_loc = ui_lingstingdisplay invisibility = INVISIBILITY_ABSTRACT + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/ling/sting/Click() if(isobserver(usr)) diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm index d0b428560eae..73f09366b018 100644 --- a/code/_onclick/hud/new_player.dm +++ b/code/_onclick/hud/new_player.dm @@ -91,8 +91,9 @@ screen_loc = "TOP,CENTER:-61" /atom/movable/screen/lobby/button + mouse_over_pointer = MOUSE_HAND_POINTER ///Is the button currently enabled? - var/enabled = TRUE + VAR_PROTECTED/enabled = TRUE ///Is the button currently being hovered over with the mouse? var/highlighted = FALSE /// The ref of the mob that owns this button. Only the owner can click on it. @@ -151,6 +152,7 @@ return FALSE enabled = status update_appearance(UPDATE_ICON) + mouse_over_pointer = enabled ? MOUSE_HAND_POINTER : MOUSE_INACTIVE_POINTER return TRUE ///Prefs menu @@ -226,12 +228,14 @@ icon = 'icons/hud/lobby/join.dmi' icon_state = "" //Default to not visible base_icon_state = "join_game" - enabled = FALSE + enabled = null // set in init /atom/movable/screen/lobby/button/join/Initialize(mapload, datum/hud/hud_owner) . = ..() + set_button_status(FALSE) switch(SSticker.current_state) if(GAME_STATE_PREGAME, GAME_STATE_STARTUP) + set_button_status(FALSE) RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(show_join_button)) if(GAME_STATE_SETTING_UP) set_button_status(TRUE) @@ -297,13 +301,14 @@ icon = 'icons/hud/lobby/observe.dmi' icon_state = "observe_disabled" base_icon_state = "observe" - enabled = FALSE + enabled = null // set in init /atom/movable/screen/lobby/button/observe/Initialize(mapload, datum/hud/hud_owner) . = ..() if(SSticker.current_state > GAME_STATE_STARTUP) set_button_status(TRUE) else + set_button_status(FALSE) RegisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME, PROC_REF(enable_observing)) /atom/movable/screen/lobby/button/observe/Click(location, control, params) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index e296a5fa13ee..bb22725067ce 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -1,5 +1,6 @@ /atom/movable/screen/robot icon = 'icons/hud/screen_cyborg.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/robot/module name = "cyborg module" @@ -309,6 +310,7 @@ name = "Alert Panel" icon = 'icons/hud/screen_ai.dmi' icon_state = "alerts" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/robot/alerts/Click() . = ..() diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 0cde55da3300..d9872ceba5bb 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -70,6 +70,7 @@ /atom/movable/screen/swap_hand plane = HUD_PLANE name = "swap hand" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/swap_hand/Click() // At this point in client Click() code we have passed the 1/10 sec check and little else @@ -90,6 +91,7 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "navigate" screen_loc = ui_navigate_menu + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/navigate/Click() if(!isliving(usr)) @@ -102,12 +104,14 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "craft" screen_loc = ui_crafting + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/area_creator name = "create new area" icon = 'icons/hud/screen_midnight.dmi' icon_state = "area_edit" screen_loc = ui_building + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/area_creator/Click() if(usr.incapacitated() || (isobserver(usr) && !isAdminGhostAI(usr))) @@ -123,6 +127,7 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "talk_wheel" screen_loc = ui_language_menu + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/language_menu/Click() usr.get_language_holder().open_language_menu(usr) @@ -251,6 +256,7 @@ plane = ABOVE_HUD_PLANE icon = 'icons/hud/screen_midnight.dmi' icon_state = "storage_close" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/close/Initialize(mapload, datum/hud/hud_owner, new_master) . = ..() @@ -268,6 +274,7 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_drop" plane = HUD_PLANE + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/drop/Click() if(usr.stat == CONSCIOUS) @@ -278,6 +285,7 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "combat_off" screen_loc = ui_combat_toggle + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/combattoggle/Initialize(mapload, datum/hud/hud_owner) . = ..() @@ -328,6 +336,7 @@ name = "run/walk toggle" icon = 'icons/hud/screen_midnight.dmi' icon_state = "running" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/mov_intent/Click() toggle(usr) @@ -354,6 +363,7 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "pull" base_icon_state = "pull" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/pull/Click() if(isobserver(usr)) @@ -369,6 +379,7 @@ icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_resist" plane = HUD_PLANE + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/resist/Click() if(isliving(usr)) @@ -381,6 +392,7 @@ icon_state = "act_rest" base_icon_state = "act_rest" plane = HUD_PLANE + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/rest/Click() if(isliving(usr)) @@ -465,6 +477,7 @@ name = "throw/catch" icon = 'icons/hud/screen_midnight.dmi' icon_state = "act_throw_off" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/throw_catch/Click() if(iscarbon(usr)) @@ -475,6 +488,7 @@ name = "damage zone" icon_state = "zone_sel" screen_loc = ui_zonesel + mouse_over_pointer = MOUSE_HAND_POINTER var/overlay_icon = 'icons/hud/screen_gen.dmi' var/static/list/hover_overlays_cache = list() var/hovering @@ -652,6 +666,7 @@ /atom/movable/screen/healthdoll name = "health doll" screen_loc = ui_healthdoll + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/healthdoll/Click() if (iscarbon(usr)) @@ -749,6 +764,7 @@ name = "mood" icon_state = "mood5" screen_loc = ui_mood + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/mood/attack_tk() return @@ -801,6 +817,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/splash) /atom/movable/screen/component_button + mouse_over_pointer = MOUSE_HAND_POINTER var/atom/movable/screen/parent /atom/movable/screen/component_button/Initialize(mapload, atom/movable/screen/parent) diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 1de3f900c8ca..94be90560614 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -222,6 +222,7 @@ SUBSYSTEM_DEF(air) cost_atoms = MC_AVERAGE(cost_atoms, TICK_DELTA_TO_MS(cached_cost)) resumed = FALSE + currentpart = SSAIR_PIPENETS SStgui.update_uis(SSair) //Lightning fast debugging motherfucker diff --git a/code/datums/bodypart_overlays/bodypart_overlay.dm b/code/datums/bodypart_overlays/bodypart_overlay.dm index 22f2b15f2ccd..58e77e0421e2 100644 --- a/code/datums/bodypart_overlays/bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/bodypart_overlay.dm @@ -9,11 +9,22 @@ ///Key of the icon states of all the sprite_datums for easy caching var/cache_key = "" + /// Whether the overlay blocks emissive light + var/blocks_emissive = EMISSIVE_BLOCK_UNIQUE + ///Wrapper for getting the proper image, colored and everything /datum/bodypart_overlay/proc/get_overlay(layer, obj/item/bodypart/limb) layer = bitflag_to_layer(layer) - . = get_image(layer, limb) - color_image(., layer, limb) + var/image/main_image = get_image(layer, limb) + color_image(main_image, layer, limb) + if(blocks_emissive == EMISSIVE_BLOCK_NONE || !limb) + return main_image + + var/list/all_images = list( + main_image, + emissive_blocker(main_image.icon, main_image.icon_state, limb, layer = main_image.layer, alpha = main_image.alpha) + ) + return all_images ///Generate the image. Needs to be overriden /datum/bodypart_overlay/proc/get_image(layer, obj/item/bodypart/limb) diff --git a/code/datums/components/clothing_dirt.dm b/code/datums/components/clothing_dirt.dm new file mode 100644 index 000000000000..40f0ddb07e24 --- /dev/null +++ b/code/datums/components/clothing_dirt.dm @@ -0,0 +1,88 @@ +/// This component applies tint to clothing when its exposed to pepperspray, used in /obj/item/clothing/mask/gas. + +/datum/component/clothing_dirt + /// Amount of dirt stacks on the clothing + var/dirtiness = 0 + +/datum/component/clothing_dirt/Initialize() + if(!isclothing(parent)) + return COMPONENT_INCOMPATIBLE + +/datum/component/clothing_dirt/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip)) + RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) + RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean)) + RegisterSignal(parent, COMSIG_ATOM_EXPOSE_REAGENTS, PROC_REF(on_expose), TRUE) + +/datum/component/clothing_dirt/UnregisterFromParent() + var/obj/item/clothing/clothing = parent + clothing.tint -= dirtiness + if(iscarbon(clothing.loc)) + var/mob/living/carbon/wearer = clothing.loc + wearer.update_tint() + UnregisterSignal(wearer, COMSIG_ATOM_EXPOSE_REAGENTS) + else + UnregisterSignal(parent, COMSIG_ATOM_EXPOSE_REAGENTS) + UnregisterSignal(parent, list( + COMSIG_ATOM_EXAMINE, + COMSIG_ITEM_EQUIPPED, + COMSIG_MOB_UNEQUIPPED_ITEM, + COMSIG_COMPONENT_CLEAN_ACT, + )) + return ..() + +/datum/component/clothing_dirt/proc/on_equip(datum/source, mob/user, slot) + SIGNAL_HANDLER + var/obj/item/clothing/clothing = parent + if (!(slot & clothing.slot_flags)) + return + UnregisterSignal(parent, COMSIG_ATOM_EXPOSE_REAGENTS) + RegisterSignal(user, COMSIG_ATOM_EXPOSE_REAGENTS, PROC_REF(on_expose), TRUE) + +/datum/component/clothing_dirt/proc/on_drop(datum/source, mob/holder) + SIGNAL_HANDLER + UnregisterSignal(holder, COMSIG_ATOM_EXPOSE_REAGENTS) + RegisterSignal(parent, COMSIG_ATOM_EXPOSE_REAGENTS, PROC_REF(on_expose), TRUE) + +/datum/component/clothing_dirt/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + if (dirtiness > 0) + examine_list += span_warning("It appears to be covered in some oily substance. Won't see much while wearing it until you wash it off.") + +/datum/component/clothing_dirt/proc/on_expose(atom/target, list/reagents, datum/reagents/source, methods) + SIGNAL_HANDLER + + var/mob/living/carbon/wearer + if(iscarbon(target)) + wearer = target + if(is_protected(wearer)) + return + + var/datum/reagent/consumable/condensedcapsaicin/pepper = locate() in reagents + if(isnull(pepper)) + return + + var/obj/item/clothing/clothing = parent + if (methods & (TOUCH | VAPOR)) + clothing.tint -= dirtiness + dirtiness = min(dirtiness + round(reagents[pepper] / 5), 3) + clothing.tint += dirtiness + if(!isnull(wearer)) + wearer.update_tint() + +/datum/component/clothing_dirt/proc/is_protected(mob/living/carbon/wearer) + return wearer.head && (wearer.head.flags_cover & PEPPERPROOF) + +/datum/component/clothing_dirt/proc/on_clean(datum/target, clean_types) + SIGNAL_HANDLER + var/obj/item/clothing/clothing = parent + var/mob/living/carbon/wearer + if(iscarbon(clothing.loc)) + wearer = clothing.loc + + if (clean_types & (CLEAN_WASH|CLEAN_SCRUB)) + clothing.tint -= dirtiness + dirtiness = 0 + if(!isnull(wearer)) + wearer.update_tint() diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm index c3ff4d12c7d9..bee610703564 100644 --- a/code/datums/components/cult_ritual_item.dm +++ b/code/datums/components/cult_ritual_item.dm @@ -370,7 +370,7 @@ var/area/summon_location = get_area(cultist) priority_announce( text = "Figments from an eldritch god are being summoned by [cultist.real_name] into [summon_location.get_original_area_name()] from an unknown dimension. Disrupt the ritual at all costs!", - sound = 'sound/ambience/antag/bloodcult/bloodcult_scribe.ogg', + sound = /*'sound/ambience/antag/bloodcult/bloodcult_scribe.ogg'*/ANNOUNCER_SPANOMALIES, sender_override = "[command_name()] Higher Dimensional Affairs", has_important_message = TRUE, ) diff --git a/code/datums/components/manual_blinking.dm b/code/datums/components/manual_blinking.dm index 67229a8b85f5..36762450a201 100644 --- a/code/datums/components/manual_blinking.dm +++ b/code/datums/components/manual_blinking.dm @@ -1,31 +1,51 @@ /datum/component/manual_blinking dupe_mode = COMPONENT_DUPE_UNIQUE - var/obj/item/organ/internal/eyes/E + var/obj/item/organ/internal/eyes/parent_eyes var/warn_grace = FALSE var/warn_dying = FALSE var/last_blink var/check_every = 20 SECONDS var/grace_period = 6 SECONDS - var/damage_rate = 1 // organ damage taken per tick - var/list/valid_emotes = list(/datum/emote/living/carbon/blink, /datum/emote/living/carbon/blink_r) - -/datum/component/manual_blinking/Initialize() + /// Organ damage taken per tick + var/damage_rate = 1 + /// How much saline needs to be dropper at once for it to count as "blinking" + var/min_saline = 1 + /// Do we display a message when adding/removing the component + var/display_message = TRUE + var/list/valid_emotes = list(/datum/emote/living/carbon/human/blink, /datum/emote/living/carbon/human/blink_r) + +/datum/component/manual_blinking/Initialize(damage_rate = 1, check_every = 20 SECONDS, grace_period = 6 SECONDS, display_message = TRUE) if(!iscarbon(parent)) return COMPONENT_INCOMPATIBLE - var/mob/living/carbon/C = parent - E = C.get_organ_slot(ORGAN_SLOT_EYES) + src.damage_rate = damage_rate + src.check_every = check_every + src.grace_period = grace_period + src.display_message = display_message - if(E) - START_PROCESSING(SSdcs, src) - last_blink = world.time - to_chat(C, span_notice("You suddenly realize you're blinking manually.")) + var/mob/living/carbon/carbon_parent = parent + ADD_TRAIT(carbon_parent, TRAIT_PREVENT_BLINK_LOOPS, REF(src)) + carbon_parent.update_body() + parent_eyes = carbon_parent.get_organ_slot(ORGAN_SLOT_EYES) + + if(!parent_eyes || IS_ROBOTIC_ORGAN(parent_eyes)) + return + + START_PROCESSING(SSdcs, src) + last_blink = world.time + if (display_message) + to_chat(carbon_parent, span_notice("You suddenly realize you're blinking manually.")) /datum/component/manual_blinking/Destroy(force) - E = null + REMOVE_TRAIT(parent, TRAIT_PREVENT_BLINK_LOOPS, REF(src)) + parent_eyes = null STOP_PROCESSING(SSdcs, src) - to_chat(parent, span_notice("You revert back to automatic blinking.")) + if (display_message) + to_chat(parent, span_notice("You revert back to automatic blinking.")) + var/mob/living/carbon/carbon_parent = parent + carbon_parent.cure_blind(REF(src)) + carbon_parent.update_body() return ..() /datum/component/manual_blinking/RegisterWithParent() @@ -34,13 +54,10 @@ RegisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(check_removed_organ)) RegisterSignal(parent, COMSIG_LIVING_REVIVE, PROC_REF(restart)) RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(pause)) + RegisterSignal(parent, COMSIG_MOB_REAGENTS_DROPPED_INTO_EYES, PROC_REF(on_dropper)) /datum/component/manual_blinking/UnregisterFromParent() - UnregisterSignal(parent, COMSIG_MOB_EMOTE) - UnregisterSignal(parent, COMSIG_CARBON_GAIN_ORGAN) - UnregisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN) - UnregisterSignal(parent, COMSIG_LIVING_REVIVE) - UnregisterSignal(parent, COMSIG_LIVING_DEATH) + UnregisterSignal(parent, list(COMSIG_MOB_EMOTE, COMSIG_CARBON_GAIN_ORGAN, COMSIG_CARBON_LOSE_ORGAN, COMSIG_LIVING_REVIVE, COMSIG_LIVING_DEATH, COMSIG_MOB_REAGENTS_DROPPED_INTO_EYES)) /datum/component/manual_blinking/proc/restart() SIGNAL_HANDLER @@ -53,41 +70,51 @@ STOP_PROCESSING(SSdcs, src) /datum/component/manual_blinking/process() - var/mob/living/carbon/C = parent - if(world.time > (last_blink + check_every + grace_period)) if(!warn_dying) - to_chat(C, span_userdanger("Your eyes begin to wither, you need to blink!")) + to_chat(parent, span_userdanger("Your eyes begin to wither, you need to blink!")) warn_dying = TRUE - - E.apply_organ_damage(damage_rate) + parent_eyes.apply_organ_damage(damage_rate) else if(world.time > (last_blink + check_every)) if(!warn_grace) - to_chat(C, span_danger("You feel a need to blink!")) + to_chat(parent, span_danger("You feel a need to blink!")) warn_grace = TRUE -/datum/component/manual_blinking/proc/check_added_organ(mob/who_cares, obj/item/organ/O) +/datum/component/manual_blinking/proc/check_added_organ(mob/who_cares, obj/item/organ/added_organ) SIGNAL_HANDLER - var/obj/item/organ/internal/eyes/new_eyes = O - - if(istype(new_eyes,/obj/item/organ/internal/eyes)) - E = new_eyes + if(istype(added_organ, /obj/item/organ/internal/eyes)) + parent_eyes = added_organ + if (IS_ROBOTIC_ORGAN(parent_eyes)) + parent_eyes = null + return + last_blink = world.time START_PROCESSING(SSdcs, src) -/datum/component/manual_blinking/proc/check_removed_organ(mob/who_cares, obj/item/organ/O) +/datum/component/manual_blinking/proc/check_removed_organ(mob/who_cares, obj/item/organ/removed_organ) SIGNAL_HANDLER - var/obj/item/organ/internal/eyes/bye_beyes = O // oh come on, that's pretty good - - if(istype(bye_beyes, /obj/item/organ/internal/eyes)) - E = null + if(removed_organ == parent_eyes) + parent_eyes = null STOP_PROCESSING(SSdcs, src) /datum/component/manual_blinking/proc/check_emote(mob/living/carbon/user, datum/emote/emote) SIGNAL_HANDLER - if(emote.type in valid_emotes) + if(!(emote.type in valid_emotes)) + return + + warn_grace = FALSE + warn_dying = FALSE + last_blink = world.time + user.become_blind(REF(src)) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living, remove_status_effect), /datum/status_effect/grouped/blindness, REF(src)), 0.15 SECONDS) + +/datum/component/manual_blinking/proc/on_dropper(datum/source, mob/living/user, atom/dropper, datum/reagents/reagents, fraction) + SIGNAL_HANDLER + + var/saline_amount = reagents.get_reagent_amount(/datum/reagent/medicine/salglu_solution) * fraction + if (saline_amount >= min_saline) warn_grace = FALSE warn_dying = FALSE last_blink = world.time diff --git a/code/datums/components/trader/trader.dm b/code/datums/components/trader/trader.dm index b10041385277..c8dd9331938a 100644 --- a/code/datums/components/trader/trader.dm +++ b/code/datums/components/trader/trader.dm @@ -174,7 +174,7 @@ Can accept both a type path, and an instance of a datum. Type path has priority. display_names["[initial(thing.name)]"] = thing if(!radial_icons_cache[thing]) - radial_icons_cache[thing] = image(icon = initial(thing.icon), icon_state = initial(thing.icon_state_preview) ? initial(thing.icon_state_preview) : initial(thing.icon_state)) + radial_icons_cache[thing] = image(icon = initial(thing.icon), icon_state = initial(thing.icon_state_preview) || initial(thing.icon_state)) var/image/item_image = radial_icons_cache[thing] product_info = products[thing] diff --git a/code/datums/elements/footstep.dm b/code/datums/elements/footstep.dm index d19ddfdbedd4..fda0f14d200e 100644 --- a/code/datums/elements/footstep.dm +++ b/code/datums/elements/footstep.dm @@ -123,7 +123,7 @@ var/turf_footstep = prepared_steps[footstep_type] if(isnull(turf_footstep) || !footstep_sounds[turf_footstep]) return - playsound(source.loc, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range, falloff_distance = 1, vary = sound_vary) + playsound(source.loc, pick_weight(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range, falloff_distance = 1, vary = sound_vary) /datum/element/footstep/proc/play_humanstep(mob/living/carbon/human/source, atom/oldloc, direction, forced, list/old_locs, momentum_change) SIGNAL_HANDLER @@ -174,7 +174,7 @@ // list returned by playsound() filled by client mobs who heard the footstep. given to play_fov_effect() var/list/heard_clients - var/picked_sound = pick(footstep_sounds[1]) + var/picked_sound = pick_weight(footstep_sounds[1]) var/picked_volume = footstep_sounds[2] * volume * volume_multiplier var/picked_range = footstep_sounds[3] + e_range + range_adjustment diff --git a/code/datums/elements/ignites_matches.dm b/code/datums/elements/ignites_matches.dm new file mode 100644 index 000000000000..9a954c0cbea8 --- /dev/null +++ b/code/datums/elements/ignites_matches.dm @@ -0,0 +1,41 @@ +/// Ignites matches swiped over it. +/datum/element/ignites_matches + +/datum/element/ignites_matches/Attach(datum/target) + . = ..() + RegisterSignal(target, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_interact)) + +/datum/element/ignites_matches/Detach(datum/source) + UnregisterSignal(source, COMSIG_ATOM_ITEM_INTERACTION) + return ..() + +/datum/element/ignites_matches/proc/on_interact(atom/source, mob/living/user, obj/item/match/match, ...) + SIGNAL_HANDLER + if(!istype(match) || match.lit || match.burnt || match.broken) + return NONE +// if(SHOULD_SKIP_INTERACTION(source, match, user)) +// return NONE + if(source.atom_storage && user.combat_mode) + return NONE + var/over_what_tp = source.loc == user ? "[user.p_their()] [source.name]" : source + var/over_what_fp = source.loc == user ? "your [source.name]" : source + if(prob(10)) + user.visible_message( + span_warning("[user] swipes [match] over [over_what_tp], but nothing happens."), + span_warning("You swipe [match] over [over_what_fp], but it fails to ignite."), + ) + return ITEM_INTERACT_SUCCESS + if(prob((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_HULK)) ? 33 : 2)) + user.visible_message( + span_warning("[user] swipes [match] over [over_what_tp], accidentally snapping it."), + span_warning("You swipe [match] over [over_what_fp] too fast, snapping it in half."), + ) + match.snap() + return ITEM_INTERACT_SUCCESS + + user.visible_message( + span_rose("[user] swipes [match] over [over_what_tp], igniting it."), + span_rose("You swipe [match] over [over_what_fp], igniting it."), + ) + match.matchignite() + return ITEM_INTERACT_SUCCESS diff --git a/code/datums/elements/turf_transparency.dm b/code/datums/elements/turf_transparency.dm index b050dd0866f0..fdf9bb96e197 100644 --- a/code/datums/elements/turf_transparency.dm +++ b/code/datums/elements/turf_transparency.dm @@ -186,8 +186,6 @@ GLOBAL_LIST_EMPTY(pillars_by_z) RegisterSignal(target, COMSIG_TURF_MULTIZ_DEL, PROC_REF(on_multiz_turf_del)) RegisterSignal(target, COMSIG_TURF_MULTIZ_NEW, PROC_REF(on_multiz_turf_new)) - ADD_TRAIT(our_turf, TURF_Z_TRANSPARENT_TRAIT, ELEMENT_TRAIT(type)) - if(!mapload) update_multi_z(our_turf) @@ -197,7 +195,6 @@ GLOBAL_LIST_EMPTY(pillars_by_z) clear_multiz(our_turf) UnregisterSignal(our_turf, list(COMSIG_TURF_MULTIZ_NEW, COMSIG_TURF_MULTIZ_DEL)) - REMOVE_TRAIT(our_turf, TURF_Z_TRANSPARENT_TRAIT, ELEMENT_TRAIT(type)) ///Updates the viscontents or underlays below this tile. /datum/element/turf_z_transparency/proc/update_multi_z(turf/our_turf) diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm index 396b902b73fe..46b641a077f1 100644 --- a/code/datums/materials/_material.dm +++ b/code/datums/materials/_material.dm @@ -152,7 +152,7 @@ Simple datum which is instanced once per type and is used for every object of sa O.clawfootstep = turf_sound_override + "claw" O.heavyfootstep = FOOTSTEP_GENERIC_HEAVY if(alpha < 255) - T.AddElement(/datum/element/turf_z_transparency) + ADD_TURF_TRANSPARENCY(T, MATERIAL_SOURCE(src)) setup_glow(T) return @@ -225,7 +225,7 @@ Simple datum which is instanced once per type and is used for every object of sa /datum/material/proc/on_removed_turf(turf/T, amount, material_flags) if(alpha < 255) - T.RemoveElement(/datum/element/turf_z_transparency) + REMOVE_TURF_TRANSPARENCY(T, MATERIAL_SOURCE(src)) // yeets glow T.UnregisterSignal(SSdcs, COMSIG_STARLIGHT_COLOR_CHANGED) T.set_light(0, 0, null) diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm index 4c78c1961043..d24870d6da6a 100644 --- a/code/datums/mutations/speech.dm +++ b/code/datums/mutations/speech.dm @@ -1,5 +1,7 @@ //These are all minor mutations that affect your speech somehow. //Individual ones aren't commented since their functions should be evident at a glance +// no they arent bro + /datum/mutation/human/nervousness name = "Nervousness" diff --git a/code/datums/quirks/negative_quirks/fluoride_stare.dm b/code/datums/quirks/negative_quirks/fluoride_stare.dm new file mode 100644 index 000000000000..f39e5a4cd1bf --- /dev/null +++ b/code/datums/quirks/negative_quirks/fluoride_stare.dm @@ -0,0 +1,38 @@ +/* +/datum/quirk/item_quirk/fluoride_stare + name = "Fluoride Stare" + desc = "You have lost your eyelids in a horrible accident, or so you tell others. You need to manually wet your eyes with a saline solution every once in a while!" + icon = FA_ICON_EYE_DROPPER + value = -6 + gain_text = span_danger("Your eyes feel itchy and dry...") + lose_text = span_notice("You realize that sudden darkness that has just enveloped you was just your eyelids growing back.") + medical_record_text = "Patient has lost their eyelids in a grueling accident." + hardcore_value = 6 + quirk_flags = QUIRK_HUMAN_ONLY + mail_goodies = list(/obj/item/reagent_containers/cup/bottle/salglu_solution, /obj/item/light/bulb) + +/datum/quirk/item_quirk/fluoride_stare/add_unique(client/client_source) + var/obj/item/reagent_containers/cup/bottle/salglu_solution/saline = new(get_turf(quirk_holder)) + give_item_to_holder(saline, list( + LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, + LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS, + )) + var/obj/item/reagent_containers/dropper/dropper = new(get_turf(quirk_holder)) + give_item_to_holder(dropper, list( + LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, + LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS, + )) + +/datum/quirk/item_quirk/fluoride_stare/add(client/client_source) + ADD_TRAIT(quirk_holder, TRAIT_NO_EYELIDS, QUIRK_TRAIT) + quirk_holder.AddComponent(/datum/component/manual_blinking, 1, 30 SECONDS, 10 SECONDS, FALSE) + +/datum/quirk/item_quirk/fluoride_stare/remove() + REMOVE_TRAIT(quirk_holder, TRAIT_NO_EYELIDS, QUIRK_TRAIT) + if (!HAS_TRAIT(quirk_holder, TRAIT_NO_EYELIDS)) + qdel(quirk_holder.GetComponent(/datum/component/manual_blinking)) +*/ diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index f4e70c637ea9..56bda0942bf6 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -243,7 +243,7 @@ var/mob/living/carbon/carbon_owner = owner carbon_owner.handle_dreams() - if(prob(2) && owner.health > owner.crit_threshold) + if(prob(8) && owner.health > owner.crit_threshold) owner.emote("snore") /atom/movable/screen/alert/status_effect/asleep @@ -889,6 +889,7 @@ name = "Ants!" desc = span_warning("JESUS FUCKING CHRIST! CLICK TO GET THOSE THINGS OFF!") icon_state = "antalert" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/ants/Click() var/mob/living/living = owner diff --git a/code/datums/status_effects/debuffs/hooked.dm b/code/datums/status_effects/debuffs/hooked.dm index 9280303209ab..5b2429240517 100644 --- a/code/datums/status_effects/debuffs/hooked.dm +++ b/code/datums/status_effects/debuffs/hooked.dm @@ -29,6 +29,7 @@ name = "Snagged By Hook" desc = "You're being caught like a fish by some asshat! Click to safely remove the hook or move away far enough to snap it off." icon_state = "hooked" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/hooked/Click() if(!owner.can_resist()) diff --git a/code/datums/status_effects/debuffs/strandling.dm b/code/datums/status_effects/debuffs/strandling.dm index 6050a3df304d..648ed65f81c3 100644 --- a/code/datums/status_effects/debuffs/strandling.dm +++ b/code/datums/status_effects/debuffs/strandling.dm @@ -88,6 +88,7 @@ desc = "Strands of Durathread are wrapped around your neck, preventing you from breathing! Click this icon to remove the strand." icon_state = "his_grace" alerttooltipstyle = "hisgrace" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/strandling/Click(location, control, params) . = ..() diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 84f30ab7855e..009c4c61102e 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -150,6 +150,7 @@ name = "Holding Up" desc = "You're currently pointing a gun at someone. Click to cancel." icon_state = "aimed" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/holdup/Click(location, control, params) . = ..() @@ -332,6 +333,7 @@ name = "Surrender" desc = "Looks like you're in trouble now, bud. Click here to surrender. (Warning: You will be incapacitated.)" icon_state = "surrender" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/surrender/Click(location, control, params) . = ..() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index dfc72301fff0..984b4a164fc5 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1485,6 +1485,9 @@ /atom/movable/proc/grant_all_languages(language_flags = ALL, grant_omnitongue = TRUE, source = LANGUAGE_MIND) return get_language_holder().grant_all_languages(language_flags, grant_omnitongue, source) +/atom/movable/proc/grant_partial_language(language, amount = 50, source = LANGUAGE_ATOM) + return get_language_holder().grant_partial_language(language, amount, source) + /// Removes a single language. /atom/movable/proc/remove_language(language, language_flags = ALL, source = LANGUAGE_ALL) return get_language_holder().remove_language(language, language_flags, source) @@ -1493,6 +1496,12 @@ /atom/movable/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE) return get_language_holder().remove_all_languages(source, remove_omnitongue) +/atom/movable/proc/remove_partial_language(language, source = LANGUAGE_ALL) + return get_language_holder().remove_partial_language(language, source) + +/atom/movable/proc/remove_all_partial_languages(source = LANGUAGE_ALL) + return get_language_holder().remove_all_partial_languages(source) + /// Adds a language to the blocked language list. Use this over remove_language in cases where you will give languages back later. /atom/movable/proc/add_blocked_language(language, source = LANGUAGE_ATOM) return get_language_holder().add_blocked_language(language, source) diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 6ed574b45343..cdf029db1957 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -12,6 +12,7 @@ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.02 resistance_flags = LAVA_PROOF | FIRE_PROOF interaction_flags_machine = parent_type::interaction_flags_machine | INTERACT_MACHINE_OPEN + mouse_over_pointer = MOUSE_HAND_POINTER ///Icon suffix for the skin of the front pannel that is added to base_icon_state var/skin = "" ///Whether it is possible to change the panel skin diff --git a/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm b/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm index 47d65a9492f0..af86ab3b6c3e 100644 --- a/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm @@ -26,6 +26,8 @@ icon_state = "eyeballs-fly" flash_protect = FLASH_PROTECTION_HYPER_SENSITIVE native_fov = NONE //flies can see all around themselves. + blink_animation = FALSE + iris_overlays = FALSE /obj/item/organ/internal/eyes/fly/Initialize(mapload) . = ..() diff --git a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm index 477b461bdf31..8a6347a4bd09 100644 --- a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm @@ -18,6 +18,7 @@ icon = 'icons/obj/medical/organs/infuser_organs.dmi' icon_state = "eyes" + iris_overlays = FALSE greyscale_config = /datum/greyscale_config/mutant_organ greyscale_colors = GOLIATH_COLORS diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm index 4e84870ec9c3..0a74ed2ef5ba 100644 --- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm @@ -21,6 +21,7 @@ icon = 'icons/obj/medical/organs/infuser_organs.dmi' icon_state = "eyes" + iris_overlays = FALSE greyscale_config = /datum/greyscale_config/mutant_organ greyscale_colors = RAT_COLORS low_light_cutoff = list(16, 11, 0) diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm index 75ddb3606330..51403e044319 100644 --- a/code/game/machinery/embedded_controller/access_controller.dm +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -10,6 +10,7 @@ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.05 active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.04 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + mouse_over_pointer = MOUSE_HAND_POINTER var/idSelf /obj/machinery/door_buttons/attackby(obj/O, mob/user) @@ -107,6 +108,7 @@ name = "access console" desc = "A small console that can cycle opening between two airlocks." interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE + mouse_over_pointer = MOUSE_HAND_POINTER var/obj/machinery/door/airlock/interiorAirlock var/obj/machinery/door/airlock/exteriorAirlock var/idInterior diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 81e28d40be04..63d50ac19916 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -18,6 +18,7 @@ max_integrity = 250 integrity_failure = 0.4 armor_type = /datum/armor/machinery_firealarm + mouse_over_pointer = MOUSE_HAND_POINTER idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.05 active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.02 power_channel = AREA_USAGE_ENVIRON diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index a4646136aaf2..96013b0c01b7 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -7,6 +7,7 @@ desc = "Make dark." power_channel = AREA_USAGE_LIGHT idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.02 + mouse_over_pointer = MOUSE_HAND_POINTER /// Set this to a string, path, or area instance to control that area /// instead of the switch's location. var/area/area = null diff --git a/code/game/machinery/newscaster/newspaper.dm b/code/game/machinery/newscaster/newspaper.dm index 2bd8187b9f8c..90176553bf4c 100644 --- a/code/game/machinery/newscaster/newspaper.dm +++ b/code/game/machinery/newscaster/newspaper.dm @@ -89,6 +89,7 @@ return add_fingerprint(user) user.balloon_alert(user, "scribbling...") + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) if(!do_after(user, 2 SECONDS, src)) return user.balloon_alert(user, "scribbled!") diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index e021d8e984e7..dc2c785593b5 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -1759,6 +1759,7 @@ input_name = sanitize_name(input_name, allow_numbers = TRUE) if(!after_input_check(user, item, input_name, scribbled_name)) return + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) scribbled_name = input_name var/list/details = item.get_writing_implement_details() details_colors[INDEX_NAME_COLOR] = details["color"] || "#000000" @@ -1766,6 +1767,7 @@ var/input_assignment = tgui_input_text(user, "What assignment would you like to put on this card?", "Cardboard card job ssignment", scribbled_assignment || "Assistant", MAX_NAME_LEN) if(!after_input_check(user, item, input_assignment, scribbled_assignment)) return + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) scribbled_assignment = sanitize(input_assignment) var/list/details = item.get_writing_implement_details() details_colors[INDEX_ASSIGNMENT_COLOR] = details["color"] || "#000000" @@ -1781,6 +1783,7 @@ var/input_trim = tgui_input_list(user, "Select trim to apply to your card.\nNote: This will not grant any trim accesses.", "Forge Trim", possible_trims) if(!input_trim || !after_input_check(user, item, input_trim, scribbled_trim)) return + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) scribbled_trim = "cardboard_[input_trim]" var/list/details = item.get_writing_implement_details() details_colors[INDEX_TRIM_COLOR] = details["color"] || "#000000" diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 4951b65e74de..a9e6c7fb181d 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -19,7 +19,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM name = "match" desc = "A simple match stick, used for lighting fine smokables." icon = 'icons/obj/cigarettes.dmi' + lefthand_file = 'icons/mob/inhands/clothing/masks_lefthand.dmi' + righthand_file = 'icons/mob/inhands/clothing/masks_righthand.dmi' icon_state = "match_unlit" + inhand_icon_state = "cigoff" + base_icon_state = "match" w_class = WEIGHT_CLASS_TINY heat = 1000 grind_results = list(/datum/reagent/phosphorus = 2) @@ -29,6 +33,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/burnt = FALSE /// How long the match lasts in seconds var/smoketime = 10 SECONDS + /// If the match is broken + var/broken = FALSE /obj/item/match/process(seconds_per_tick) smoketime -= seconds_per_tick * (1 SECONDS) @@ -38,23 +44,72 @@ CIGARETTE PACKETS ARE IN FANCY.DM open_flame(heat) /obj/item/match/fire_act(exposed_temperature, exposed_volume) + . = ..() matchignite() +/obj/item/match/update_name(updates) + . = ..() + if(lit) + name = "lit [initial(name)]" + else if(burnt) + name = "burnt [initial(name)]" + else if(broken) + name = "broken [initial(name)]" + else + name = "[initial(name)]" + +/obj/item/match/update_desc(updates) + . = ..() + if(lit) + desc = "[initial(desc)]. This one is lit." + else if(burnt) + desc = "[initial(desc)]. This one has seen better days." + else if(broken) + desc = "[initial(desc)]. This one is broken." + else + desc = initial(desc) + +/obj/item/match/update_icon_state() + . = ..() + inhand_icon_state = "cigoff" + if(lit) + icon_state = "[base_icon_state]_lit" + inhand_icon_state = "cigon" + else if(burnt) + icon_state = "[base_icon_state]_burnt" + else if(broken) + icon_state = "[base_icon_state]_broken" + else + icon_state = "[base_icon_state]_unlit" + +/obj/item/match/proc/snap() + if(broken) + return + if(lit) + matchburnout() + + playsound(src, 'sound/effects/snap.ogg', 15, TRUE) + broken = TRUE + attack_verb_continuous = string_list(list("flicks")) + attack_verb_simple = string_list(list("flick")) + STOP_PROCESSING(SSobj, src) + update_appearance() + /obj/item/match/proc/matchignite() - if(lit || burnt) + if(lit || burnt || broken) return playsound(src, 'sound/items/match_strike.ogg', 15, TRUE) lit = TRUE - icon_state = "match_lit" damtype = BURN force = 3 hitsound = 'sound/items/welder.ogg' - inhand_icon_state = "cigon" - name = "lit [initial(name)]" - desc = "A [initial(name)]. This one is lit." attack_verb_continuous = string_list(list("burns", "singes")) attack_verb_simple = string_list(list("burn", "singe")) + if(isliving(loc)) + var/mob/living/male_model = loc + if(male_model.fire_stacks && !(male_model.on_fire)) + male_model.ignite_mob() START_PROCESSING(SSobj, src) update_appearance() @@ -66,13 +121,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM burnt = TRUE damtype = BRUTE force = initial(force) - icon_state = "match_burnt" - inhand_icon_state = "cigoff" - name = "burnt [initial(name)]" - desc = "A [initial(name)]. This one has seen better days." attack_verb_continuous = string_list(list("flicks")) attack_verb_simple = string_list(list("flick")) STOP_PROCESSING(SSobj, src) + update_appearance() /obj/item/match/extinguish() . = ..() diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index daf4b1d99ac8..0bc98cd39fdf 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -1,7 +1,3 @@ -#define UPPER_LIP "Upper" -#define MIDDLE_LIP "Middle" -#define LOWER_LIP "Lower" - /obj/item/lipstick gender = PLURAL name = "red lipstick" @@ -333,7 +329,3 @@ /obj/item/razor/surgery/get_surgery_tool_overlay(tray_extended) return "razor" - -#undef UPPER_LIP -#undef MIDDLE_LIP -#undef LOWER_LIP diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index bb2de5007a4c..73ef4c45decc 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -12,13 +12,15 @@ var/independent = FALSE /// What channels does this encryption key grant to the parent headset. var/list/channels = list() - var/datum/language/translated_language + /// Assoc list of language to how well understood it is. 0 is invalid, 100 is perfect. + var/list/language_data + greyscale_config = /datum/greyscale_config/encryptionkey_basic greyscale_colors = "#820a16#3758c4" /obj/item/encryptionkey/examine(mob/user) . = ..() - if(LAZYLEN(channels) || translate_binary) + if(LAZYLEN(channels) || translate_binary || LAZYLEN(language_data)) var/list/examine_text_list = list() for(var/i in channels) examine_text_list += "[GLOB.channel_tokens[i]] - [lowertext(i)]" @@ -26,7 +28,24 @@ if(translate_binary) examine_text_list += "[GLOB.channel_tokens[MODE_BINARY]] - [MODE_BINARY]" - . += span_notice("It can access the following channels; [jointext(examine_text_list, ", ")].") + if(length(examine_text_list)) + . += span_notice("It can access the following channels; [jointext(examine_text_list, ", ")].") + + var/list/language_text_list = list() + for(var/lang in language_data) + var/langstring = "[GLOB.language_datum_instances[lang].name]" + switch(language_data[lang]) + if(25 to 50) + langstring += " (poor)" + if(50 to 75) + langstring += " (average)" + if(75 to 100) + langstring += " (good)" + language_text_list += langstring + + if(length(language_text_list)) + . += span_notice("It can translate the following languages; [jointext(language_text_list, ", ")].") + else . += span_warning("Has no special codes in it. You should probably tell a coder!") @@ -42,7 +61,9 @@ name = "binary translator key" icon_state = "cypherkey_basic" translate_binary = TRUE - translated_language = /datum/language/machine + language_data = list( + /datum/language/machine = 100, + ) greyscale_config = /datum/greyscale_config/encryptionkey_basic greyscale_colors = "#24a157#3758c4" @@ -221,7 +242,9 @@ RADIO_CHANNEL_ENTERTAINMENT = 1, ) translate_binary = TRUE - translated_language = /datum/language/machine + language_data = list( + /datum/language/machine = 100, + ) /obj/item/encryptionkey/ai/evil //ported from NT, this goes 'inside' the AI. name = "syndicate binary encryption key" @@ -233,3 +256,94 @@ /obj/item/encryptionkey/secbot channels = list(RADIO_CHANNEL_AI_PRIVATE = 1, RADIO_CHANNEL_SECURITY = 1) + +// This is used for cargo goodies +/obj/item/encryptionkey/language + desc = "An encryption key that automatically translate some language into some other language you can hopefully understand." + icon_state = "cypherkey_cube" + greyscale_config = /datum/greyscale_config/encryptionkey_cube + greyscale_colors = "#339900#246202" + +// Thsese are just for admins - the cargo goodies automatically generate these +/obj/item/encryptionkey/language/moth + name = "\improper Moffic translation key" + language_data = list( + /datum/language/moffic = 100, + ) + +/obj/item/encryptionkey/language/moth/budget + name = "budget Moffic translation key" + language_data = list( + /datum/language/moffic = 50, + ) + +/obj/item/encryptionkey/language/draconic + name = "\improper Draconic translation key" + language_data = list( + /datum/language/draconic = 100, + ) + +/obj/item/encryptionkey/language/draconic/budget + name = "budget Draconic translation key" + language_data = list( + /datum/language/draconic = 50, + ) + +/obj/item/encryptionkey/language/plasmaman + name = "\improper Calcic translation key" + language_data = list( + /datum/language/calcic = 100, + ) + +/obj/item/encryptionkey/language/plasmaman/budget + name = "budget Calcic translation key" + language_data = list( + /datum/language/calcic = 50, + ) + +/obj/item/encryptionkey/language/ethereal + name = "\improper Ethereal translation key" + language_data = list( + /datum/language/voltaic = 100, + ) + +/obj/item/encryptionkey/language/ethereal/budget + name = "budget Ethereal translation key" + language_data = list( + /datum/language/voltaic = 50, + ) + +/obj/item/encryptionkey/language/felinid + name = "\improper Felinid translation key" + language_data = list( + /datum/language/nekomimetic = 100, + ) + +/obj/item/encryptionkey/language/felinid/budget + name = "budget Felinid translation key" + language_data = list( + /datum/language/nekomimetic = 50, + ) + +/obj/item/encryptionkey/language/uncommon + name = "\improper Uncommon translation key" + language_data = list( + /datum/language/uncommon = 100, + ) + +/obj/item/encryptionkey/language/uncommon/budget + name = "budget Uncommon translation key" + language_data = list( + /datum/language/uncommon = 75, // better than average because common can already partially understand it + ) + +// This one is used in cargo +/obj/item/encryptionkey/language/all_crew + name = "crew cohesion translation key" + desc = "An encryption key that'll translate a little bit of a lot of languages. Might give you a hint of what's going on, maybe." + +/obj/item/encryptionkey/language/all_crew/Initialize(mapload) + . = ..() + language_data = list() + for(var/lang in GLOB.uncommon_roundstart_languages) + language_data[lang] = 20 diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 4451316efb91..657f380e9e9e 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -32,8 +32,6 @@ GLOBAL_LIST_INIT(channel_tokens, list( slot_flags = ITEM_SLOT_EARS dog_fashion = null var/obj/item/encryptionkey/keyslot2 = null - /// A list of all languages that this headset allows the user to understand. Populated by language encryption keys. - var/list/language_list // headset is too small to display overlays overlay_speaker_idle = null @@ -101,8 +99,32 @@ GLOBAL_LIST_INIT(channel_tokens, list( /// Grants all the languages this headset allows the mob to understand via installed chips. /obj/item/radio/headset/proc/grant_headset_languages(mob/grant_to) + var/list/language_list = keyslot?.language_data?.Copy() + + if(keyslot2) + if(length(language_list)) + for(var/language in keyslot2.language_data) + if(language_list[language] < keyslot2.language_data[language]) + language_list[language] = keyslot2.language_data[language] + continue + language_list[language] = keyslot2.language_data[language] + + else + language_list = keyslot2.language_data?.Copy() + for(var/language in language_list) - grant_to.grant_language(language, language_flags = UNDERSTOOD_LANGUAGE, source = LANGUAGE_RADIOKEY) + var/amount_understood = language_list[language] + if(amount_understood >= 100) + grant_to.grant_language(language, language_flags = UNDERSTOOD_LANGUAGE, source = LANGUAGE_RADIOKEY) + else + grant_to.grant_partial_language(language, amount = amount_understood, source = LANGUAGE_RADIOKEY) + +/// Clears all radio related languages from the mob. +/obj/item/radio/headset/proc/remove_headset_languages(mob/remove_from) + if(QDELETED(remove_from)) + return + remove_from.remove_all_languages(source = LANGUAGE_RADIOKEY) + remove_from.remove_all_partial_languages(source = LANGUAGE_RADIOKEY) /obj/item/radio/headset/equipped(mob/user, slot, initial) . = ..() @@ -113,8 +135,7 @@ GLOBAL_LIST_INIT(channel_tokens, list( /obj/item/radio/headset/dropped(mob/user, silent) . = ..() - for(var/language in language_list) - user.remove_language(language, language_flags = UNDERSTOOD_LANGUAGE, source = LANGUAGE_RADIOKEY) + remove_headset_languages(user) /obj/item/radio/headset/syndicate //disguised to look like a normal headset for stealth ops @@ -419,22 +440,10 @@ GLOBAL_LIST_INIT(channel_tokens, list( for(var/ch_name in channels) secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name]) - var/list/old_language_list = language_list?.Copy() - language_list = list() - if(keyslot?.translated_language) - language_list += keyslot.translated_language - if(keyslot2?.translated_language) - language_list += keyslot2.translated_language - - // If we're equipped on a mob, we should make sure all the languages - // learned from our installed key chips are all still accurate + // Updates radio languages entirely for the mob wearing the headset var/mob/mob_loc = loc if(istype(mob_loc) && mob_loc.get_item_by_slot(slot_flags) == src) - // Remove all the languages we may not be able to know anymore - for(var/language in old_language_list) - mob_loc.remove_language(language, language_flags = UNDERSTOOD_LANGUAGE, source = LANGUAGE_RADIOKEY) - - // And grant all the languages we definitely should know now + remove_headset_languages(mob_loc) grant_headset_languages(mob_loc) /obj/item/radio/headset/AltClick(mob/living/user) diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index dc4e81b2f96e..0d8d5c9636bd 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -187,7 +187,7 @@ var/mob/living/carbon/C = user if(C.wear_mask) in_mouth = ", barely missing [user.p_their()] nose" - . = span_warning("[user] swings [user.p_their()] [name][in_mouth]. [user.p_They()] light[user.p_s()] [A.loc == user ? "[user.p_their()] [A.name]" : A] in the process.") + . = span_rose("[user] swings [user.p_their()] [name][in_mouth]. [user.p_They()] light[user.p_s()] [A.loc == user ? "[user.p_their()] [A.name]" : A] in the process.") playsound(loc, hitsound, get_clamped_volume(), TRUE, -1) add_fingerprint(user) // Light your candles while spinning around the room diff --git a/code/game/objects/items/implants/implantcase.dm b/code/game/objects/items/implants/implantcase.dm index ffef74de3c1c..1a3ec50eba25 100644 --- a/code/game/objects/items/implants/implantcase.dm +++ b/code/game/objects/items/implants/implantcase.dm @@ -43,6 +43,7 @@ if((user.get_active_held_item() != used_item) || !user.can_perform_action(src)) return if(new_name) + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) name = "implant case - '[new_name]'" else name = "implant case" diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 874e82261f33..b41c3c378006 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -87,7 +87,7 @@ var/mob/living/carbon/carbon_user = user if(carbon_user.wear_mask) in_mouth = ", barely missing [carbon_user.p_their()] nose" - . = span_warning("[user] swings [user.p_their()] [name][in_mouth]. [user.p_They()] light[user.p_s()] [user.p_their()] [atom.name] in the process.") + . = span_rose("[user] swings [user.p_their()] [name][in_mouth]. [user.p_They()] light[user.p_s()] [user.p_their()] [atom.name] in the process.") playsound(loc, hitsound, get_clamped_volume(), TRUE, -1) add_fingerprint(user) diff --git a/code/game/objects/items/signs.dm b/code/game/objects/items/signs.dm index 85a71dc0e8f7..d0ed3425f971 100644 --- a/code/game/objects/items/signs.dm +++ b/code/game/objects/items/signs.dm @@ -25,6 +25,7 @@ return var/txt = tgui_input_text(user, "What would you like to write on the sign?", "Sign Label", max_length = 30) if(txt && user.can_perform_action(src)) + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) label = txt name = "[label] sign" desc = "It reads: [label]" diff --git a/code/game/objects/items/storage/boxes/service_boxes.dm b/code/game/objects/items/storage/boxes/service_boxes.dm index 8dcc1f4f6b62..6fdee8e60e58 100644 --- a/code/game/objects/items/storage/boxes/service_boxes.dm +++ b/code/game/objects/items/storage/boxes/service_boxes.dm @@ -91,6 +91,7 @@ . = ..() atom_storage.max_slots = 10 atom_storage.set_holdable(/obj/item/match) + AddElement(/datum/element/ignites_matches) /obj/item/storage/box/matches/PopulateContents() for(var/i in 1 to 10) diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index f6ace35c2ce7..3920be703db9 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -315,7 +315,7 @@ /obj/item/weldingtool/ignition_effect(atom/ignitable_atom, mob/user) if(use_tool(ignitable_atom, user, 0)) - return span_notice("[user] casually lights [ignitable_atom] with [src], what a badass.") + return span_rose("[user] casually lights [ignitable_atom] with [src], what a badass.") else return "" diff --git a/code/game/objects/structures/crates_lockers/closets/bodybag.dm b/code/game/objects/structures/crates_lockers/closets/bodybag.dm index 759c6f0497e8..4a43e15d8223 100644 --- a/code/game/objects/structures/crates_lockers/closets/bodybag.dm +++ b/code/game/objects/structures/crates_lockers/closets/bodybag.dm @@ -52,6 +52,7 @@ ///Handles renaming of the bodybag's examine tag. /obj/structure/closet/body_bag/proc/handle_tag(new_name) + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) tag_name = new_name name = tag_name ? "[initial(name)] - [tag_name]" : initial(name) update_appearance() diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm index ef6ea9d433e8..771fb5746693 100644 --- a/code/game/objects/structures/ladders.dm +++ b/code/game/objects/structures/ladders.dm @@ -4,10 +4,14 @@ desc = "A sturdy metal ladder." icon = 'icons/obj/structures.dmi' icon_state = "ladder11" + base_icon_state = "ladder" anchored = TRUE obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN - var/obj/structure/ladder/down //the ladder below this one - var/obj/structure/ladder/up //the ladder above this one + ///the ladder below this one + VAR_FINAL/obj/structure/ladder/down + ///the ladder above this one + VAR_FINAL/obj/structure/ladder/up + /// Ladders crafted midround can only link to other ladders crafted midround var/crafted = FALSE /// travel time for ladder in deciseconds var/travel_time = 1 SECONDS @@ -15,17 +19,12 @@ /obj/structure/ladder/Initialize(mapload, obj/structure/ladder/up, obj/structure/ladder/down) ..() GLOB.ladders += src - if (up) - src.up = up - up.down = src - up.update_appearance() - if (down) - src.down = down - down.up = src - down.update_appearance() + if(up) + link_up(up) + if(down) + link_down(down) register_context() - return INITIALIZE_HINT_LATELOAD /obj/structure/ladder/add_context(atom/source, list/context, obj/item/held_item, mob/user) @@ -37,46 +36,185 @@ /obj/structure/ladder/examine(mob/user) . = ..() - . += span_info("Left-click it to start moving up; Right-click to start moving down.") + . += span_info("[EXAMINE_HINT("Left-click")] it to start moving up; [EXAMINE_HINT("Right-click")] to start moving down.") /obj/structure/ladder/Destroy(force) GLOB.ladders -= src disconnect() return ..() +/// Trait source applied by ladder holes +#define SOURCE_LADDER(ladder) "ladder_[REF(ladder)]" + +/// Abstract object used to represent a hole in the floor created by a ladder +/obj/effect/abstract/ladder_hole + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + plane = TRANSPARENT_FLOOR_PLANE + layer = SPACE_LAYER + alpha = 254 + /// The ladder that created this hole + VAR_FINAL/obj/structure/ladder/ladder + +/obj/effect/abstract/ladder_hole/Initialize(mapload, obj/structure/ladder/ladder) + . = ..() + if(isnull(ladder) || !isopenturf(loc) || isopenspaceturf(loc)) + return INITIALIZE_HINT_QDEL + for(var/obj/effect/abstract/ladder_hole/hole in loc) + if(hole.ladder == ladder) + return INITIALIZE_HINT_QDEL + + src.ladder = ladder + RegisterSignal(ladder, COMSIG_QDELETING, PROC_REF(cleanup)) + + icon = ladder.icon + icon_state = "[ladder.base_icon_state]_hole" + render_target = "*[SOURCE_LADDER(ladder)]" + + ADD_KEEP_TOGETHER(loc, SOURCE_LADDER(ladder)) + ADD_TURF_TRANSPARENCY(loc, SOURCE_LADDER(ladder)) + RegisterSignal(loc, COMSIG_TURF_CHANGE, PROC_REF(turf_changing)) + RegisterSignal(loc, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_ladder_rim)) + loc.add_filter(SOURCE_LADDER(ladder), 1, alpha_mask_filter( + x = ladder.pixel_x + ladder.pixel_w, + y = ladder.pixel_y + ladder.pixel_z, + render_source = "*[SOURCE_LADDER(ladder)]", + flags = MASK_INVERSE, + )) + loc.update_appearance(UPDATE_OVERLAYS) + +/obj/effect/abstract/ladder_hole/Destroy() + if(isnull(ladder)) + return ..() + + if(isopenturf(loc)) + UnregisterSignal(loc, list(COMSIG_TURF_CHANGE, COMSIG_ATOM_UPDATE_OVERLAYS)) + REMOVE_KEEP_TOGETHER(loc, SOURCE_LADDER(ladder)) + REMOVE_TURF_TRANSPARENCY(loc, SOURCE_LADDER(ladder)) + loc.remove_filter(SOURCE_LADDER(ladder)) + loc.update_appearance(UPDATE_OVERLAYS) + + UnregisterSignal(ladder, COMSIG_QDELETING) + ladder = null + + return ..() + +/obj/effect/abstract/ladder_hole/proc/cleanup() + SIGNAL_HANDLER + + // the ladder will qdel us in its Destroy regardless, when it unlinks + // this is just an extra layer of safety, in case the ladder gets moved or something + qdel(src) + +/obj/effect/abstract/ladder_hole/proc/turf_changing(datum/source, path, new_baseturfs, flags, list/datum/callback/post_change_callbacks) + SIGNAL_HANDLER + + post_change_callbacks += CALLBACK(ladder, TYPE_PROC_REF(/obj/structure/ladder, make_base_transparent)) + qdel(src) + +/obj/effect/abstract/ladder_hole/proc/add_ladder_rim(turf/source, list/overlays) + SIGNAL_HANDLER + + var/mutable_appearance/rim = mutable_appearance( + icon = ladder.icon, + icon_state = "[ladder.base_icon_state]_rim", + layer = TURF_DECAL_LAYER, + plane = FLOOR_PLANE, + offset_spokesman = source, + ) + rim.pixel_w = ladder.pixel_w + rim.pixel_x = ladder.pixel_x + rim.pixel_y = ladder.pixel_y + rim.pixel_z = ladder.pixel_z + + overlays += rim + +/// Makes the base of the ladder transparent +/obj/structure/ladder/proc/make_base_transparent() + if(!SSmapping.level_trait(z, ZTRAIT_DOWN)) // Ladders which are actually teleporting you to another z level + return + base_pixel_z = initial(base_pixel_z) + 12 + pixel_z = base_pixel_z + new /obj/effect/abstract/ladder_hole(loc, src) + +/// Clears any ladder holes created by this ladder +/obj/structure/ladder/proc/clear_base_transparency() + base_pixel_z = initial(base_pixel_z) + pixel_z = base_pixel_z + for(var/obj/effect/abstract/ladder_hole/hole in loc) + if(hole.ladder == src) + qdel(hole) + +#undef SOURCE_LADDER + +/// Links this ladder to passed ladder (which should generally be below it) +/obj/structure/ladder/proc/link_down(obj/structure/ladder/down_ladder) + if(down) + return + + down = down_ladder + down_ladder.up = src + down_ladder.update_appearance(UPDATE_ICON_STATE) + update_appearance(UPDATE_ICON_STATE) + make_base_transparent() + +/// Unlinks this ladder from the ladder below it. +/obj/structure/ladder/proc/unlink_down() + if(!down) + return + + down.up = null + down.update_appearance(UPDATE_ICON_STATE) + down = null + update_appearance(UPDATE_ICON_STATE) + clear_base_transparency() + +/// Links this ladder to passed ladder (which should generally be above it) +/obj/structure/ladder/proc/link_up(obj/structure/ladder/up_ladder) + if(up) + return + + up = up_ladder + up_ladder.down = src + up_ladder.make_base_transparent() + up_ladder.update_appearance(UPDATE_ICON_STATE) + update_appearance(UPDATE_ICON_STATE) + +/// Unlinks this ladder from the ladder above it. +/obj/structure/ladder/proc/unlink_up() + if(!up) + return + + up.down = null + up.clear_base_transparency() + up.update_appearance(UPDATE_ICON_STATE) + up = null + update_appearance(UPDATE_ICON_STATE) + +/// Helper to unlink everything +/obj/structure/ladder/proc/disconnect() + unlink_down() + unlink_up() + /obj/structure/ladder/LateInitialize() // By default, discover ladders above and below us vertically - var/turf/T = get_turf(src) - var/obj/structure/ladder/L - - if (!down) - L = locate() in GET_TURF_BELOW(T) - if (L) - if(crafted == L.crafted) - down = L - L.up = src // Don't waste effort looping the other way - L.update_appearance() - if (!up) - L = locate() in GET_TURF_ABOVE(T) - if (L) - if(crafted == L.crafted) - up = L - L.down = src // Don't waste effort looping the other way - L.update_appearance() + var/turf/base = get_turf(src) - update_appearance() + if(isnull(down)) + var/obj/structure/ladder/new_down = locate() in GET_TURF_BELOW(base) + if (new_down && crafted == new_down.crafted) + link_down(new_down) -/obj/structure/ladder/proc/disconnect() - if(up && up.down == src) - up.down = null - up.update_appearance() - if(down && down.up == src) - down.up = null - down.update_appearance() - up = down = null + if(isnull(up)) + var/obj/structure/ladder/new_up = locate() in GET_TURF_ABOVE(base) + if (new_up && crafted == new_up.crafted) + link_up(new_up) + + // Linking updates our icon, so if we failed both links we need a manual update + if(isnull(down) && isnull(up)) + update_appearance(UPDATE_ICON_STATE) /obj/structure/ladder/update_icon_state() - icon_state = "ladder[up ? 1 : 0][down ? 1 : 0]" + icon_state = "[base_icon_state][!!up][!!down]" return ..() /obj/structure/ladder/singularity_pull() diff --git a/code/game/sound.dm b/code/game/sound.dm index 3d19d2b21fcd..4f24b994659c 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -217,278 +217,323 @@ return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs. /proc/get_sfx(soundin) - if(istext(soundin)) - switch(soundin) - if(SFX_SHATTER) - soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') - if(SFX_EXPLOSION) - soundin = pick('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg') - if(SFX_EXPLOSION_CREAKING) - soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg') - if(SFX_HULL_CREAKING) - soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') - if(SFX_SPARKS) - soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg') - if(SFX_RUSTLE) - soundin = pick('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg') - if(SFX_BODYFALL) - soundin = pick('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg') - if(SFX_PUNCH) - soundin = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') - if(SFX_CLOWN_STEP) - soundin = pick('sound/effects/footstep/clownstep1.ogg','sound/effects/footstep/clownstep2.ogg') - if(SFX_SUIT_STEP) - soundin = pick('sound/effects/suitstep1.ogg','sound/effects/suitstep2.ogg') - if(SFX_SWING_HIT) - soundin = pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg') - if(SFX_HISS) - soundin = pick('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg') - if(SFX_PAGE_TURN) - soundin = pick('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg') - if(SFX_RICOCHET) - soundin = pick( 'sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg','sound/weapons/effects/ric3.ogg','sound/weapons/effects/ric4.ogg','sound/weapons/effects/ric5.ogg') - if(SFX_TERMINAL_TYPE) - soundin = pick(list( - 'sound/machines/terminal_button01.ogg', - 'sound/machines/terminal_button02.ogg', - 'sound/machines/terminal_button03.ogg', - 'sound/machines/terminal_button04.ogg', - 'sound/machines/terminal_button05.ogg', - 'sound/machines/terminal_button06.ogg', - 'sound/machines/terminal_button07.ogg', - 'sound/machines/terminal_button08.ogg', - )) - if(SFX_DESECRATION) - soundin = pick('sound/misc/desecration-01.ogg', 'sound/misc/desecration-02.ogg', 'sound/misc/desecration-03.ogg') - if(SFX_IM_HERE) - soundin = pick('sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg') - if(SFX_CAN_OPEN) - soundin = pick('sound/effects/can_open1.ogg', 'sound/effects/can_open2.ogg', 'sound/effects/can_open3.ogg') - if(SFX_BULLET_MISS) - soundin = pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg') - if(SFX_REVOLVER_SPIN) - soundin = pick('sound/weapons/gun/revolver/spin1.ogg', 'sound/weapons/gun/revolver/spin2.ogg', 'sound/weapons/gun/revolver/spin3.ogg') - if(SFX_LAW) - soundin = pick(list( - 'sound/voice/beepsky/creep.ogg', - 'sound/voice/beepsky/god.ogg', - 'sound/voice/beepsky/iamthelaw.ogg', - 'sound/voice/beepsky/insult.ogg', - 'sound/voice/beepsky/radio.ogg', - 'sound/voice/beepsky/secureday.ogg', - )) - if(SFX_HONKBOT_E) - soundin = pick(list( - 'sound/effects/pray.ogg', - 'sound/effects/reee.ogg', - 'sound/items/AirHorn.ogg', - 'sound/items/AirHorn2.ogg', - 'sound/items/bikehorn.ogg', - 'sound/items/WEEOO1.ogg', - 'sound/machines/buzz-sigh.ogg', - 'sound/machines/ping.ogg', - 'sound/magic/Fireball.ogg', - 'sound/misc/sadtrombone.ogg', - 'sound/voice/beepsky/creep.ogg', - 'sound/voice/beepsky/iamthelaw.ogg', - 'sound/voice/hiss1.ogg', - 'sound/weapons/bladeslice.ogg', - 'sound/weapons/flashbang.ogg', - )) - if(SFX_GOOSE) - soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg') - if(SFX_WARPSPEED) - soundin = 'sound/runtime/hyperspace/hyperspace_begin.ogg' - if(SFX_SM_CALM) - soundin = pick(list( - 'sound/machines/sm/accent/normal/1.ogg', - 'sound/machines/sm/accent/normal/2.ogg', - 'sound/machines/sm/accent/normal/3.ogg', - 'sound/machines/sm/accent/normal/4.ogg', - 'sound/machines/sm/accent/normal/5.ogg', - 'sound/machines/sm/accent/normal/6.ogg', - 'sound/machines/sm/accent/normal/7.ogg', - 'sound/machines/sm/accent/normal/8.ogg', - 'sound/machines/sm/accent/normal/9.ogg', - 'sound/machines/sm/accent/normal/10.ogg', - 'sound/machines/sm/accent/normal/11.ogg', - 'sound/machines/sm/accent/normal/12.ogg', - 'sound/machines/sm/accent/normal/13.ogg', - 'sound/machines/sm/accent/normal/14.ogg', - 'sound/machines/sm/accent/normal/15.ogg', - 'sound/machines/sm/accent/normal/16.ogg', - 'sound/machines/sm/accent/normal/17.ogg', - 'sound/machines/sm/accent/normal/18.ogg', - 'sound/machines/sm/accent/normal/19.ogg', - 'sound/machines/sm/accent/normal/20.ogg', - 'sound/machines/sm/accent/normal/21.ogg', - 'sound/machines/sm/accent/normal/22.ogg', - 'sound/machines/sm/accent/normal/23.ogg', - 'sound/machines/sm/accent/normal/24.ogg', - 'sound/machines/sm/accent/normal/25.ogg', - 'sound/machines/sm/accent/normal/26.ogg', - 'sound/machines/sm/accent/normal/27.ogg', - 'sound/machines/sm/accent/normal/28.ogg', - 'sound/machines/sm/accent/normal/29.ogg', - 'sound/machines/sm/accent/normal/30.ogg', - 'sound/machines/sm/accent/normal/31.ogg', - 'sound/machines/sm/accent/normal/32.ogg', - 'sound/machines/sm/accent/normal/33.ogg', - )) - if(SFX_SM_DELAM) - soundin = pick(list( - 'sound/machines/sm/accent/delam/1.ogg', - 'sound/machines/sm/accent/delam/2.ogg', - 'sound/machines/sm/accent/delam/3.ogg', - 'sound/machines/sm/accent/delam/4.ogg', - 'sound/machines/sm/accent/delam/5.ogg', - 'sound/machines/sm/accent/delam/6.ogg', - 'sound/machines/sm/accent/delam/7.ogg', - 'sound/machines/sm/accent/delam/8.ogg', - 'sound/machines/sm/accent/delam/9.ogg', - 'sound/machines/sm/accent/delam/10.ogg', - 'sound/machines/sm/accent/delam/11.ogg', - 'sound/machines/sm/accent/delam/12.ogg', - 'sound/machines/sm/accent/delam/13.ogg', - 'sound/machines/sm/accent/delam/14.ogg', - 'sound/machines/sm/accent/delam/15.ogg', - 'sound/machines/sm/accent/delam/16.ogg', - 'sound/machines/sm/accent/delam/17.ogg', - 'sound/machines/sm/accent/delam/18.ogg', - 'sound/machines/sm/accent/delam/19.ogg', - 'sound/machines/sm/accent/delam/20.ogg', - 'sound/machines/sm/accent/delam/21.ogg', - 'sound/machines/sm/accent/delam/22.ogg', - 'sound/machines/sm/accent/delam/23.ogg', - 'sound/machines/sm/accent/delam/24.ogg', - 'sound/machines/sm/accent/delam/25.ogg', - 'sound/machines/sm/accent/delam/26.ogg', - 'sound/machines/sm/accent/delam/27.ogg', - 'sound/machines/sm/accent/delam/28.ogg', - 'sound/machines/sm/accent/delam/29.ogg', - 'sound/machines/sm/accent/delam/30.ogg', - 'sound/machines/sm/accent/delam/31.ogg', - 'sound/machines/sm/accent/delam/32.ogg', - 'sound/machines/sm/accent/delam/33.ogg', - )) - if(SFX_HYPERTORUS_CALM) - soundin = pick(list( - 'sound/machines/sm/accent/normal/1.ogg', - 'sound/machines/sm/accent/normal/2.ogg', - 'sound/machines/sm/accent/normal/3.ogg', - 'sound/machines/sm/accent/normal/4.ogg', - 'sound/machines/sm/accent/normal/5.ogg', - 'sound/machines/sm/accent/normal/6.ogg', - 'sound/machines/sm/accent/normal/7.ogg', - 'sound/machines/sm/accent/normal/8.ogg', - 'sound/machines/sm/accent/normal/9.ogg', - 'sound/machines/sm/accent/normal/10.ogg', - 'sound/machines/sm/accent/normal/11.ogg', - 'sound/machines/sm/accent/normal/12.ogg', - 'sound/machines/sm/accent/normal/13.ogg', - 'sound/machines/sm/accent/normal/14.ogg', - 'sound/machines/sm/accent/normal/15.ogg', - 'sound/machines/sm/accent/normal/16.ogg', - 'sound/machines/sm/accent/normal/17.ogg', - 'sound/machines/sm/accent/normal/18.ogg', - 'sound/machines/sm/accent/normal/19.ogg', - 'sound/machines/sm/accent/normal/20.ogg', - 'sound/machines/sm/accent/normal/21.ogg', - 'sound/machines/sm/accent/normal/22.ogg', - 'sound/machines/sm/accent/normal/23.ogg', - 'sound/machines/sm/accent/normal/24.ogg', - 'sound/machines/sm/accent/normal/25.ogg', - 'sound/machines/sm/accent/normal/26.ogg', - 'sound/machines/sm/accent/normal/27.ogg', - 'sound/machines/sm/accent/normal/28.ogg', - 'sound/machines/sm/accent/normal/29.ogg', - 'sound/machines/sm/accent/normal/30.ogg', - 'sound/machines/sm/accent/normal/31.ogg', - 'sound/machines/sm/accent/normal/32.ogg', - 'sound/machines/sm/accent/normal/33.ogg', - )) - if(SFX_HYPERTORUS_MELTING) - soundin = pick(list( - 'sound/machines/sm/accent/delam/1.ogg', - 'sound/machines/sm/accent/delam/2.ogg', - 'sound/machines/sm/accent/delam/3.ogg', - 'sound/machines/sm/accent/delam/4.ogg', - 'sound/machines/sm/accent/delam/5.ogg', - 'sound/machines/sm/accent/delam/6.ogg', - 'sound/machines/sm/accent/delam/7.ogg', - 'sound/machines/sm/accent/delam/8.ogg', - 'sound/machines/sm/accent/delam/9.ogg', - 'sound/machines/sm/accent/delam/10.ogg', - 'sound/machines/sm/accent/delam/11.ogg', - 'sound/machines/sm/accent/delam/12.ogg', - 'sound/machines/sm/accent/delam/13.ogg', - 'sound/machines/sm/accent/delam/14.ogg', - 'sound/machines/sm/accent/delam/15.ogg', - 'sound/machines/sm/accent/delam/16.ogg', - 'sound/machines/sm/accent/delam/17.ogg', - 'sound/machines/sm/accent/delam/18.ogg', - 'sound/machines/sm/accent/delam/19.ogg', - 'sound/machines/sm/accent/delam/20.ogg', - 'sound/machines/sm/accent/delam/21.ogg', - 'sound/machines/sm/accent/delam/22.ogg', - 'sound/machines/sm/accent/delam/23.ogg', - 'sound/machines/sm/accent/delam/24.ogg', - 'sound/machines/sm/accent/delam/25.ogg', - 'sound/machines/sm/accent/delam/26.ogg', - 'sound/machines/sm/accent/delam/27.ogg', - 'sound/machines/sm/accent/delam/28.ogg', - 'sound/machines/sm/accent/delam/29.ogg', - 'sound/machines/sm/accent/delam/30.ogg', - 'sound/machines/sm/accent/delam/31.ogg', - 'sound/machines/sm/accent/delam/32.ogg', - 'sound/machines/sm/accent/delam/33.ogg', - )) - if(SFX_CRUNCHY_BUSH_WHACK) - soundin = pick('sound/effects/crunchybushwhack1.ogg', 'sound/effects/crunchybushwhack2.ogg', 'sound/effects/crunchybushwhack3.ogg') - if(SFX_TREE_CHOP) - soundin = pick('sound/effects/treechop1.ogg', 'sound/effects/treechop2.ogg', 'sound/effects/treechop3.ogg') - if(SFX_ROCK_TAP) - soundin = pick('sound/effects/rocktap1.ogg', 'sound/effects/rocktap2.ogg', 'sound/effects/rocktap3.ogg') - if(SFX_SEAR) - soundin = 'sound/weapons/sear.ogg' - if(SFX_REEL) - soundin = pick( - 'sound/items/reel1.ogg', - 'sound/items/reel2.ogg', - 'sound/items/reel3.ogg', - 'sound/items/reel4.ogg', - 'sound/items/reel5.ogg', - ) - if(SFX_PORTAL_CLOSE) - soundin = 'sound/effects/portal_close.ogg' - if(SFX_PORTAL_ENTER) - soundin = 'sound/effects/portal_travel.ogg' - if(SFX_PORTAL_CREATED) - soundin = pick( - 'sound/effects/portal_open_1.ogg', - 'sound/effects/portal_open_2.ogg', - 'sound/effects/portal_open_3.ogg', - ) - if(SFX_SCREECH) - soundin = pick( - 'sound/creatures/monkey/monkey_screech_1.ogg', - 'sound/creatures/monkey/monkey_screech_2.ogg', - 'sound/creatures/monkey/monkey_screech_3.ogg', - 'sound/creatures/monkey/monkey_screech_4.ogg', - 'sound/creatures/monkey/monkey_screech_5.ogg', - 'sound/creatures/monkey/monkey_screech_6.ogg', - 'sound/creatures/monkey/monkey_screech_7.ogg', - ) - if(SFX_MUFFLED_SPEECH) - soundin = pick( - 'sound/effects/muffspeech/muffspeech1.ogg', - 'sound/effects/muffspeech/muffspeech2.ogg', - 'sound/effects/muffspeech/muffspeech3.ogg', - 'sound/effects/muffspeech/muffspeech4.ogg', - 'sound/effects/muffspeech/muffspeech5.ogg', - 'sound/effects/muffspeech/muffspeech6.ogg', - 'sound/effects/muffspeech/muffspeech7.ogg', - 'sound/effects/muffspeech/muffspeech8.ogg', - 'sound/effects/muffspeech/muffspeech9.ogg', - ) + if(!istext(soundin)) + return soundin + switch(soundin) + if(SFX_SHATTER) + soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') + if(SFX_EXPLOSION) + soundin = pick('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg') + if(SFX_EXPLOSION_CREAKING) + soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg') + if(SFX_HULL_CREAKING) + soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') + if(SFX_SPARKS) + soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg') + if(SFX_RUSTLE) + soundin = pick('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg') + if(SFX_BODYFALL) + soundin = pick('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg') + if(SFX_PUNCH) + soundin = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') + if(SFX_CLOWN_STEP) + soundin = pick('sound/effects/footstep/clownstep1.ogg','sound/effects/footstep/clownstep2.ogg') + if(SFX_SUIT_STEP) + soundin = pick('sound/effects/suitstep1.ogg','sound/effects/suitstep2.ogg') + if(SFX_SWING_HIT) + soundin = pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg') + if(SFX_HISS) + soundin = pick('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg') + if(SFX_PAGE_TURN) + soundin = pick('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg') + if(SFX_RICOCHET) + soundin = pick( 'sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg','sound/weapons/effects/ric3.ogg','sound/weapons/effects/ric4.ogg','sound/weapons/effects/ric5.ogg') + if(SFX_TERMINAL_TYPE) + soundin = pick(list( + 'sound/machines/terminal_button01.ogg', + 'sound/machines/terminal_button02.ogg', + 'sound/machines/terminal_button03.ogg', + 'sound/machines/terminal_button04.ogg', + 'sound/machines/terminal_button05.ogg', + 'sound/machines/terminal_button06.ogg', + 'sound/machines/terminal_button07.ogg', + 'sound/machines/terminal_button08.ogg', + )) + if(SFX_DESECRATION) + soundin = pick('sound/misc/desecration-01.ogg', 'sound/misc/desecration-02.ogg', 'sound/misc/desecration-03.ogg') + if(SFX_IM_HERE) + soundin = pick('sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg') + if(SFX_CAN_OPEN) + soundin = pick('sound/effects/can_open1.ogg', 'sound/effects/can_open2.ogg', 'sound/effects/can_open3.ogg') + if(SFX_BULLET_MISS) + soundin = pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg') + if(SFX_REVOLVER_SPIN) + soundin = pick('sound/weapons/gun/revolver/spin1.ogg', 'sound/weapons/gun/revolver/spin2.ogg', 'sound/weapons/gun/revolver/spin3.ogg') + if(SFX_LAW) + soundin = pick(list( + 'sound/voice/beepsky/creep.ogg', + 'sound/voice/beepsky/god.ogg', + 'sound/voice/beepsky/iamthelaw.ogg', + 'sound/voice/beepsky/insult.ogg', + 'sound/voice/beepsky/radio.ogg', + 'sound/voice/beepsky/secureday.ogg', + )) + if(SFX_HONKBOT_E) + soundin = pick(list( + 'sound/effects/pray.ogg', + 'sound/effects/reee.ogg', + 'sound/items/AirHorn.ogg', + 'sound/items/AirHorn2.ogg', + 'sound/items/bikehorn.ogg', + 'sound/items/WEEOO1.ogg', + 'sound/machines/buzz-sigh.ogg', + 'sound/machines/ping.ogg', + 'sound/magic/Fireball.ogg', + 'sound/misc/sadtrombone.ogg', + 'sound/voice/beepsky/creep.ogg', + 'sound/voice/beepsky/iamthelaw.ogg', + 'sound/voice/hiss1.ogg', + 'sound/weapons/bladeslice.ogg', + 'sound/weapons/flashbang.ogg', + )) + if(SFX_GOOSE) + soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg') + if(SFX_WARPSPEED) + soundin = 'sound/runtime/hyperspace/hyperspace_begin.ogg' + if(SFX_SM_CALM) + soundin = pick(list( + 'sound/machines/sm/accent/normal/1.ogg', + 'sound/machines/sm/accent/normal/2.ogg', + 'sound/machines/sm/accent/normal/3.ogg', + 'sound/machines/sm/accent/normal/4.ogg', + 'sound/machines/sm/accent/normal/5.ogg', + 'sound/machines/sm/accent/normal/6.ogg', + 'sound/machines/sm/accent/normal/7.ogg', + 'sound/machines/sm/accent/normal/8.ogg', + 'sound/machines/sm/accent/normal/9.ogg', + 'sound/machines/sm/accent/normal/10.ogg', + 'sound/machines/sm/accent/normal/11.ogg', + 'sound/machines/sm/accent/normal/12.ogg', + 'sound/machines/sm/accent/normal/13.ogg', + 'sound/machines/sm/accent/normal/14.ogg', + 'sound/machines/sm/accent/normal/15.ogg', + 'sound/machines/sm/accent/normal/16.ogg', + 'sound/machines/sm/accent/normal/17.ogg', + 'sound/machines/sm/accent/normal/18.ogg', + 'sound/machines/sm/accent/normal/19.ogg', + 'sound/machines/sm/accent/normal/20.ogg', + 'sound/machines/sm/accent/normal/21.ogg', + 'sound/machines/sm/accent/normal/22.ogg', + 'sound/machines/sm/accent/normal/23.ogg', + 'sound/machines/sm/accent/normal/24.ogg', + 'sound/machines/sm/accent/normal/25.ogg', + 'sound/machines/sm/accent/normal/26.ogg', + 'sound/machines/sm/accent/normal/27.ogg', + 'sound/machines/sm/accent/normal/28.ogg', + 'sound/machines/sm/accent/normal/29.ogg', + 'sound/machines/sm/accent/normal/30.ogg', + 'sound/machines/sm/accent/normal/31.ogg', + 'sound/machines/sm/accent/normal/32.ogg', + 'sound/machines/sm/accent/normal/33.ogg', + )) + if(SFX_SM_DELAM) + soundin = pick(list( + 'sound/machines/sm/accent/delam/1.ogg', + 'sound/machines/sm/accent/delam/2.ogg', + 'sound/machines/sm/accent/delam/3.ogg', + 'sound/machines/sm/accent/delam/4.ogg', + 'sound/machines/sm/accent/delam/5.ogg', + 'sound/machines/sm/accent/delam/6.ogg', + 'sound/machines/sm/accent/delam/7.ogg', + 'sound/machines/sm/accent/delam/8.ogg', + 'sound/machines/sm/accent/delam/9.ogg', + 'sound/machines/sm/accent/delam/10.ogg', + 'sound/machines/sm/accent/delam/11.ogg', + 'sound/machines/sm/accent/delam/12.ogg', + 'sound/machines/sm/accent/delam/13.ogg', + 'sound/machines/sm/accent/delam/14.ogg', + 'sound/machines/sm/accent/delam/15.ogg', + 'sound/machines/sm/accent/delam/16.ogg', + 'sound/machines/sm/accent/delam/17.ogg', + 'sound/machines/sm/accent/delam/18.ogg', + 'sound/machines/sm/accent/delam/19.ogg', + 'sound/machines/sm/accent/delam/20.ogg', + 'sound/machines/sm/accent/delam/21.ogg', + 'sound/machines/sm/accent/delam/22.ogg', + 'sound/machines/sm/accent/delam/23.ogg', + 'sound/machines/sm/accent/delam/24.ogg', + 'sound/machines/sm/accent/delam/25.ogg', + 'sound/machines/sm/accent/delam/26.ogg', + 'sound/machines/sm/accent/delam/27.ogg', + 'sound/machines/sm/accent/delam/28.ogg', + 'sound/machines/sm/accent/delam/29.ogg', + 'sound/machines/sm/accent/delam/30.ogg', + 'sound/machines/sm/accent/delam/31.ogg', + 'sound/machines/sm/accent/delam/32.ogg', + 'sound/machines/sm/accent/delam/33.ogg', + )) + if(SFX_HYPERTORUS_CALM) + soundin = pick(list( + 'sound/machines/sm/accent/normal/1.ogg', + 'sound/machines/sm/accent/normal/2.ogg', + 'sound/machines/sm/accent/normal/3.ogg', + 'sound/machines/sm/accent/normal/4.ogg', + 'sound/machines/sm/accent/normal/5.ogg', + 'sound/machines/sm/accent/normal/6.ogg', + 'sound/machines/sm/accent/normal/7.ogg', + 'sound/machines/sm/accent/normal/8.ogg', + 'sound/machines/sm/accent/normal/9.ogg', + 'sound/machines/sm/accent/normal/10.ogg', + 'sound/machines/sm/accent/normal/11.ogg', + 'sound/machines/sm/accent/normal/12.ogg', + 'sound/machines/sm/accent/normal/13.ogg', + 'sound/machines/sm/accent/normal/14.ogg', + 'sound/machines/sm/accent/normal/15.ogg', + 'sound/machines/sm/accent/normal/16.ogg', + 'sound/machines/sm/accent/normal/17.ogg', + 'sound/machines/sm/accent/normal/18.ogg', + 'sound/machines/sm/accent/normal/19.ogg', + 'sound/machines/sm/accent/normal/20.ogg', + 'sound/machines/sm/accent/normal/21.ogg', + 'sound/machines/sm/accent/normal/22.ogg', + 'sound/machines/sm/accent/normal/23.ogg', + 'sound/machines/sm/accent/normal/24.ogg', + 'sound/machines/sm/accent/normal/25.ogg', + 'sound/machines/sm/accent/normal/26.ogg', + 'sound/machines/sm/accent/normal/27.ogg', + 'sound/machines/sm/accent/normal/28.ogg', + 'sound/machines/sm/accent/normal/29.ogg', + 'sound/machines/sm/accent/normal/30.ogg', + 'sound/machines/sm/accent/normal/31.ogg', + 'sound/machines/sm/accent/normal/32.ogg', + 'sound/machines/sm/accent/normal/33.ogg', + )) + if(SFX_HYPERTORUS_MELTING) + soundin = pick(list( + 'sound/machines/sm/accent/delam/1.ogg', + 'sound/machines/sm/accent/delam/2.ogg', + 'sound/machines/sm/accent/delam/3.ogg', + 'sound/machines/sm/accent/delam/4.ogg', + 'sound/machines/sm/accent/delam/5.ogg', + 'sound/machines/sm/accent/delam/6.ogg', + 'sound/machines/sm/accent/delam/7.ogg', + 'sound/machines/sm/accent/delam/8.ogg', + 'sound/machines/sm/accent/delam/9.ogg', + 'sound/machines/sm/accent/delam/10.ogg', + 'sound/machines/sm/accent/delam/11.ogg', + 'sound/machines/sm/accent/delam/12.ogg', + 'sound/machines/sm/accent/delam/13.ogg', + 'sound/machines/sm/accent/delam/14.ogg', + 'sound/machines/sm/accent/delam/15.ogg', + 'sound/machines/sm/accent/delam/16.ogg', + 'sound/machines/sm/accent/delam/17.ogg', + 'sound/machines/sm/accent/delam/18.ogg', + 'sound/machines/sm/accent/delam/19.ogg', + 'sound/machines/sm/accent/delam/20.ogg', + 'sound/machines/sm/accent/delam/21.ogg', + 'sound/machines/sm/accent/delam/22.ogg', + 'sound/machines/sm/accent/delam/23.ogg', + 'sound/machines/sm/accent/delam/24.ogg', + 'sound/machines/sm/accent/delam/25.ogg', + 'sound/machines/sm/accent/delam/26.ogg', + 'sound/machines/sm/accent/delam/27.ogg', + 'sound/machines/sm/accent/delam/28.ogg', + 'sound/machines/sm/accent/delam/29.ogg', + 'sound/machines/sm/accent/delam/30.ogg', + 'sound/machines/sm/accent/delam/31.ogg', + 'sound/machines/sm/accent/delam/32.ogg', + 'sound/machines/sm/accent/delam/33.ogg', + )) + if(SFX_CRUNCHY_BUSH_WHACK) + soundin = pick('sound/effects/crunchybushwhack1.ogg', 'sound/effects/crunchybushwhack2.ogg', 'sound/effects/crunchybushwhack3.ogg') + if(SFX_TREE_CHOP) + soundin = pick('sound/effects/treechop1.ogg', 'sound/effects/treechop2.ogg', 'sound/effects/treechop3.ogg') + if(SFX_ROCK_TAP) + soundin = pick('sound/effects/rocktap1.ogg', 'sound/effects/rocktap2.ogg', 'sound/effects/rocktap3.ogg') + if(SFX_SEAR) + soundin = 'sound/weapons/sear.ogg' + if(SFX_REEL) + soundin = pick( + 'sound/items/reel1.ogg', + 'sound/items/reel2.ogg', + 'sound/items/reel3.ogg', + 'sound/items/reel4.ogg', + 'sound/items/reel5.ogg', + ) + if(SFX_PORTAL_CLOSE) + soundin = 'sound/effects/portal_close.ogg' + if(SFX_PORTAL_ENTER) + soundin = 'sound/effects/portal_travel.ogg' + if(SFX_PORTAL_CREATED) + soundin = pick( + 'sound/effects/portal_open_1.ogg', + 'sound/effects/portal_open_2.ogg', + 'sound/effects/portal_open_3.ogg', + ) + if(SFX_SCREECH) + soundin = pick( + 'sound/creatures/monkey/monkey_screech_1.ogg', + 'sound/creatures/monkey/monkey_screech_2.ogg', + 'sound/creatures/monkey/monkey_screech_3.ogg', + 'sound/creatures/monkey/monkey_screech_4.ogg', + 'sound/creatures/monkey/monkey_screech_5.ogg', + 'sound/creatures/monkey/monkey_screech_6.ogg', + 'sound/creatures/monkey/monkey_screech_7.ogg', + ) + if(SFX_MUFFLED_SPEECH) + soundin = pick( + 'sound/effects/muffspeech/muffspeech1.ogg', + 'sound/effects/muffspeech/muffspeech2.ogg', + 'sound/effects/muffspeech/muffspeech3.ogg', + 'sound/effects/muffspeech/muffspeech4.ogg', + 'sound/effects/muffspeech/muffspeech5.ogg', + 'sound/effects/muffspeech/muffspeech6.ogg', + 'sound/effects/muffspeech/muffspeech7.ogg', + 'sound/effects/muffspeech/muffspeech8.ogg', + 'sound/effects/muffspeech/muffspeech9.ogg', + ) + if(SFX_LIQUID_POUR) + soundin = pick( + 'sound/effects/liquid_pour1.ogg', + 'sound/effects/liquid_pour2.ogg', + 'sound/effects/liquid_pour3.ogg', + ) + if(SFX_SNORE_FEMALE) + soundin = pick_weight(list( + 'sound/voice/human/snore/snore_female1.ogg' = 33, + 'sound/voice/human/snore/snore_female2.ogg' = 33, + 'sound/voice/human/snore/snore_female3.ogg' = 33, + 'sound/voice/human/snore/snore_mimimi1.ogg' = 1, + )) + if(SFX_SNORE_MALE) + soundin = pick_weight(list( + 'sound/voice/human/snore/snore_male1.ogg' = 20, + 'sound/voice/human/snore/snore_male2.ogg' = 20, + 'sound/voice/human/snore/snore_male3.ogg' = 20, + 'sound/voice/human/snore/snore_male3.ogg' = 20, + 'sound/voice/human/snore/snore_male5.ogg' = 20, + 'sound/voice/human/snore/snore_mimimi2.ogg' = 1, + )) + if(SFX_MALE_SIGH) + soundin = pick( + 'sound/voice/human/sigh/male_sigh1.ogg', + 'sound/voice/human/sigh/male_sigh2.ogg', + 'sound/voice/human/sigh/male_sigh3.ogg', + ) + if(SFX_FEMALE_SIGH) + soundin = pick( + 'sound/voice/human/sigh/female_sigh1.ogg', + 'sound/voice/human/sigh/female_sigh2.ogg', + 'sound/voice/human/sigh/female_sigh3.ogg', + ) + if(SFX_WRITING_PEN) + soundin = pick( + 'sound/effects/writing_pen/writing_pen1.ogg', + 'sound/effects/writing_pen/writing_pen2.ogg', + 'sound/effects/writing_pen/writing_pen3.ogg', + 'sound/effects/writing_pen/writing_pen4.ogg', + 'sound/effects/writing_pen/writing_pen5.ogg', + 'sound/effects/writing_pen/writing_pen6.ogg', + 'sound/effects/writing_pen/writing_pen7.ogg', + ) return soundin diff --git a/code/game/turfs/open/floor/glass.dm b/code/game/turfs/open/floor/glass.dm index c28ec9e1d4e8..09641490da0e 100644 --- a/code/game/turfs/open/floor/glass.dm +++ b/code/game/turfs/open/floor/glass.dm @@ -33,8 +33,7 @@ return INITIALIZE_HINT_LATELOAD /turf/open/floor/glass/LateInitialize() - . = ..() - AddElement(/datum/element/turf_z_transparency) + ADD_TURF_TRANSPARENCY(src, INNATE_TRAIT) setup_glow() /turf/open/floor/glass/Destroy() diff --git a/code/game/turfs/open/floor/iron_floor.dm b/code/game/turfs/open/floor/iron_floor.dm index d38aedfd4f9d..b7a4361647f1 100644 --- a/code/game/turfs/open/floor/iron_floor.dm +++ b/code/game/turfs/open/floor/iron_floor.dm @@ -219,6 +219,7 @@ icon_state = "white" base_icon_state = "white" floor_tile = /obj/item/stack/tile/iron/white + footstep = FOOTSTEP_TILES /turf/open/floor/iron/white/smooth_edge icon_state = "white_edge" @@ -254,6 +255,7 @@ icon_state = "cafeteria" base_icon_state = "cafeteria" floor_tile = /obj/item/stack/tile/iron/cafeteria + footstep = FOOTSTEP_TILES /turf/open/floor/iron/white/textured icon_state = "textured_white" @@ -386,6 +388,7 @@ icon_state = "kitchen" base_icon_state = "kitchen" floor_tile = /obj/item/stack/tile/iron/kitchen + footstep = FOOTSTEP_TILES /turf/open/floor/iron/kitchen/small icon_state = "kitchen_small" @@ -406,6 +409,7 @@ icon_state = "chapel" base_icon_state = "chapel" floor_tile = /obj/item/stack/tile/iron/chapel + footstep = FOOTSTEP_TILES /turf/open/floor/iron/showroomfloor icon_state = "showroomfloor" @@ -428,6 +432,7 @@ icon_state = "freezerfloor" base_icon_state = "freezerfloor" floor_tile = /obj/item/stack/tile/iron/freezer + footstep = FOOTSTEP_TILES /turf/open/floor/iron/freezer/airless initial_gas_mix = AIRLESS_ATMOS @@ -443,6 +448,7 @@ icon_state = "freezerfloor" base_icon_state = "freezerfloor" floor_tile = /obj/item/stack/tile/iron/freezer + footstep = FOOTSTEP_TILES /turf/open/floor/iron/grimy icon_state = "grimy" diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index f6a9dd8b77dc..61d8004e0285 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -32,8 +32,7 @@ return INITIALIZE_HINT_LATELOAD /turf/open/openspace/LateInitialize() - . = ..() - AddElement(/datum/element/turf_z_transparency) + ADD_TURF_TRANSPARENCY(src, INNATE_TRAIT) /turf/open/openspace/ChangeTurf(path, list/new_baseturfs, flags) UnregisterSignal(src, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON) diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index d404870e1c8c..f636065d5160 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -273,8 +273,7 @@ GLOBAL_LIST_EMPTY(starlight) return INITIALIZE_HINT_LATELOAD /turf/open/space/openspace/LateInitialize() - . = ..() - AddElement(/datum/element/turf_z_transparency) + ADD_TURF_TRANSPARENCY(src, INNATE_TRAIT) /turf/open/space/openspace/Destroy() // Signals persist through destroy, GO HOME diff --git a/code/modules/antagonists/heretic/magic/mansus_grasp.dm b/code/modules/antagonists/heretic/magic/mansus_grasp.dm index 4ba6aceb2009..cc985f3d9a03 100644 --- a/code/modules/antagonists/heretic/magic/mansus_grasp.dm +++ b/code/modules/antagonists/heretic/magic/mansus_grasp.dm @@ -83,7 +83,7 @@ remove_hand_with_no_refund(user) /obj/item/melee/touch_attack/mansus_fist/ignition_effect(atom/to_light, mob/user) - . = span_notice("[user] effortlessly snaps [user.p_their()] fingers near [to_light], igniting it with eldritch energies. Fucking badass!") + . = span_rose("[user] effortlessly snaps [user.p_their()] fingers near [to_light], igniting it with eldritch energies. Fucking badass!") remove_hand_with_no_refund(user) /obj/item/melee/touch_attack/mansus_fist/suicide_act(mob/living/user) diff --git a/code/modules/antagonists/heretic/magic/star_touch.dm b/code/modules/antagonists/heretic/magic/star_touch.dm index 9037d07295a9..d5a68712f912 100644 --- a/code/modules/antagonists/heretic/magic/star_touch.dm +++ b/code/modules/antagonists/heretic/magic/star_touch.dm @@ -91,7 +91,7 @@ remove_hand_with_no_refund(user) /obj/item/melee/touch_attack/star_touch/ignition_effect(atom/to_light, mob/user) - . = span_notice("[user] effortlessly snaps [user.p_their()] fingers near [to_light], igniting it with cosmic energies. Fucking badass!") + . = span_rose("[user] effortlessly snaps [user.p_their()] fingers near [to_light], igniting it with cosmic energies. Fucking badass!") remove_hand_with_no_refund(user) /obj/item/melee/touch_attack/star_touch/attack_self(mob/living/user) diff --git a/code/modules/antagonists/ninja/ninja_clothing.dm b/code/modules/antagonists/ninja/ninja_clothing.dm index 54ed46c9c3ec..4eaf40f9c79c 100644 --- a/code/modules/antagonists/ninja/ninja_clothing.dm +++ b/code/modules/antagonists/ninja/ninja_clothing.dm @@ -15,7 +15,8 @@ resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF flags_inv = HIDEFACIALHAIR | HIDEFACE | HIDESNOUT flags_cover = MASKCOVERSMOUTH | PEPPERPROOF - has_fov = FALSE + pepper_tint = FALSE + /obj/item/clothing/under/syndicate/ninja name = "ninja suit" diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm index 75354c0eee39..f65f0f9a89e1 100644 --- a/code/modules/atmospherics/environmental/LINDA_fire.dm +++ b/code/modules/atmospherics/environmental/LINDA_fire.dm @@ -15,6 +15,28 @@ /turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) return +/turf/open/proc/set_active_hotspot(obj/effect/hotspot/new_lad) + if(active_hotspot == new_lad) + return + var/hotspot_around = NONE + if(active_hotspot) + if(new_lad) + hotspot_around = active_hotspot.smoothing_junction + if(!QDELETED(active_hotspot)) + QDEL_NULL(active_hotspot) + else + for(var/direction in GLOB.cardinals) + var/turf/open/open = get_step(src, direction) + if(!isopenturf(open) || !open.active_hotspot) + continue + var/existing_directions = open.active_hotspot.smoothing_junction + open.active_hotspot.set_smoothed_icon_state(existing_directions | REVERSE_DIR(direction)) + hotspot_around |= direction + + active_hotspot = new_lad + if(active_hotspot) + active_hotspot.set_smoothed_icon_state(hotspot_around) + /** * Handles the creation of hotspots and initial activation of turfs. * Setting the conditions for the reaction to actually happen for gasmixtures @@ -55,10 +77,13 @@ if(((exposed_temperature > PLASMA_MINIMUM_BURN_TEMPERATURE) && (plas > 0.5 || trit > 0.5 || h2 > 0.5)) || \ ((exposed_temperature < FREON_MAXIMUM_BURN_TEMPERATURE) && (freon > 0.5))) - active_hotspot = new /obj/effect/hotspot(src, exposed_volume*25, exposed_temperature) + set_active_hotspot(new /obj/effect/hotspot(src, exposed_volume * 25, exposed_temperature)) + if(COOLDOWN_FINISHED(src, fire_puff_cooldown)) + playsound(src, 'sound/effects/fire_puff.ogg', 30) + COOLDOWN_START(src, fire_puff_cooldown, 5 SECONDS) active_hotspot.just_spawned = (current_cycle < SSair.times_fired) - //remove just_spawned protection if no longer processing this cell + //remove just_spawned protection if no longer processing this cell SSair.add_to_active(src) /** @@ -78,6 +103,9 @@ light_power = 1 light_color = LIGHT_COLOR_FIRE + /// base sprite used for our icon states when smoothing + /// BAAAASICALY the same as icon_state but is helpful to avoid duplicated work + var/fire_stage = "" /** * Volume is the representation of how big and healthy a fire is. * Hotspot volume will be divided by turf volume to get the ratio for temperature setting on non bypassing mode. @@ -93,7 +121,8 @@ var/visual_update_tick = 0 ///Are we burning freon? var/cold_fire = FALSE - + ///the group of hotspots we are a part of + var/datum/hot_group/our_hot_group /obj/effect/hotspot/Initialize(mapload, starting_volume, starting_temperature) . = ..() @@ -110,6 +139,24 @@ COMSIG_ATOM_ABSTRACT_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) + var/turf/open/our_turf = loc + //on creation we check adjacent turfs for hot spot to start grouping, if surrounding do not have hot spots we create our own + for(var/turf/open/to_check as anything in our_turf.atmos_adjacent_turfs) + if(to_check.active_hotspot) + var/obj/effect/hotspot/enemy_spot = to_check.active_hotspot + if(!our_hot_group) + enemy_spot.our_hot_group.add_to_group(src) + else if(our_hot_group != enemy_spot.our_hot_group && enemy_spot.our_hot_group) //if we belongs to a hot group from prior loop and we encounter another hot spot with a group then we merge + our_hot_group.merge_hot_groups(enemy_spot.our_hot_group) + if(!our_hot_group)//if after loop through all the adjacents turfs and we havent belong to a group yet, make our own + our_hot_group = new + our_hot_group.add_to_group(src) + +/obj/effect/hotspot/set_smoothed_icon_state(new_junction) + + smoothing_junction = new_junction + + update_color() /** * Perform interactions between the hotspot and the gasmixture. @@ -130,7 +177,7 @@ if(!istype(location) || !(location.air)) return - location.active_hotspot = src + location.set_active_hotspot(src) bypassing = !just_spawned && (volume > CELL_VOLUME*0.95) @@ -199,7 +246,7 @@ sparkle_overlay.alpha = sparkle_amt * 255 add_overlay(sparkle_overlay) if(temperature > 400000 && temperature < 1500000) //Lightning because very anime. - var/mutable_appearance/lightning_overlay = mutable_appearance(icon, "overcharged") + var/mutable_appearance/lightning_overlay = mutable_appearance('icons/effects/fire.dmi', "overcharged") lightning_overlay.blend_mode = BLEND_ADD add_overlay(lightning_overlay) if(temperature > 4500000) //This is where noblium happens. Some fusion-y effects. @@ -264,7 +311,7 @@ perform_exposure() if(bypassing) - icon_state = "3" + set_fire_stage("heavy") if(!cold_fire) location.burn_tile() @@ -280,20 +327,30 @@ else if(volume > CELL_VOLUME*0.4) - icon_state = "2" + set_fire_stage("medium") else - icon_state = "1" + set_fire_stage("light") if((visual_update_tick++ % 7) == 0) update_color() return TRUE +/obj/effect/hotspot/proc/set_fire_stage(stage) + if(fire_stage == stage) + return + fire_stage = stage + icon_state = stage + dir = pick(GLOB.cardinals) + update_color() + /obj/effect/hotspot/Destroy() SSair.hotspots -= src var/turf/open/T = loc if(istype(T) && T.active_hotspot == src) - T.active_hotspot = null + our_hot_group.remove_from_group(src) + our_hot_group = null + T.set_active_hotspot(null) return ..() /obj/effect/hotspot/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) @@ -305,4 +362,95 @@ /obj/effect/hotspot/singularity_pull() return +/datum/looping_sound/fire + mid_sounds = list('sound/effects/fireclip1.ogg' = 1, 'sound/effects/fireclip2.ogg' = 1, 'sound/effects/fireclip3.ogg' = 1, 'sound/effects/fireclip4.ogg' = 1, + 'sound/effects/fireclip5.ogg' = 1, 'sound/effects/fireclip6.ogg' = 1, 'sound/effects/fireclip7.ogg' = 1) + volume = 30 + mid_length = 2 SECONDS + falloff_distance = 1 + +#define MIN_SIZE_SOUND 2 +///handle the grouping of hotspot and then determining an average center to play sound in +/datum/hot_group + var/list/obj/effect/hotspot/spot_list = list() + ///the sound center turf which the looping sound will play + var/turf/open/current_sound_loc + var/datum/looping_sound/fire/sound + var/tiles_limit = 80 // arbitrary limit so we dont have one giant group + ///these lists and average var are to find the average center of a group + var/list/x_coord = list() + var/list/y_coord = list() + var/list/z_coord = list() + var/average_x + var/average_y + var/average_Z + ///the range for the sound to drop off based on the size of the group + var/drop_off_dist + COOLDOWN_DECLARE(update_sound_center) + + +/datum/hot_group/Destroy() + . = ..() + current_sound_loc = null + spot_list = null + qdel(sound) + +/datum/hot_group/proc/remove_from_group(obj/effect/hotspot/target) + spot_list -= target + var/turf/open/target_turf = target.loc + x_coord -= target_turf.x + y_coord -= target_turf.y + if(!length(spot_list)) + qdel(src) + return + +/datum/hot_group/proc/add_to_group(obj/effect/hotspot/target) + spot_list += target + target.our_hot_group = src + var/turf/open/target_turf = target.loc + x_coord += target_turf.x + y_coord += target_turf.y + z_coord += target_turf.z + if(COOLDOWN_FINISHED(src, update_sound_center) && length(spot_list) > MIN_SIZE_SOUND)//arbitrary size to start playing the sound + update_sound() + COOLDOWN_START(src, update_sound_center, 5 SECONDS) + +/datum/hot_group/proc/merge_hot_groups(datum/hot_group/enemy_group) + if(length(spot_list) >= tiles_limit || length(enemy_group.spot_list) >= tiles_limit) + return + var/datum/hot_group/saving_group + var/datum/hot_group/sacrificial_group + if(length(spot_list) > length(enemy_group.spot_list) || (length(spot_list) == length(enemy_group.spot_list) && prob(50)))//we're bigger take all of their territory! + saving_group = src + sacrificial_group = enemy_group + else + saving_group = enemy_group + sacrificial_group = src + for(var/obj/effect/hotspot/reference as anything in sacrificial_group.spot_list) + reference.our_hot_group = saving_group + saving_group.spot_list += sacrificial_group.spot_list + saving_group.x_coord += sacrificial_group.x_coord + saving_group.y_coord += sacrificial_group.y_coord + qdel(sacrificial_group) + if(COOLDOWN_FINISHED(src, update_sound_center) && length(spot_list) > MIN_SIZE_SOUND)//arbitrary size to start playing the sound + update_sound() + COOLDOWN_START(src, update_sound_center, 5 SECONDS) + +/datum/hot_group/proc/update_sound() + //we can draw a cross around the average middle of any globs of group, curves or hollow groups may cause issues with this + average_x = round((max(x_coord) + min(x_coord))/2) + average_y = round((max(y_coord) + min(y_coord))/2) + average_Z = round((min(z_coord) + max(z_coord))/2) + drop_off_dist = max((max(y_coord) - min(y_coord)), (max(x_coord) - min(x_coord)), 1)// pick the largest value between the width and length of the group to determine sound drop off + var/turf/open/sound_turf = locate(average_x, average_y, average_Z) + if(sound) + sound.falloff_distance = drop_off_dist + if(sound_turf != current_sound_loc) + sound.parent = sound_turf + return + sound = new(sound_turf, TRUE) + sound.falloff_distance = drop_off_dist + current_sound_loc = sound_turf + +#undef MIN_SIZE_SOUND #undef INSUFFICIENT diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index a5822084b61d..4bc54df2a2aa 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -50,6 +50,8 @@ ///gas IDs of current active gas overlays var/list/atmos_overlay_types var/significant_share_ticker = 0 + ///the cooldown on playing a fire starting sound each time a tile is ignited + COOLDOWN_DECLARE(fire_puff_cooldown) #ifdef TRACK_MAX_SHARE var/max_share = 0 #endif @@ -679,5 +681,6 @@ Then we space some of our heat, and think about if we should stop conducting. temperature += heat / heat_capacity //The higher your own heat cap the less heat you get from this arrangement sharer.temperature -= heat / sharer.heat_capacity + #undef LAST_SHARE_CHECK #undef PLANET_SHARE_CHECK diff --git a/code/modules/buildmode/buttons.dm b/code/modules/buildmode/buttons.dm index ca48ec2767e1..aa885a6e6825 100644 --- a/code/modules/buildmode/buttons.dm +++ b/code/modules/buildmode/buttons.dm @@ -1,5 +1,6 @@ /atom/movable/screen/buildmode icon = 'icons/misc/buildmode.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER var/datum/buildmode/bd // If we don't do this, we get occluded by item action buttons plane = ABOVE_HUD_PLANE diff --git a/code/modules/cargo/goodies.dm b/code/modules/cargo/goodies.dm index 7b1850514788..e9e3a90b1a0d 100644 --- a/code/modules/cargo/goodies.dm +++ b/code/modules/cargo/goodies.dm @@ -219,6 +219,75 @@ cost = PAYCHECK_CREW * 10 contains = list(/obj/item/construction/rld) +// All this does is generate the supply packs for the language keys +/datum/supply_pack/language_keys_constructor + +/datum/supply_pack/language_keys_constructor/generate_supply_packs() + . = list() + + var/datum/preference/languages/language_pref = GLOB.preference_entries[/datum/preference/languages] + for(var/langtype in language_pref.selectable_languages) + var/datum/language/lang = GLOB.language_datum_instances[langtype] + + var/datum/supply_pack/goody/language_keys/pack = new + pack.target_language = langtype + pack.translation_power = 100 + pack.name = "[lang.name] radio translation key" + pack.desc = "A hi-tech radio encryption key that allows the wearer to understand [lang.name] when the radio is worn." + pack.cost = PAYCHECK_COMMAND * 12 + pack.id = "[pack.type]_[langtype]_full" + pack.contains = list(/obj/item/encryptionkey/language) + + . += pack + + var/datum/supply_pack/goody/language_keys/budget_pack = new + budget_pack.target_language = langtype + budget_pack.translation_power = (lang.mutual_understanding?[/datum/language/common] ? 75 : 50) + budget_pack.name = "[lang.name] budget radio translation key" + budget_pack.desc = "A budget radio encryption key that allows the wearer to understand *some* words in [lang.name] when the radio is worn." + budget_pack.cost = PAYCHECK_COMMAND * 4 + budget_pack.id = "[budget_pack.type]_[langtype]_budget" + budget_pack.contains = list(/obj/item/encryptionkey/language) + + . += budget_pack + +// These are auto-generated by the language_keys_constructor +/datum/supply_pack/goody/language_keys + group = "Language Keys (Goodies)" + /// Language this pack is made for + var/target_language + /// How good the translation is + var/translation_power = 100 + +/datum/supply_pack/goody/language_keys/fill(obj/structure/closet/crate/crate) + var/obj/item/encryptionkey/language/key = new(crate) + key.language_data = list() + key.language_data[target_language] = translation_power // i am afraid of byond butchering this so i'm doing it across two lines + key.name = "\improper [src.name]" + key.desc = src.desc + + var/list/jokes = list( + /datum/language/draconic = "The signal's not quite to scale.", + /datum/language/voltaic = "The signal's overpowering.", + /datum/language/nekomimetic = "The signal's rather scratchy.", + /datum/language/moffic = "The signal's a little fuzzy.", + /datum/language/calcic = "The signal lacks a bit of teeth.", + /datum/language/uncommon = "The signal's a bit distorted.", + ) + + if(jokes[target_language]) + key.desc += " [jokes[target_language]]" + + if(admin_spawned) + key.flags_1 |= ADMIN_SPAWNED_1 + +/datum/supply_pack/goody/all_crew_translation + name = "Crew Cohesion radio translation key" + desc = "A radio encryption key that allows the wearer to understand a few words in most languages spoken by the crew." + group = /datum/supply_pack/goody/language_keys::group + cost = PAYCHECK_COMMAND * 16 + contains = list(/obj/item/encryptionkey/language/all_crew) + /datum/supply_pack/goody/fishing_toolbox name = "Fishing toolbox" desc = "Complete toolbox set for your fishing adventure. Advanced hooks and lines sold separetely." diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm index 3f8ceb5ca021..5bf00c49d80a 100644 --- a/code/modules/cargo/order.dm +++ b/code/modules/cargo/order.dm @@ -190,11 +190,10 @@ generateManifest(crate, account_holder, pack, pack.cost) return crate -/datum/supply_order/proc/generateCombo(miscbox, misc_own, misc_contents, misc_cost) - for (var/I in misc_contents) - new I(miscbox) +/datum/supply_order/proc/generateCombo(obj/miscbox, misc_own, list/datum/supply_pack/misc_contents, misc_cost) + for (var/datum/supply_pack/pack as anything in misc_contents) + pack.fill(miscbox) generateManifest(miscbox, misc_own, "", misc_cost) - return /datum/supply_order/proc/append_order(list/new_contents, cost_increase) for(var/i as anything in new_contents) diff --git a/code/modules/clothing/head/hat.dm b/code/modules/clothing/head/hat.dm index aebb4dc112d1..13373fd71cf5 100644 --- a/code/modules/clothing/head/hat.dm +++ b/code/modules/clothing/head/hat.dm @@ -187,6 +187,7 @@ name = "santa hat" desc = "On the first day of christmas my employer gave to me!" icon_state = "santa_hat" + icon_state_preview = "santahatnorm" greyscale_colors = "#cc0000#f8f8f8" greyscale_config = /datum/greyscale_config/santa_hat greyscale_config_worn = /datum/greyscale_config/santa_hat/worn diff --git a/code/modules/clothing/masks/costume.dm b/code/modules/clothing/masks/costume.dm index 64fa86d0d354..16e22055210d 100644 --- a/code/modules/clothing/masks/costume.dm +++ b/code/modules/clothing/masks/costume.dm @@ -44,6 +44,7 @@ name = "kitsune mask" desc = "Porcelain mask made in the style of the Sol-3 region. It is painted to look like a kitsune." icon_state = "kitsune" + icon_state_preview = "kitsune_base" inhand_icon_state = null w_class = WEIGHT_CLASS_SMALL adjusted_flags = ITEM_SLOT_HEAD diff --git a/code/modules/clothing/masks/gas_filter.dm b/code/modules/clothing/masks/gas_filter.dm index 08ae650c2472..58e518a8c4da 100644 --- a/code/modules/clothing/masks/gas_filter.dm +++ b/code/modules/clothing/masks/gas_filter.dm @@ -1,15 +1,15 @@ ///Filtering ratio for high amounts of gas -#define HIGH_FILTERING_RATIO 0.001 +#define HIGH_FILTERING_RATIO 0.01 ///Filtering ratio for min amount of gas -#define LOW_FILTERING_RATIO 0.0005 +#define LOW_FILTERING_RATIO 0.0025 ///Min amount of high filtering gases for high filtering ratio #define HIGH_FILTERING_MOLES 0.001 ///Min amount of mid filtering gases for high filtering ratio #define MID_FILTERING_MOLES 0.0025 ///Min amount of low filtering gases for high filtering ratio -#define LOW_FILTERING_MOLES 0.0005 +#define LOW_FILTERING_MOLES 0.005 ///Min amount of wear that the filter gets when used -#define FILTERS_CONSTANT_WEAR 0.05 +#define FILTERS_CONSTANT_WEAR 0.025 /obj/item/gas_filter name = "atmospheric gas filter" @@ -71,23 +71,23 @@ if(gas_id in high_filtering_gases) if(breath.gases[gas_id][MOLES] > HIGH_FILTERING_MOLES) breath.gases[gas_id][MOLES] = max(breath.gases[gas_id][MOLES] - filter_strength_high * filter_efficiency * HIGH_FILTERING_RATIO, 0) - danger_points += 0.5 + danger_points += 1 continue breath.gases[gas_id][MOLES] = max(breath.gases[gas_id][MOLES] - filter_strength_high * filter_efficiency * LOW_FILTERING_RATIO, 0) - danger_points += 0.05 + danger_points += 0.2 continue if(gas_id in mid_filtering_gases) if(breath.gases[gas_id][MOLES] > MID_FILTERING_MOLES) breath.gases[gas_id][MOLES] = max(breath.gases[gas_id][MOLES] - filter_strength_mid * filter_efficiency * HIGH_FILTERING_RATIO, 0) - danger_points += 0.75 + danger_points += 1.25 continue breath.gases[gas_id][MOLES] = max(breath.gases[gas_id][MOLES] - filter_strength_mid * filter_efficiency * LOW_FILTERING_RATIO, 0) - danger_points += 0.15 + danger_points += 0.25 continue if(gas_id in low_filtering_gases) if(breath.gases[gas_id][MOLES] > LOW_FILTERING_MOLES) breath.gases[gas_id][MOLES] = max(breath.gases[gas_id][MOLES] - filter_strength_low * filter_efficiency * HIGH_FILTERING_RATIO, 0) - danger_points += 1 + danger_points += 1.5 continue breath.gases[gas_id][MOLES] = max(breath.gases[gas_id][MOLES] - filter_strength_low * filter_efficiency * LOW_FILTERING_RATIO, 0) danger_points += 0.5 diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index a74d8bfca401..1fb6f63c8021 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -18,17 +18,20 @@ GLOBAL_LIST_INIT(clown_mask_options, list( armor_type = /datum/armor/mask_gas flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH | PEPPERPROOF resistance_flags = NONE + voice_filter = "lowpass=f=750,volume=2" ///Max numbers of installable filters var/max_filters = 1 ///List to keep track of each filter var/list/gas_filters ///Type of filter that spawns on roundstart var/starting_filter_type = /obj/item/gas_filter - ///Does the mask have an FOV? - var/has_fov = TRUE ///Cigarette in the mask var/obj/item/clothing/mask/cigarette/cig - voice_filter = "lowpass=f=750,volume=2" + ///How much does this mask affect fishing difficulty + var/fishing_modifier = 2 + ///Applies clothing_dirt component to the pepperproof mask if true + var/pepper_tint = TRUE + /datum/armor/mask_gas bio = 100 @@ -39,7 +42,10 @@ GLOBAL_LIST_INIT(clown_mask_options, list( /obj/item/clothing/mask/gas/Initialize(mapload) . = ..() - init_fov() + + if((flags_cover & PEPPERPROOF) && pepper_tint) + AddComponent(/datum/component/clothing_dirt) + if(!max_filters || !starting_filter_type) return @@ -84,10 +90,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( var/valid_wearer = ismob(loc) var/mob/wearer = loc if(istype(tool, /obj/item/clothing/mask/cigarette)) - if(flags_cover & MASKCOVERSMOUTH) - balloon_alert(user, "mask's mouth is covered!") - return ..() - if(max_filters <= 0 || cig) balloon_alert(user, "can't hold that!") return ..() @@ -153,11 +155,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( has_filter = FALSE return filtered_breath -/// Initializes the FoV component for the gas mask -/obj/item/clothing/mask/gas/proc/init_fov() - if (has_fov) - AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) - /** * Getter for overall filter durability, takes into consideration all filters filter_status */ @@ -245,8 +242,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list( icon_state = "plaguedoctor" flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT|HIDEHAIR inhand_icon_state = "gas_mask" - has_fov = FALSE - flags_cover = MASKCOVERSEYES + clothing_flags = BLOCK_GAS_SMOKE_EFFECT|MASKINTERNALS /obj/item/clothing/mask/gas/syndicate name = "syndicate mask" @@ -256,7 +252,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list( resistance_flags = FIRE_PROOF | ACID_PROOF strip_delay = 60 w_class = WEIGHT_CLASS_SMALL - has_fov = FALSE + pepper_tint = FALSE /obj/item/clothing/mask/gas/clown_hat name = "clown wig and mask" @@ -272,7 +268,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( resistance_flags = FLAMMABLE actions_types = list(/datum/action/item_action/adjust) dog_fashion = /datum/dog_fashion/head/clown - has_fov = FALSE var/list/clownmask_designs = list() voice_filter = null // performer masks expect to be talked through @@ -316,7 +311,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( righthand_file = 'icons/mob/inhands/clothing/hats_righthand.dmi' flags_cover = MASKCOVERSEYES resistance_flags = FLAMMABLE - has_fov = FALSE /obj/item/clothing/mask/gas/mime name = "mime mask" @@ -329,7 +323,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( resistance_flags = FLAMMABLE actions_types = list(/datum/action/item_action/adjust) species_exception = list(/datum/species/golem) - has_fov = FALSE var/list/mimemask_designs = list() /obj/item/clothing/mask/gas/mime/plasmaman @@ -373,7 +366,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( inhand_icon_state = "owl_mask" flags_cover = MASKCOVERSEYES resistance_flags = FLAMMABLE - has_fov = FALSE /obj/item/clothing/mask/gas/sexymime name = "sexy mime mask" @@ -384,14 +376,12 @@ GLOBAL_LIST_INIT(clown_mask_options, list( flags_cover = MASKCOVERSEYES resistance_flags = FLAMMABLE species_exception = list(/datum/species/golem) - has_fov = FALSE /obj/item/clothing/mask/gas/cyborg name = "cyborg visor" desc = "Beep boop." icon_state = "death" resistance_flags = FLAMMABLE - has_fov = FALSE flags_cover = MASKCOVERSEYES /obj/item/clothing/mask/gas/owl_mask @@ -402,14 +392,12 @@ GLOBAL_LIST_INIT(clown_mask_options, list( clothing_flags = MASKINTERNALS flags_cover = MASKCOVERSEYES resistance_flags = FLAMMABLE - has_fov = FALSE /obj/item/clothing/mask/gas/carp name = "carp mask" desc = "Gnash gnash." icon_state = "carp_mask" inhand_icon_state = null - has_fov = FALSE flags_cover = MASKCOVERSEYES /obj/item/clothing/mask/gas/tiki_mask @@ -419,7 +407,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( inhand_icon_state = null custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 1.25) resistance_flags = FLAMMABLE - has_fov = FALSE flags_cover = MASKCOVERSEYES max_integrity = 100 actions_types = list(/datum/action/item_action/adjust) @@ -465,7 +452,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( inhand_icon_state = "gas_atmos" resistance_flags = FIRE_PROOF | ACID_PROOF flags_inv = HIDEFACIALHAIR|HIDEFACE|HIDEEYES|HIDEEARS|HIDEHAIR|HIDESNOUT - has_fov = FALSE /obj/item/clothing/mask/gas/prop name = "prop gas mask" @@ -475,7 +461,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( clothing_flags = NONE flags_cover = MASKCOVERSMOUTH resistance_flags = FLAMMABLE - has_fov = FALSE /obj/item/clothing/mask/gas/atmosprop name = "prop atmospheric gas mask" @@ -486,7 +471,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list( clothing_flags = NONE flags_cover = MASKCOVERSMOUTH resistance_flags = FLAMMABLE - has_fov = FALSE /obj/item/clothing/mask/gas/driscoll name = "driscoll mask" diff --git a/code/modules/clothing/masks/hailer.dm b/code/modules/clothing/masks/hailer.dm index 963d107fd477..e56e0b99de44 100644 --- a/code/modules/clothing/masks/hailer.dm +++ b/code/modules/clothing/masks/hailer.dm @@ -56,7 +56,6 @@ GLOBAL_LIST_INIT(hailer_phrases, list( flags_cover = MASKCOVERSMOUTH | PEPPERPROOF visor_flags_cover = MASKCOVERSMOUTH | PEPPERPROOF tint = 0 - has_fov = FALSE unique_death = 'sound/voice/sec_death.ogg' COOLDOWN_DECLARE(hailer_cooldown) ///Decides the phrases available for use; defines used are the last index of a category of available phrases @@ -88,6 +87,7 @@ GLOBAL_LIST_INIT(hailer_phrases, list( visor_flags_cover = MASKCOVERSMOUTH | MASKCOVERSEYES | PEPPERPROOF drop_sound = 'maplestation_modules/sound/items/drop/helm.ogg' pickup_sound = 'maplestation_modules/sound/items/pickup/helm.ogg' + pepper_tint = FALSE /obj/item/clothing/mask/gas/sechailer/swat/spacepol name = "spacepol mask" diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm index e504d476089f..3cfacde19cf3 100644 --- a/code/modules/clothing/shoes/boots.dm +++ b/code/modules/clothing/shoes/boots.dm @@ -23,8 +23,8 @@ /obj/item/clothing/shoes/combat/Initialize(mapload) . = ..() - create_storage(storage_type = /datum/storage/pockets/shoes) + AddElement(/datum/element/ignites_matches) /obj/item/clothing/shoes/combat/swat //overpowered boots for death squads name = "\improper SWAT boots" @@ -73,6 +73,11 @@ /datum/armor/shoes_jackboots bio = 90 +/obj/item/clothing/shoes/jackboots/Initialize(mapload) + . = ..() + create_storage(storage_type = /datum/storage/pockets/shoes) + AddElement(/datum/element/ignites_matches) + /obj/item/clothing/shoes/jackboots/fast slowdown = -1 @@ -110,8 +115,8 @@ /obj/item/clothing/shoes/winterboots/Initialize(mapload) . = ..() - create_storage(storage_type = /datum/storage/pockets/shoes) + AddElement(/datum/element/ignites_matches) /obj/item/clothing/shoes/winterboots/ice_boots name = "ice hiking boots" @@ -159,8 +164,8 @@ /obj/item/clothing/shoes/workboots/Initialize(mapload) . = ..() - create_storage(storage_type = /datum/storage/pockets/shoes) + AddElement(/datum/element/ignites_matches) /obj/item/clothing/shoes/workboots/mining name = "mining boots" @@ -179,8 +184,8 @@ /obj/item/clothing/shoes/russian/Initialize(mapload) . = ..() - create_storage(storage_type = /datum/storage/pockets/shoes) + AddElement(/datum/element/ignites_matches) /obj/item/clothing/shoes/discoshoes name = "green lizardskin shoes" diff --git a/code/modules/clothing/shoes/clown.dm b/code/modules/clothing/shoes/clown.dm index dea346b8613b..94fd81e3b0ed 100644 --- a/code/modules/clothing/shoes/clown.dm +++ b/code/modules/clothing/shoes/clown.dm @@ -15,6 +15,7 @@ create_storage(storage_type = /datum/storage/pockets/shoes/clown) LoadComponent(/datum/component/squeak, squeak_sound, 50, falloff_exponent = 20) //die off quick please AddElement(/datum/element/swabable, CELL_LINE_TABLE_CLOWN, CELL_VIRUS_TABLE_GENERIC, rand(2,3), 0) + AddElement(/datum/element/ignites_matches) /obj/item/clothing/shoes/clown_shoes/equipped(mob/living/user, slot) . = ..() diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm index a033a561439f..ee8ca1b92d2e 100644 --- a/code/modules/clothing/shoes/cowboy.dm +++ b/code/modules/clothing/shoes/cowboy.dm @@ -16,16 +16,12 @@ /obj/item/clothing/shoes/cowboy/Initialize(mapload) . = ..() - create_storage(storage_type = /datum/storage/pockets/shoes) - - if(prob(2)) - //There's a snake in my boot + if(prob(2)) //There's a snake in my boot new /mob/living/basic/snake(src) - if(has_spurs) LoadComponent(/datum/component/squeak, spur_sound, 50, falloff_exponent = 20) - + AddElement(/datum/element/ignites_matches) /obj/item/clothing/shoes/cowboy/equipped(mob/living/carbon/user, slot) . = ..() diff --git a/code/modules/clothing/suits/moth.dm b/code/modules/clothing/suits/moth.dm index 5a9dc725456b..27f3a3b1df32 100644 --- a/code/modules/clothing/suits/moth.dm +++ b/code/modules/clothing/suits/moth.dm @@ -2,6 +2,8 @@ name = "mothic flightsuit" desc = "This peculiar utility harness is a common sight among the moth fleet's crews due to its ability to fasten the wings to the body without impacting mobility inside cramped ship interiors. It looks somewhat crude yet it's surprisingly comfortable." icon_state = "mothcoat" + icon_preview = 'icons/obj/clothing/suits/moth.dmi' + icon_state_preview = "mothcoat" greyscale_config = /datum/greyscale_config/mothcoat greyscale_config_worn = /datum/greyscale_config/mothcoat/worn greyscale_colors = "#eaeaea" @@ -23,6 +25,7 @@ name = "mothic mantella" desc = "A thick garment that keeps warm and protects those precious wings from harsh weather, also commonly used during festivities. Feels much heavier than it looks." icon_state = "mothcoat_winter" + icon_state_preview = "mothcoat_mantle_top" greyscale_config = /datum/greyscale_config/mothcoat_winter greyscale_config_worn = /datum/greyscale_config/mothcoat_winter/worn greyscale_colors = "#557979#795e55" diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm index 289c59ae3d13..5a6ff84d729a 100644 --- a/code/modules/clothing/under/shorts.dm +++ b/code/modules/clothing/under/shorts.dm @@ -2,6 +2,8 @@ name = "shorts" desc = "A pair of comfy shorts." icon_state = "shorts" + icon_preview = 'icons/obj/clothing/under/shorts_pants_shirts.dmi' + icon_state_preview = "shorts" greyscale_config = /datum/greyscale_config/shorts greyscale_config_worn = /datum/greyscale_config/shorts/worn greyscale_colors = "#575757#3E3E3E#75634F" diff --git a/code/modules/clothing/under/skirt_dress.dm b/code/modules/clothing/under/skirt_dress.dm index 31e74ff11524..d8200220f327 100644 --- a/code/modules/clothing/under/skirt_dress.dm +++ b/code/modules/clothing/under/skirt_dress.dm @@ -55,6 +55,8 @@ name = "turtleneck skirt" desc = "A casual turtleneck skirt." icon_state = "turtleskirt" + icon_preview = 'icons/obj/clothing/under/dress.dmi' + icon_state_preview = "turtleskirt_top" custom_price = PAYCHECK_CREW greyscale_colors = "#cc0000#5f5f5f" greyscale_config = /datum/greyscale_config/turtleskirt @@ -65,6 +67,8 @@ name = "tango dress" desc = "Filled with Latin fire." icon_state = "tango" + icon_preview = 'icons/obj/clothing/under/dress.dmi' + icon_state_preview = "tango_base" custom_price = PAYCHECK_CREW greyscale_colors = "#ff0000#1c1c1c" greyscale_config = /datum/greyscale_config/tango @@ -75,6 +79,8 @@ name = "sundress" desc = "Makes you want to frolic in a field of daisies." icon_state = "sundress" + icon_preview = 'icons/obj/clothing/under/dress.dmi' + icon_state_preview = "sundress_base" custom_price = PAYCHECK_CREW greyscale_colors = "#FFE60F#9194A5#1F243C" greyscale_config = /datum/greyscale_config/sundress diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index f59aa5e85cce..bbbb18313d45 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -237,6 +237,7 @@ if(!user.can_perform_action(src)) return balloon_alert(user, "writing box tag...") + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) boxtag_set = TRUE update_appearance() return diff --git a/code/modules/hallucination/station_message.dm b/code/modules/hallucination/station_message.dm index 97b37e77cd9e..2c4b81f4179d 100644 --- a/code/modules/hallucination/station_message.dm +++ b/code/modules/hallucination/station_message.dm @@ -80,7 +80,7 @@ priority_announce( text = "Figments from an eldritch god are being summoned by [totally_real_cult_leader.real_name] into [fake_summon_area] from an unknown dimension. Disrupt the ritual at all costs!", title = "[command_name()] Higher Dimensional Affairs", - sound = 'sound/ambience/antag/bloodcult/bloodcult_scribe.ogg', + sound = /*'sound/ambience/antag/bloodcult/bloodcult_scribe.ogg'*/ANNOUNCER_SPANOMALIES, has_important_message = TRUE, players = list(hallucinator), ) diff --git a/code/modules/language/_language_holder.dm b/code/modules/language/_language_holder.dm index f061ed2bab35..3dc09d9dbf5c 100644 --- a/code/modules/language/_language_holder.dm +++ b/code/modules/language/_language_holder.dm @@ -52,6 +52,10 @@ Key procs var/selected_language /// Tracks the entity that owns the holder. var/atom/movable/owner + /// Lazyassoclist of all other mutual understanding this holder has in addition to what they understand from their understood languages. + /// This is primarily for adding mutual understanding from other sources at runtime. + /// Format: list(language_type = list(source = % of understanding)) + var/list/other_mutual_understanding /// Initializes, and copies in the languages from the current atom if available. /datum/language_holder/New(atom/new_owner) @@ -91,6 +95,11 @@ Key procs omnitongue = TRUE return TRUE +/datum/language_holder/proc/grant_partial_language(language, amount = 50, source = LANGUAGE_MIND) + LAZYINITLIST(other_mutual_understanding) + LAZYSET(other_mutual_understanding[language], source, amount) + return TRUE + /// Removes a single language or source, removing all sources returns the pre-removal state of the language. /datum/language_holder/proc/remove_language(language, language_flags = ALL, source = LANGUAGE_ALL) if(language_flags & UNDERSTOOD_LANGUAGE) @@ -117,6 +126,17 @@ Key procs omnitongue = FALSE return TRUE +/datum/language_holder/proc/remove_partial_language(language, source = LANGUAGE_MIND) + LAZYREMOVE(other_mutual_understanding[language], source) + ASSOC_UNSETEMPTY(other_mutual_understanding, language) + UNSETEMPTY(other_mutual_understanding) + return TRUE + +/datum/language_holder/proc/remove_all_partial_languages(source = LANGUAGE_MIND) + for(var/language in other_mutual_understanding) + remove_partial_language(language, source) + return TRUE + /// Adds a single language or list of languages to the blocked language list. /datum/language_holder/proc/add_blocked_language(languages, source = LANGUAGE_MIND) if(!islist(languages)) @@ -183,9 +203,15 @@ Key procs var/datum/language/language_instance = GLOB.language_datum_instances[language_type] for(var/mutual_language_type in language_instance.mutual_understanding) // add it to the list OR override it if it's a stronger mutual understanding - if(!mutual_languages[mutual_language_type] || mutual_languages[mutual_language_type] < language_instance.mutual_understanding[mutual_language_type]) + if(mutual_languages[mutual_language_type] < language_instance.mutual_understanding[mutual_language_type]) mutual_languages[mutual_language_type] = language_instance.mutual_understanding[mutual_language_type] + for(var/language_type in other_mutual_understanding) + for(var/language_source in other_mutual_understanding[language_type]) + var/understanding_for_type_by_source = other_mutual_understanding[language_type][language_source] + if(mutual_languages[language_type] < understanding_for_type_by_source) + mutual_languages[language_type] = understanding_for_type_by_source + return mutual_languages /// Gets a random spoken language, useful for forced speech and such. @@ -241,6 +267,11 @@ Key procs if(LANGUAGE_MIND in blocked_languages[language]) remove_blocked_language(language, LANGUAGE_MIND) to_holder.add_blocked_language(language, LANGUAGE_MIND) + for(var/language in other_mutual_understanding) + var/mind_understanding = other_mutual_understanding[language][LANGUAGE_MIND] + if(mind_understanding > 0) + remove_partial_language(language, LANGUAGE_MIND) + to_holder.grant_partial_language(language, mind_understanding, LANGUAGE_MIND) if(owner) get_selected_language() diff --git a/code/modules/library/book.dm b/code/modules/library/book.dm index 5ae9afcdcbe4..1052c438cd9d 100644 --- a/code/modules/library/book.dm +++ b/code/modules/library/book.dm @@ -131,6 +131,7 @@ to_chat(user, span_warning("That title is invalid.")) return name = newtitle + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) book_data.set_title(html_decode(newtitle)) //Don't want to double encode here if("Contents") var/content = tgui_input_text(user, "Write your book's contents (HTML NOT allowed)", "Book Contents", multiline = TRUE) @@ -140,6 +141,7 @@ to_chat(user, span_warning("The content is invalid.")) return book_data.set_content(html_decode(content)) + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) if("Author") var/author = tgui_input_text(user, "Write the author's name", "Author Name") if(!user.can_perform_action(src) || !user.can_write(attacking_item)) @@ -148,6 +150,7 @@ to_chat(user, span_warning("The name is invalid.")) return book_data.set_author(html_decode(author)) //Setting this encodes, don't want to double up + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) else if(istype(attacking_item, /obj/item/barcodescanner)) var/obj/item/barcodescanner/scanner = attacking_item diff --git a/code/modules/library/skill_learning/skillchip.dm b/code/modules/library/skill_learning/skillchip.dm index 2ef7a20e6806..9133ee7b5eb1 100644 --- a/code/modules/library/skill_learning/skillchip.dm +++ b/code/modules/library/skill_learning/skillchip.dm @@ -1,10 +1,3 @@ -// Skillchip categories -//Various skillchip categories. Use these when setting which categories a skillchip restricts being paired with -//while using the SKILLCHIP_RESTRICTED_CATEGORIES flag -/// General related skillchip category -#define SKILLCHIP_CATEGORY_GENERAL "general" - - /obj/item/skillchip name = "skillchip" desc = "This biochip integrates with user's brain to enable mastery of specific skill. Consult certified Nanotrasen neurosurgeon before use." @@ -148,6 +141,7 @@ * * silent - Boolean. Whether or not an activation message should be shown to the user. */ /obj/item/skillchip/proc/on_activate(mob/living/carbon/user, silent=FALSE) + SHOULD_CALL_PARENT(TRUE) if(!silent && activate_message) to_chat(user, activate_message) @@ -182,6 +176,7 @@ * * silent - Boolean. Whether or not a deactivation message should be shown to the user. */ /obj/item/skillchip/proc/on_deactivate(mob/living/carbon/user, silent=FALSE) + SHOULD_CALL_PARENT(TRUE) if(!silent && deactivate_message) to_chat(user, deactivate_message) @@ -507,4 +502,94 @@ activate_message = span_notice("You think of your favourite food and realise that you can rotate its flavour in your mind.") deactivate_message = span_notice("You feel your food-based mind palace crumbling...") -#undef SKILLCHIP_CATEGORY_GENERAL +/obj/item/skillchip/musical + name = "\improper Old Copy of \"Space Station 13: The Musical\"" + desc = "An old copy of \"Space Station 13: The Musical\", \ + ran on the station's 100th anniversary...Or maybe it was the 200th?" + skill_name = "Memory of a Musical" + skill_description = "Allows you to hit that high note, like those that came a century before us." + skill_icon = FA_ICON_MUSIC + activate_message = span_notice("You feel like you could \u2669 sing a soooong! \u266B") + deactivate_message = span_notice("The musical fades from your mind, leaving you with a sense of nostalgia.") + custom_premium_price = PAYCHECK_CREW * 4 + +/obj/item/skillchip/musical/Initialize(mapload, is_removable) + . = ..() + name = replacetext(name, "Old", round(CURRENT_STATION_YEAR - pick(50, 100, 150, 200, 250), 5)) + +/obj/item/skillchip/musical/on_activate(mob/living/carbon/user, silent = FALSE) + . = ..() + RegisterSignal(user, COMSIG_MOB_SAY, PROC_REF(make_music)) + +/obj/item/skillchip/musical/on_deactivate(mob/living/carbon/user, silent) + . = ..() + UnregisterSignal(user, COMSIG_MOB_SAY) + +/obj/item/skillchip/musical/proc/make_music(mob/living/carbon/source, list/say_args) + SIGNAL_HANDLER + + var/raw_message = say_args[SPEECH_MESSAGE] + var/list/words = splittext(raw_message, " ") + if(length(words) <= 1) + say_args[SPEECH_MODS][MODE_SING] = TRUE + return + var/last_word = words[length(words)] + var/num_chars = length_char(last_word) + var/last_vowel = "" + // find the last vowel present in the word + for(var/i in 1 to num_chars) + var/char = copytext_char(last_word, i, i + 1) + if(char in VOWELS) + last_vowel = char + + // now we'll reshape the final word to make it sound like they're singing it + var/final_word = "" + var/has_ellipsis = copytext(last_word, -3) == "..." + for(var/i in 1 to num_chars) + var/char = copytext_char(last_word, i, i + 1) + // replacing any final periods with exclamation marks (so long as it's not an ellipsis) + if(char == "." && i == num_chars && !has_ellipsis) + final_word += "!" + // or if it's the vowel we found, we're gonna repeat it a few times (holding the note) + else if(char == last_vowel) + for(var/j in 1 to 4) + final_word += char + // if we dragged out the last character of the word, just period it + if(i == num_chars) + final_word += "." + // no special handing otherwise + else + final_word += char + + if(!has_ellipsis) + // adding an extra exclamation mark at the end if there's no period + var/last_char = copytext_char(final_word, -1) + if(last_char != ".") + final_word += "!" + + words[length(words)] = final_word + // now we siiiiiiing + say_args[SPEECH_MESSAGE] = jointext(words, " ") + say_args[SPEECH_MODS][MODE_SING] = TRUE + +/obj/item/skillchip/musical/examine(mob/user) + . = ..() + . += span_tinynoticeital("Huh, looks like it'd fit in a skillchip adapter.") + +/obj/item/skillchip/musical/examine_more(mob/user) + . = ..() + var/list/songs = list() + songs += "• \"The Ballad of Space Station 13\"" + songs += "• \"The Captain's Call\"" + songs += "• \"A Mime's Lament\"" + songs += "• \"Banned from Cargo\"" + songs += "• \"Botany Blues\"" + songs += "• \"Clown Song\"" + songs += "• \"Elegy to an Engineer\"" + songs += "• \"Medical Malpractitioner\"" + songs += "• \"Security Strike\"" + songs += "• \"Send for the Shuttle\"" + songs += "• And one song scratched out..." + + . += span_notice("On the back of the chip, you see a list of songs:") + . += span_smallnotice("[jointext(songs, "
")]
") diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm index 305b89ad9f03..4486a7b79e3b 100644 --- a/code/modules/mining/equipment/explorer_gear.dm +++ b/code/modules/mining/equipment/explorer_gear.dm @@ -66,7 +66,6 @@ actions_types = list(/datum/action/item_action/adjust) armor_type = /datum/armor/gas_explorer resistance_flags = FIRE_PROOF - has_fov = FALSE /datum/armor/gas_explorer melee = 10 diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 8b252da35bc7..093536c2921f 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -11,6 +11,7 @@ usable_hands = 0 //Populated on init through list/bodyparts mobility_flags = MOBILITY_FLAGS_CARBON_DEFAULT blocks_emissive = EMISSIVE_BLOCK_NONE + mouse_drop_zone = TRUE ///List of [/obj/item/organ]s in the mob. They don't go in the contents for some reason I don't want to know. var/list/obj/item/organ/organs = list() ///Same as [above][/mob/living/carbon/var/organs], but stores "slot ID" - "organ" pairs for easy access. diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm index 9ed0e146732e..2699691df523 100644 --- a/code/modules/mob/living/carbon/emote.dm +++ b/code/modules/mob/living/carbon/emote.dm @@ -6,16 +6,6 @@ message = "is strumming the air and headbanging like a safari chimp." hands_use_check = TRUE -/datum/emote/living/carbon/blink - key = "blink" - key_third_person = "blinks" - message = "blinks." - -/datum/emote/living/carbon/blink_r - key = "blink_r" - name = "blink (Rapid)" - message = "blinks rapidly." - /datum/emote/living/carbon/clap key = "clap" key_third_person = "claps" diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 3f5140a8e804..98f1787992a0 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1308,6 +1308,10 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/get_cry_sound(mob/living/carbon/human/human) return +/// Returns the species' sigh sound. +/datum/species/proc/get_sigh_sound(mob/living/carbon/human/human) + return + /// Returns the species' cough sound. /datum/species/proc/get_cough_sound(mob/living/carbon/human/human) return @@ -1320,6 +1324,10 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/get_sneeze_sound(mob/living/carbon/human/human) return +/// Returns the species' snore sound. +/datum/species/proc/get_snore_sound(mob/living/carbon/human/human) + return + /datum/species/proc/get_types_to_preload() var/list/to_store = list() to_store += mutant_organs diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index bbe8c103ba25..79412218a724 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -26,6 +26,8 @@ /datum/emote/living/carbon/human/glasses/run_emote(mob/user, params, type_override, intentional) . = ..() + if(!.) + return var/image/emote_animation = image('icons/mob/human/emote_visuals.dmi', user, "glasses") flick_overlay_global(emote_animation, GLOB.clients, 1.6 SECONDS) @@ -206,6 +208,43 @@ return pick(user.get_speech_sounds()) return null +/datum/emote/living/carbon/human/blink + key = "blink" + key_third_person = "blinks" + message = "blinks." + +/datum/emote/living/carbon/human/blink/can_run_emote(mob/living/carbon/human/user, status_check, intentional, params) + if (!ishuman(user) || HAS_TRAIT(user, TRAIT_PREVENT_BLINKING) || HAS_TRAIT(user, TRAIT_NO_EYELIDS)) + return FALSE + var/obj/item/organ/internal/eyes/eyes = user.get_organ_slot(ORGAN_SLOT_EYES) + if (!eyes) + return FALSE + return ..() + +/datum/emote/living/carbon/human/blink/run_emote(mob/living/carbon/human/user, params, type_override, intentional) + . = ..() + // Set to update_body until update_body_parts_head_only is fixed + user.update_body() // Refreshing instantly makes the user blink + +/datum/emote/living/carbon/human/blink_r + key = "blink_r" + name = "blink (Rapid)" + message = "blinks rapidly." + +/datum/emote/living/carbon/human/blink_r/can_run_emote(mob/living/carbon/human/user, status_check, intentional, params) + if (!ishuman(user) || HAS_TRAIT(user, TRAIT_PREVENT_BLINKING) || HAS_TRAIT(user, TRAIT_NO_EYELIDS)) + return FALSE + var/obj/item/organ/internal/eyes/eyes = user.get_organ_slot(ORGAN_SLOT_EYES) + if (!eyes) + return FALSE + return ..() + +/datum/emote/living/carbon/human/blink_r/run_emote(mob/user, params, type_override, intentional) + . = ..() + // Set to update_body until update_body_parts_head_only is fixed + for (var/i in 1 to 3) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob, update_body)), i * 0.3 SECONDS) + ///Snowflake emotes only for le epic chimp /datum/emote/living/carbon/human/monkey diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 6c6095801286..277bc7d72af8 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -51,51 +51,6 @@ features["ears"] = pick("None", "Cat") return features -/datum/species/human/felinid/get_laugh_sound(mob/living/carbon/human/felinid) - if(felinid.physique == FEMALE) - return 'sound/voice/human/womanlaugh.ogg' - return pick( - 'sound/voice/human/manlaugh1.ogg', - 'sound/voice/human/manlaugh2.ogg', - ) - - -/datum/species/human/felinid/get_cough_sound(mob/living/carbon/human/felinid) - if(felinid.physique == FEMALE) - return pick( - 'sound/voice/human/female_cough1.ogg', - 'sound/voice/human/female_cough2.ogg', - 'sound/voice/human/female_cough3.ogg', - 'sound/voice/human/female_cough4.ogg', - 'sound/voice/human/female_cough5.ogg', - 'sound/voice/human/female_cough6.ogg', - ) - return pick( - 'sound/voice/human/male_cough1.ogg', - 'sound/voice/human/male_cough2.ogg', - 'sound/voice/human/male_cough3.ogg', - 'sound/voice/human/male_cough4.ogg', - 'sound/voice/human/male_cough5.ogg', - 'sound/voice/human/male_cough6.ogg', - ) - -/datum/species/human/felinid/get_cry_sound(mob/living/carbon/human/felinid) - if(felinid.physique == FEMALE) - return pick( - 'sound/voice/human/female_cry1.ogg', - 'sound/voice/human/female_cry2.ogg', - ) - return pick( - 'sound/voice/human/male_cry1.ogg', - 'sound/voice/human/male_cry2.ogg', - 'sound/voice/human/male_cry3.ogg', - ) - -/datum/species/human/felinid/get_sneeze_sound(mob/living/carbon/human/felinid) - if(felinid.physique == FEMALE) - return 'sound/voice/human/female_sneeze1.ogg' - return 'sound/voice/human/male_sneeze1.ogg' - /proc/mass_purrbation() for(var/mob in GLOB.human_list) purrbation_apply(mob) diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index 98a4518c4fa2..5adb85fdbc8b 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -79,6 +79,16 @@ 'sound/voice/human/manlaugh2.ogg', ) +/datum/species/human/get_snore_sound(mob/living/carbon/human/human) + if(human.physique == FEMALE) + return SFX_SNORE_FEMALE + return SFX_SNORE_MALE + +/datum/species/human/get_sigh_sound(mob/living/carbon/human/human) + if(human.physique == FEMALE) + return SFX_FEMALE_SIGH + return SFX_MALE_SIGH + /datum/species/human/get_species_description() return "Humans are the dominant species in the known galaxy. \ Their kind extend from old Earth to the edges of known space." diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 76aac9d6cfa2..44e3e2b79eed 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -18,6 +18,7 @@ ) mutanttongue = /obj/item/organ/internal/tongue/lizard mutantstomach = /obj/item/organ/internal/stomach/lizard + mutanteyes = /obj/item/organ/internal/eyes/lizard coldmod = 1.5 heatmod = 0.67 payday_modifier = 1.0 @@ -112,6 +113,16 @@ /datum/species/lizard/get_laugh_sound(mob/living/carbon/human/lizard) return 'sound/voice/lizard/lizard_laugh1.ogg' +/datum/species/lizard/get_snore_sound(mob/living/carbon/human/lizard) + if(lizard.physique == FEMALE) + return SFX_SNORE_FEMALE + return SFX_SNORE_MALE + +/datum/species/lizard/get_sigh_sound(mob/living/carbon/human/lizard) + if(lizard.physique == FEMALE) + return SFX_FEMALE_SIGH + return SFX_MALE_SIGH + /datum/species/lizard/get_physical_attributes() return "Lizardpeople can withstand slightly higher temperatures than most species, but they are very vulnerable to the cold \ and can't regulate their body-temperature internally, making the vacuum of space extremely deadly to them." diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index 85c61cc26d85..b71956311fc8 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -96,6 +96,11 @@ /datum/species/moth/get_scream_sound(mob/living/carbon/human/human) return 'sound/voice/moth/scream_moth.ogg' +/datum/species/moth/get_sigh_sound(mob/living/carbon/human/moth) + if(moth.physique == FEMALE) + return SFX_FEMALE_SIGH + return SFX_MALE_SIGH + /datum/species/moth/get_physical_attributes() return "Moths have large and fluffy wings, which help them navigate the station if gravity is offline by pushing the air around them. \ Due to that, it isn't of much use out in space. Their eyes are very sensitive." diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index c77ad3dfee1e..61fc14a467b4 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -93,6 +93,7 @@ name = "burning red eyes" desc = "Even without their shadowy owner, looking at these eyes gives you a sense of dread." icon = 'icons/obj/medical/organs/shadow_organs.dmi' + iris_overlays = FALSE color_cutoffs = list(20, 10, 40) pepperspray_protect = TRUE diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 7b3e04263876..a34850adc278 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -88,7 +88,38 @@ key = "dance" key_third_person = "dances" message = "dances around happily." - hands_use_check = TRUE + cooldown = 2.5 SECONDS + +/datum/emote/living/dance/can_run_emote(mob/living/user, status_check = TRUE, intentional) + return can_dance(user) && user.num_legs >= 2 && ..() + +/datum/emote/living/dance/proc/can_dance(mob/living/user) + if(QDELETED(user) || user.incapacitated(IGNORE_RESTRAINTS) || user.body_position != STANDING_UP) + return FALSE + return TRUE + +/datum/emote/living/dance/run_emote(mob/user, params, type_override, intentional) + . = ..() + if(!.) + return + INVOKE_ASYNC(src, PROC_REF(dance_animation), user) + +/datum/emote/living/dance/proc/dance_animation(mob/living/user) + for(var/i in 1 to 8) + switch(i) + if(1, 7) + animate(user, pixel_w = user.pixel_w + 6, time = 0.5 SECONDS) + if(3, 5) + animate(user, pixel_w = user.pixel_w - 6, time = 0.5 SECONDS) + else + user.setDir(turn(user.dir, 90)) + sleep(0.25 SECONDS) + if(!can_dance(user)) + user.pixel_w = user.base_pixel_w + return + if(user.num_legs < 2) + user.Knockdown(2 SECONDS) + return /datum/emote/living/deathgasp key = "deathgasp" @@ -381,14 +412,20 @@ message = "sighs." message_mime = "acts out an exaggerated silent sigh." emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE + vary = TRUE /datum/emote/living/sigh/run_emote(mob/living/user, params, type_override, intentional) . = ..() - if(!ishuman(user)) + if(!. || !ishuman(user)) return var/image/emote_animation = image('icons/mob/human/emote_visuals.dmi', user, "sigh") flick_overlay_global(emote_animation, GLOB.clients, 2.0 SECONDS) +/datum/emote/living/sigh/get_sound(mob/living/carbon/human/user) + if(!istype(user)) + return + return user.dna.species.get_sigh_sound(user) + /datum/emote/living/sit key = "sit" key_third_person = "sits" @@ -433,6 +470,12 @@ emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE stat_allowed = UNCONSCIOUS +// eventually we want to give species their own "snoring" sounds +/datum/emote/living/snore/get_sound(mob/living/carbon/human/user) + if(!istype(user)) + return + return user.dna.species.get_snore_sound(user) + /datum/emote/living/stare key = "stare" key_third_person = "stares" diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index 576a438a2708..c8cb3dd8ca4a 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -16,6 +16,7 @@ designation = "Default" //used for displaying the prefix & getting the current model of cyborg has_limbs = TRUE hud_type = /datum/hud/robot + mouse_drop_zone = TRUE ///Represents the cyborg's model (engineering, medical, etc.) var/obj/item/robot_model/model = null diff --git a/code/modules/mod/mod_link.dm b/code/modules/mod/mod_link.dm index 8629a75cbdf3..32fb29c0ba08 100644 --- a/code/modules/mod/mod_link.dm +++ b/code/modules/mod/mod_link.dm @@ -499,6 +499,7 @@ desc = "Someone is calling you! Left-click this to accept the call. Right-click to deny it." icon_state = "called" timeout = 10 SECONDS + mouse_over_pointer = MOUSE_HAND_POINTER var/end_message = "call timed out!" /// A weak reference to the MODlink that is calling. var/datum/weakref/caller_ref diff --git a/code/modules/pai/hud.dm b/code/modules/pai/hud.dm index 1a71b5235b61..403bc1e0c74e 100644 --- a/code/modules/pai/hud.dm +++ b/code/modules/pai/hud.dm @@ -2,6 +2,7 @@ /atom/movable/screen/pai icon = 'icons/hud/screen_pai.dmi' + mouse_over_pointer = MOUSE_HAND_POINTER var/required_software /atom/movable/screen/pai/Click() diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm index d37fdf812632..4a145f663a66 100644 --- a/code/modules/paperwork/folders.dm +++ b/code/modules/paperwork/folders.dm @@ -51,6 +51,7 @@ if(user.can_perform_action(src)) name = "folder[(inputvalue ? " - '[inputvalue]'" : null)]" + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) /obj/item/folder/proc/remove_item(obj/item/Item, mob/user) if(istype(Item)) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index a786251d4d12..7a64fdee62a7 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -596,6 +596,8 @@ // Safe to assume there are writing implement details as user.can_write(...) fails with an invalid writing implement. var/writing_implement_data = holding.get_writing_implement_details() + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) + add_raw_text(paper_input, writing_implement_data["font"], writing_implement_data["color"], writing_implement_data["use_bold"], check_rights_for(user?.client, R_FUN)) log_paper("[key_name(user)] wrote to [name]: \"[paper_input]\"") diff --git a/code/modules/photography/photos/photo.dm b/code/modules/photography/photos/photo.dm index 6c1eb7c7b9ac..806943233dfb 100644 --- a/code/modules/photography/photos/photo.dm +++ b/code/modules/photography/photos/photo.dm @@ -75,6 +75,7 @@ return var/txt = tgui_input_text(user, "What would you like to write on the back?", "Photo Writing", max_length = 128) if(txt && user.can_perform_action(src)) + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) scribble = txt else return ..() diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index 373607e53dd6..e2db1b2cfbda 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -100,7 +100,7 @@ /obj/item/gun/ballistic/revolver/ignition_effect(atom/A, mob/user) if(last_fire && last_fire + 15 SECONDS > world.time) - . = span_notice("[user] touches the end of [src] to \the [A], using the residual heat to ignite it in a puff of smoke. What a badass.") + return span_rose("[user] touches the end of [src] to \the [A], using the residual heat to ignite it in a puff of smoke. What a badass.") /obj/item/gun/ballistic/revolver/c38 name = "\improper .38 revolver" diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 5c9195f56e88..4ec479662056 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -324,7 +324,7 @@ playsound(user, E.fire_sound, 50, TRUE) playsound(user, loaded_projectile.hitsound, 50, TRUE) cell.use(E.e_cost) - . = span_danger("[user] casually lights [A.loc == user ? "[user.p_their()] [A.name]" : A] with [src]. Damn.") + . = span_rose("[user] casually lights [A.loc == user ? "[user.p_their()] [A.name]" : A] with [src]. Damn.") /obj/item/gun/energy/proc/instant_recharge() SIGNAL_HANDLER diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm index 0ab2052d04c3..efb689f06c17 100644 --- a/code/modules/projectiles/projectile/energy/stun.dm +++ b/code/modules/projectiles/projectile/energy/stun.dm @@ -286,6 +286,7 @@ name = "Tased!" desc = "Taser electrodes are shocking you! You can click this or resist to try to remove them." icon_state = "stun" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/tazed/Click(location, control, params) . = ..() diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 70a3473953ef..df12232b522f 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -111,6 +111,7 @@ if(custom_label) labelled = TRUE name = "blood pack - [custom_label]" + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) balloon_alert(user, "new label set") else labelled = FALSE diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 10f7ce1ce608..3a188751739f 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -124,7 +124,7 @@ return var/trans = reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user) - playsound(target.loc, pick('sound/effects/liquid_pour1.ogg', 'sound/effects/liquid_pour2.ogg', 'sound/effects/liquid_pour3.ogg'), 50) + playsound(target.loc, SFX_LIQUID_POUR, 50) to_chat(user, span_notice("You transfer [trans] unit\s of the solution to [target].")) else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us. diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm index 0899608155d8..a654be49ba74 100644 --- a/code/modules/reagents/reagent_containers/cups/bottle.dm +++ b/code/modules/reagents/reagent_containers/cups/bottle.dm @@ -537,6 +537,7 @@ return if(user.can_perform_action(src)) + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) name = "[(inputvalue ? "[inputvalue]" : null)] bottle" //types of syrups diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index beb6f3e6314c..29a83ff37ef4 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -45,8 +45,8 @@ target.visible_message(span_danger("[user] tries to squirt something into [target]'s eyes, but fails!"), \ span_userdanger("[user] tries to squirt something into your eyes, but fails!")) - - to_chat(user, span_notice("You transfer [trans] unit\s of the solution.")) + if(trans) + to_chat(user, span_notice("You transfer [trans] unit\s of the solution.")) update_appearance() return else if(isalien(target)) //hiss-hiss has no eyes! @@ -56,6 +56,7 @@ target.visible_message(span_danger("[user] squirts something into [target]'s eyes!"), \ span_userdanger("[user] squirts something into your eyes!")) + SEND_SIGNAL(target, COMSIG_MOB_REAGENTS_DROPPED_INTO_EYES, user, src, reagents, fraction) reagents.expose(target, TOUCH, fraction) var/mob/M = target var/R diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 8915cc232ca8..98bdaf43dc84 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -123,6 +123,7 @@ if(!str || !length(str)) to_chat(user, span_warning("Invalid text!")) return + playsound(src, SFX_WRITING_PEN, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, SOUND_FALLOFF_EXPONENT + 3, ignore_walls = FALSE) user.visible_message(span_notice("[user] labels [src] as [str].")) name = "[name] ([str])" diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index 6e946cca05c4..c30b866e4805 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -242,8 +242,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( misc_contents[buyer] = list() for(var/datum/supply_order/our_order as anything in buying_account_orders) - for (var/item in our_order.pack.contains) - misc_contents[buyer] += item + misc_contents[buyer] += our_order.pack misc_costs[buyer] += our_order.pack.cost misc_order_num[buyer] = "[misc_order_num[buyer]]#[our_order.id] " diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 0b953e49a877..99e034c5ff4b 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -91,6 +91,8 @@ /// Can this head be dismembered normally? can_dismember = FALSE + var/missing_eye_file = 'icons/mob/human/human_face.dmi' + /obj/item/bodypart/head/Destroy() QDEL_NULL(worn_ears_offset) QDEL_NULL(worn_glasses_offset) @@ -188,7 +190,7 @@ . += eye_left . += eye_right else if(!eyes && (head_flags & HEAD_EYEHOLES)) - var/image/no_eyes = image(owner?.missing_eye_file || 'icons/mob/human/human_face.dmi', "eyes_missing", -BODY_LAYER, SOUTH) // NON-MODULE CHANGE / UPSTREAM ME + var/image/no_eyes = image(missing_eye_file || 'icons/mob/human/human_face.dmi', "eyes_missing", -BODY_LAYER, SOUTH) // NON-MODULE CHANGE / UPSTREAM ME worn_face_offset?.apply_offset(no_eyes) . += no_eyes diff --git a/code/modules/surgery/bodyparts/head_hair_and_lips.dm b/code/modules/surgery/bodyparts/head_hair_and_lips.dm index c6e141cf7a46..34880e338b51 100644 --- a/code/modules/surgery/bodyparts/head_hair_and_lips.dm +++ b/code/modules/surgery/bodyparts/head_hair_and_lips.dm @@ -187,7 +187,7 @@ /// Returns an appropriate missing eyes overlay /obj/item/bodypart/head/proc/get_eyeless_overlay(can_rotate = TRUE) RETURN_TYPE(/image) - var/eyeless_icon = owner?.missing_eye_file || 'icons/mob/human/human_face.dmi' // NON-MODULE CHANGE + var/eyeless_icon = missing_eye_file || 'icons/mob/human/human_face.dmi' // NON-MODULE CHANGE var/eyeless_icon_state = "eyes_missing" var/image/eyeless_overlay diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm index 71e2b69b74f3..07b23b777e66 100644 --- a/code/modules/surgery/organs/internal/eyes/_eyes.dm +++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm @@ -44,6 +44,15 @@ var/old_eye_color_left = "fff" /// The color of the previous right eye before this one was inserted var/old_eye_color_right = "fff" + /// Do these eyes have blinking animations + var/blink_animation = TRUE + /// Do these eyes have iris overlays + var/iris_overlays = TRUE + /// Should our blinking be synchronized or can separate eyes have (slightly) separate blinking times + var/synchronized_blinking = TRUE + // A pair of abstract eyelid objects (yes, really) used to animate blinking + var/obj/effect/abstract/eyelid_effect/eyelid_left + var/obj/effect/abstract/eyelid_effect/eyelid_right /// Glasses cannot be worn over these eyes. Currently unused var/no_glasses = FALSE @@ -52,21 +61,29 @@ /// Native FOV that will be applied if a config is enabled var/native_fov = FOV_90_DEGREES -/obj/item/organ/internal/eyes/Insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED) - // If we don't do this before everything else, heterochromia will be reset leading to eye_color_right no longer being accurate - if(ishuman(eye_recipient)) - var/mob/living/carbon/human/human_recipient = eye_recipient - old_eye_color_left = human_recipient.eye_color_left - old_eye_color_right = human_recipient.eye_color_right + var/eye_overlay_file = 'icons/mob/human/human_face.dmi' +/obj/item/organ/internal/eyes/Initialize(mapload) . = ..() + if (blink_animation) + eyelid_left = new(src, "[eye_icon_state]_l") + eyelid_right = new(src, "[eye_icon_state]_r") - if(!.) - return +/obj/item/organ/internal/eyes/Destroy() + QDEL_NULL(eyelid_left) + QDEL_NULL(eyelid_right) + return ..() + +/obj/item/organ/internal/eyes/on_mob_insert(mob/living/carbon/receiver, special, movement_flags) + . = ..() + if(ishuman(receiver)) + var/mob/living/carbon/human/human_recipient = receiver + old_eye_color_left = human_recipient.eye_color_left + old_eye_color_right = human_recipient.eye_color_right - eye_recipient.cure_blind(NO_EYES) + receiver.cure_blind(NO_EYES) apply_damaged_eye_effects() - refresh(eye_recipient, call_update = TRUE) + refresh(receiver, call_update = TRUE) /// Refreshes the visuals of the eyes /// If call_update is TRUE, we also will call update_body @@ -94,31 +111,32 @@ if(call_update) affected_human.update_body() -/obj/item/organ/internal/eyes/Remove(mob/living/carbon/eye_owner, special, movement_flags) +/obj/item/organ/internal/eyes/on_mob_remove(mob/living/carbon/organ_owner, special) . = ..() - if(ishuman(eye_owner)) - var/mob/living/carbon/human/human_owner = eye_owner + + if(ishuman(organ_owner)) + var/mob/living/carbon/human/human_owner = organ_owner if(initial(eye_color_left)) human_owner.eye_color_left = old_eye_color_left if(initial(eye_color_right)) human_owner.eye_color_right = old_eye_color_right if(native_fov) - eye_owner.remove_fov_trait(type) + human_owner.remove_fov_trait(type) if(!special) human_owner.update_body() // Cure blindness from eye damage - eye_owner.cure_blind(EYE_DAMAGE) - eye_owner.cure_nearsighted(EYE_DAMAGE) + organ_owner.cure_blind(EYE_DAMAGE) + organ_owner.cure_nearsighted(EYE_DAMAGE) // Eye blind and temp blind go to, even if this is a bit of cheesy way to clear blindness - eye_owner.remove_status_effect(/datum/status_effect/eye_blur) - eye_owner.remove_status_effect(/datum/status_effect/temporary_blindness) + organ_owner.remove_status_effect(/datum/status_effect/eye_blur) + organ_owner.remove_status_effect(/datum/status_effect/temporary_blindness) // Then become blind anyways (if not special) if(!special) - eye_owner.become_blind(NO_EYES) + organ_owner.become_blind(NO_EYES) - eye_owner.update_tint() - eye_owner.update_sight() + organ_owner.update_tint() + organ_owner.update_sight() #define OFFSET_X 1 #define OFFSET_Y 2 @@ -161,8 +179,8 @@ if(isnull(eye_icon_state)) return list() - var/mutable_appearance/eye_left = mutable_appearance(eye_overlay_file, "[eye_icon_state]_l", -BODY_LAYER) // NON-MODULE CHANGE / UPSTREAM ME - var/mutable_appearance/eye_right = mutable_appearance(eye_overlay_file, "[eye_icon_state]_r", -BODY_LAYER) // NON-MODULE CHANGE / UPSTREAM ME + var/mutable_appearance/eye_left = mutable_appearance(eye_overlay_file, "[eye_icon_state]_l", -BODY_LAYER, parent) // NON-MODULE CHANGE / UPSTREAM ME + var/mutable_appearance/eye_right = mutable_appearance(eye_overlay_file, "[eye_icon_state]_r", -BODY_LAYER, parent) // NON-MODULE CHANGE / UPSTREAM ME var/list/overlays = list(eye_left, eye_right) var/obscured = parent.check_obscured_slots(TRUE) @@ -170,26 +188,40 @@ overlays += emissive_appearance(eye_left.icon, eye_left.icon_state, parent, -BODY_LAYER, alpha = eye_left.alpha) overlays += emissive_appearance(eye_right.icon, eye_right.icon_state, parent, -BODY_LAYER, alpha = eye_right.alpha) var/obj/item/bodypart/head/my_head = parent.get_bodypart(BODY_ZONE_HEAD) - if(my_head) - if(my_head.head_flags & HEAD_EYECOLOR) - // NON-MODULE CHANGE for eyelids - if(IS_ROBOTIC_ORGAN(src) || !my_head.draw_color || (parent.appears_alive() && !HAS_TRAIT(parent, TRAIT_KNOCKEDOUT))) - eye_right.color = eye_color_right - eye_left.color = eye_color_left - else - var/list/base_color = rgb2num(my_head.draw_color, COLORSPACE_HSL) - base_color[2] *= 0.85 - base_color[3] *= 0.85 - var/eyelid_color = rgb(base_color[1], base_color[2], base_color[3], (length(base_color) >= 4 ? base_color[4] : null), COLORSPACE_HSL) - eye_right.color = eyelid_color - eye_left.color = eyelid_color - if(my_head.worn_face_offset) - my_head.worn_face_offset.apply_offset(eye_left) - my_head.worn_face_offset.apply_offset(eye_right) + if(!my_head) + return overlays + + if(my_head.head_flags & HEAD_EYECOLOR) + eye_right.color = eye_color_right + eye_left.color = eye_color_left + var/list/eyelids = setup_eyelids(eye_left, eye_right, parent) + if (LAZYLEN(eyelids)) + overlays += eyelids + + if(my_head.worn_face_offset) + my_head.worn_face_offset.apply_offset(eye_left) + my_head.worn_face_offset.apply_offset(eye_right) return overlays +/obj/item/organ/internal/eyes/update_overlays() + . = ..() + if (iris_overlays && eye_color_left && eye_color_right) + var/mutable_appearance/left_iris = mutable_appearance(icon, "[icon_state]_iris_l") + var/mutable_appearance/right_iris = mutable_appearance(icon, "[icon_state]_iris_r") + var/list/color_left = rgb2num(eye_color_left, COLORSPACE_HSL) + var/list/color_right = rgb2num(eye_color_right, COLORSPACE_HSL) + // Ugly as sin? Indeed it is! But otherwise eyeballs turn out to be super dark, and this way even lighter colors are mostly preserved + if (color_left[3]) + color_left[3] /= sqrt(color_left[3] * 0.01) + if (color_right[3]) + color_right[3] /= sqrt(color_right[3] * 0.01) + left_iris.color = rgb(color_left[1], color_left[2], color_left[3], space = COLORSPACE_HSL) + right_iris.color = rgb(color_right[1], color_right[2], color_right[3], space = COLORSPACE_HSL) + . += left_iris + . += right_iris + #undef OFFSET_X #undef OFFSET_Y @@ -238,6 +270,92 @@ damaged = TRUE +#define BASE_BLINKING_DELAY 5 SECONDS +#define RAND_BLINKING_DELAY 1 SECONDS +#define BLINK_DURATION 0.15 SECONDS +#define BLINK_LOOPS 5 +#define ASYNC_BLINKING_BRAIN_DAMAGE 60 + +/// Modifies eye overlays to also act as eyelids, both for blinking and for when you're knocked out cold +/obj/item/organ/internal/eyes/proc/setup_eyelids(mutable_appearance/eye_left, mutable_appearance/eye_right, mob/living/carbon/human/parent) + var/obj/item/bodypart/head/my_head = parent.get_bodypart(BODY_ZONE_HEAD) + // Robotic eyes don't get the privelege of having eyelids + if (IS_ROBOTIC_ORGAN(src) || HAS_TRAIT(parent, TRAIT_NO_EYELIDS)) + return + + var/list/base_color = rgb2num(my_head.draw_color || "#EEEEEE", COLORSPACE_HSL) + base_color[2] *= 0.85 + base_color[3] *= 0.85 + var/eyelid_color = rgb(base_color[1], base_color[2], base_color[3], (length(base_color) >= 4 ? base_color[4] : null), COLORSPACE_HSL) + // If we're knocked out, just color the eyes + if (!parent.appears_alive() || HAS_TRAIT(parent, TRAIT_KNOCKEDOUT)) + eye_right.color = eyelid_color + eye_left.color = eyelid_color + return + + if (!blink_animation || HAS_TRAIT(parent, TRAIT_PREVENT_BLINKING)) + return + + eyelid_left.color = eyelid_color + eyelid_right.color = eyelid_color + eyelid_left.render_target = "*[REF(parent)]_eyelid_left" + eyelid_right.render_target = "*[REF(parent)]_eyelid_right" + parent.vis_contents += eyelid_left + parent.vis_contents += eyelid_right + var/sync_blinking = synchronized_blinking && (parent.get_organ_loss(ORGAN_SLOT_BRAIN) < ASYNC_BLINKING_BRAIN_DAMAGE) + // Randomize order for unsynched animations + if (sync_blinking || prob(50)) + var/list/anim_times = animate_eyelid(eyelid_left, parent, sync_blinking) + animate_eyelid(eyelid_right, parent, sync_blinking, anim_times) + else + var/list/anim_times = animate_eyelid(eyelid_right, parent, sync_blinking) + animate_eyelid(eyelid_left, parent, sync_blinking, anim_times) + + var/mutable_appearance/left_eyelid_overlay = mutable_appearance(layer = -BODY_LAYER, offset_spokesman = parent) + var/mutable_appearance/right_eyelid_overlay = mutable_appearance(layer = -BODY_LAYER, offset_spokesman = parent) + left_eyelid_overlay.render_source = "*[REF(parent)]_eyelid_left" + right_eyelid_overlay.render_source = "*[REF(parent)]_eyelid_right" + return list(left_eyelid_overlay, right_eyelid_overlay) + +/// Animates one eyelid at a time, thanks BYOND and thanks animation chains +/obj/item/organ/internal/eyes/proc/animate_eyelid(obj/effect/abstract/eyelid_effect/eyelid, mob/living/carbon/human/parent, sync_blinking = TRUE, list/anim_times = null) + . = list() + var/prevent_loops = HAS_TRAIT(parent, TRAIT_PREVENT_BLINK_LOOPS) + animate(eyelid, alpha = 0, time = 0, loop = (prevent_loops ? 0 : -1)) + for (var/i in 1 to (prevent_loops ? 1 : BLINK_LOOPS)) + var/wait_time = rand(BASE_BLINKING_DELAY - RAND_BLINKING_DELAY, BASE_BLINKING_DELAY + RAND_BLINKING_DELAY) + if (anim_times) + if (sync_blinking) + wait_time = anim_times[1] + anim_times.Cut(1, 2) + else + wait_time = rand(max(BASE_BLINKING_DELAY - RAND_BLINKING_DELAY, anim_times[1] - RAND_BLINKING_DELAY), anim_times[1]) + . += wait_time + if (anim_times && !sync_blinking) + // Make sure that we're somewhat in sync with the other eye + animate(time = anim_times[1] - wait_time) + anim_times.Cut(1, 2) + animate(alpha = 255, time = 0) + animate(time = BLINK_DURATION) + animate(alpha = 0, time = 0) + animate(time = wait_time) + +/obj/effect/abstract/eyelid_effect + name = "eyelid" + icon = 'icons/mob/human/human_face.dmi' + layer = -BODY_LAYER + vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE | VIS_INHERIT_ID + +/obj/effect/abstract/eyelid_effect/Initialize(mapload, new_state) + . = ..() + icon_state = new_state + +#undef BASE_BLINKING_DELAY +#undef RAND_BLINKING_DELAY +#undef BLINK_DURATION +#undef BLINK_LOOPS +#undef ASYNC_BLINKING_BRAIN_DAMAGE + #define NIGHTVISION_LIGHT_OFF 0 #define NIGHTVISION_LIGHT_LOW 1 #define NIGHTVISION_LIGHT_MID 2 @@ -304,9 +422,11 @@ /obj/item/organ/internal/eyes/golem name = "resonating crystal" + desc = "Golems somehow measure external light levels and detect nearby ore using this sensitive mineral lattice." icon_state = "adamantine_cords" eye_icon_state = null - desc = "Golems somehow measure external light levels and detect nearby ore using this sensitive mineral lattice." + blink_animation = FALSE + iris_overlays = FALSE color = COLOR_GOLEM_GRAY visual = FALSE organ_flags = ORGAN_MINERAL @@ -330,8 +450,9 @@ /obj/item/organ/internal/eyes/robotic name = "robotic eyes" - icon_state = "cybernetic_eyeballs" desc = "Your vision is augmented." + icon_state = "cybernetic_eyeballs" + iris_overlays = FALSE organ_flags = ORGAN_ROBOTIC failing_desc = "seems to be broken." @@ -696,59 +817,77 @@ /obj/item/organ/internal/eyes/moth name = "moth eyes" desc = "These eyes seem to have increased sensitivity to bright light, with no improvement to low light vision." - eye_icon_state = "motheyes" icon_state = "eyeballs-moth" + eye_icon_state = "motheyes" + blink_animation = FALSE + iris_overlays = FALSE flash_protect = FLASH_PROTECTION_SENSITIVE /obj/item/organ/internal/eyes/robotic/moth name = "robotic moth eyes" - eye_icon_state = "motheyes" - icon_state = "eyeballs-cybermoth" desc = "Your vision is augmented. Much like actual moth eyes, very sensitive to bright lights." + icon_state = "eyeballs-cybermoth" + eye_icon_state = "motheyes" + blink_animation = FALSE flash_protect = FLASH_PROTECTION_SENSITIVE /obj/item/organ/internal/eyes/robotic/basic/moth name = "basic robotic moth eyes" - eye_icon_state = "motheyes" icon_state = "eyeballs-cybermoth" + eye_icon_state = "motheyes" + blink_animation = FALSE flash_protect = FLASH_PROTECTION_SENSITIVE /obj/item/organ/internal/eyes/robotic/xray/moth - name = "robotic eyes" - eye_icon_state = "motheyes" - icon_state = "eyeballs-cybermoth" + name = "moth x-ray eyes" desc = "These cybernetic imitation moth eyes will give you X-ray vision. Blinking is futile. Much like actual moth eyes, very sensitive to bright lights." + icon_state = "eyeballs-cybermoth" + eye_icon_state = "motheyes" + blink_animation = FALSE flash_protect = FLASH_PROTECTION_SENSITIVE /obj/item/organ/internal/eyes/robotic/shield/moth name = "shielded robotic moth eyes" - eye_icon_state = "motheyes" icon_state = "eyeballs-cybermoth" + eye_icon_state = "motheyes" + blink_animation = FALSE /obj/item/organ/internal/eyes/robotic/glow/moth - name = "High Luminosity Moth Eyes" + name = "high luminosity moth eyes" + desc = "Special glowing eyes, to be one with the lamp. Much like actual moth eyes, very sensitive to bright lights." + icon_state = "eyeballs-cybermoth" eye_icon_state = "motheyes" + blink_animation = FALSE base_eye_state = "eyes_mothglow" - icon_state = "eyeballs-cybermoth" - desc = "Special glowing eyes, to be one with the lamp. Much like actual moth eyes, very sensitive to bright lights." flash_protect = FLASH_PROTECTION_SENSITIVE /obj/item/organ/internal/eyes/robotic/thermals/moth //we inherit flash weakness from thermals name = "thermal moth eyes" - eye_icon_state = "motheyes" icon_state = "eyeballs-cybermoth" + eye_icon_state = "motheyes" + blink_animation = FALSE /obj/item/organ/internal/eyes/snail name = "snail eyes" desc = "These eyes seem to have a large range, but might be cumbersome with glasses." - eye_icon_state = "snail_eyes" icon_state = "snail_eyeballs" + eye_icon_state = "snail_eyes" + blink_animation = FALSE + iris_overlays = FALSE /obj/item/organ/internal/eyes/jelly name = "jelly eyes" desc = "These eyes are made of a soft jelly. Unlike all other eyes, though, there are three of them." - eye_icon_state = "jelleyes" icon_state = "eyeballs-jelly" + eye_icon_state = "jelleyes" + blink_animation = FALSE + iris_overlays = FALSE + +/obj/item/organ/internal/eyes/lizard + name = "reptile eyes" + desc = "A pair of reptile eyes with thin vertical slits for pupils." + icon_state = "lizard_eyes" + synchronized_blinking = FALSE /obj/item/organ/internal/eyes/night_vision/maintenance_adapted name = "adapted eyes" @@ -758,6 +897,7 @@ eye_color_right = "f00" icon_state = "adapted_eyes" eye_icon_state = "eyes_glow" + iris_overlays = FALSE overlay_ignore_lighting = TRUE low_light_cutoff = list(5, 12, 20) medium_light_cutoff = list(15, 20, 30) diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index 66363173e8c3..e1580c5edda0 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -83,7 +83,7 @@ return surgical_tray_overlay /obj/item/cautery/ignition_effect(atom/ignitable_atom, mob/user) - . = span_notice("[user] touches the end of [src] to \the [ignitable_atom], igniting it with a puff of smoke.") + return span_rose("[user] touches the end of [src] to \the [ignitable_atom], igniting it with a puff of smoke.") /obj/item/cautery/augment desc = "A heated element that cauterizes wounds." diff --git a/code/modules/transport/elevator/elev_panel.dm b/code/modules/transport/elevator/elev_panel.dm index 3e9e0e073c19..ad577f79fa24 100644 --- a/code/modules/transport/elevator/elev_panel.dm +++ b/code/modules/transport/elevator/elev_panel.dm @@ -19,6 +19,7 @@ icon_state = "elevpanel0" base_icon_state = "elevpanel" + mouse_over_pointer = MOUSE_HAND_POINTER power_channel = AREA_USAGE_ENVIRON // Indestructible until someone wants to make these constructible, with all the chaos that implies resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm index 59bd06135bb8..115b90f62be9 100644 --- a/code/modules/vending/autodrobe.dm +++ b/code/modules/vending/autodrobe.dm @@ -205,13 +205,15 @@ /obj/item/clothing/head/costume/powdered_wig = 1, /obj/item/clothing/head/costume/tv_head = 1, /obj/item/clothing/mask/muzzle = 2, - /obj/item/clothing/shoes/ducky_shoes = 1, /obj/item/clothing/shoes/clown_shoes/meown_shoes = 1, + /obj/item/clothing/shoes/ducky_shoes = 1, /obj/item/clothing/suit/costume/judgerobe = 1, /obj/item/clothing/head/costume/lobsterhat = 1, /obj/item/clothing/under/costume/lobster = 1, /obj/item/gun/magic/wand/nothing = 2, + /obj/item/skillchip/musical = 3, /obj/item/storage/box/tape_wizard = 1, + ) premium = list( /obj/item/clothing/suit/costume/pirate/captain = 2, diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi index 3612c747f50e..37aa4ceaa063 100644 Binary files a/icons/obj/cigarettes.dmi and b/icons/obj/cigarettes.dmi differ diff --git a/icons/obj/medical/organs/organs.dmi b/icons/obj/medical/organs/organs.dmi index 1fda82050384..3cccb0a253ce 100644 Binary files a/icons/obj/medical/organs/organs.dmi and b/icons/obj/medical/organs/organs.dmi differ diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi index f1802915bc43..058e96a7ab59 100644 Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ diff --git a/maplestation.dme b/maplestation.dme index a20225737010..941b2de00853 100644 --- a/maplestation.dme +++ b/maplestation.dme @@ -1018,6 +1018,7 @@ #include "code\datums\components\chuunibyou.dm" #include "code\datums\components\cleaner.dm" #include "code\datums\components\clickbox.dm" +#include "code\datums\components\clothing_dirt.dm" #include "code\datums\components\clothing_fov_visor.dm" #include "code\datums\components\codeword_hearing.dm" #include "code\datums\components\combo_attacks.dm" @@ -1408,6 +1409,7 @@ #include "code\datums\elements\honkspam.dm" #include "code\datums\elements\hostile_machine.dm" #include "code\datums\elements\human_biter.dm" +#include "code\datums\elements\ignites_matches.dm" #include "code\datums\elements\immerse.dm" #include "code\datums\elements\item_fov.dm" #include "code\datums\elements\item_scaling.dm" @@ -6170,6 +6172,7 @@ #include "maplestation_modules\code\game\machinery\towel_rack.dm" #include "maplestation_modules\code\game\objects\unique_examine_items.dm" #include "maplestation_modules\code\game\objects\effects\landmarks.dm" +#include "maplestation_modules\code\game\objects\effects\posters.dm" #include "maplestation_modules\code\game\objects\effects\decals\turfdecal\textured.dm" #include "maplestation_modules\code\game\objects\effects\decals\turfdecal\tile.dm" #include "maplestation_modules\code\game\objects\effects\temporary_visuals\projectiles\impact.dm" @@ -6523,7 +6526,6 @@ #include "maplestation_modules\code\modules\surgery\organs\augments_arms.dm" #include "maplestation_modules\code\modules\surgery\organs\autosurgeon.dm" #include "maplestation_modules\code\modules\surgery\organs\ears.dm" -#include "maplestation_modules\code\modules\surgery\organs\eyes.dm" #include "maplestation_modules\code\modules\surgery\organs\tails.dm" #include "maplestation_modules\code\modules\surgery\organs\tongue.dm" #include "maplestation_modules\code\modules\uplink\uplink_devices.dm" diff --git a/maplestation_modules/code/datums/quirks/neutral.dm b/maplestation_modules/code/datums/quirks/neutral.dm index 318f0b66813b..acf2a093a098 100644 --- a/maplestation_modules/code/datums/quirks/neutral.dm +++ b/maplestation_modules/code/datums/quirks/neutral.dm @@ -207,3 +207,78 @@ return #undef RANDOM_INNATE_MUTATION + +#define COLORBLINDNESS_PROTANOPIA "Protanopia (Red-Green)" +#define COLORBLINDNESS_DEUTERANOPIA "Deuteranopia (Red-Green)" +#define COLORBLINDNESS_TRITANOPIA "Tritanopia (Blue-Yellow)" + +// Uses the same values as the colorblind test debug. As always, they're not accurate and if you argue about that or argue like it is accurate i will SLAP YOU +/datum/quirk/colorblind + name = "Colorblind" + desc = "You are partially colorblind and are unable to percieve the full color spectrum." + icon = FA_ICON_PALETTE + value = 0 + gain_text = span_notice("You suddenly can't see as many colors anymore.") + lose_text = span_danger("You can see the world in full color now! It's not that great...") + medical_record_text = "Patient is afflicted with color blindness." + var/colorblind_type = COLORBLINDNESS_DEUTERANOPIA //cached to prevent on-the-fly prefs switching causing issues + +/datum/quirk/colorblind/add(client/client_source) + colorblind_type = client_source?.prefs?.read_preference(/datum/preference/choiced/colorblindedness) + switch(colorblind_type) + if(COLORBLINDNESS_PROTANOPIA) + quirk_holder.add_client_colour(/datum/client_colour/colorblind/protanopia) + if(COLORBLINDNESS_DEUTERANOPIA) + quirk_holder.add_client_colour(/datum/client_colour/colorblind/deuteranopia) + if(COLORBLINDNESS_TRITANOPIA) + quirk_holder.add_client_colour(/datum/client_colour/colorblind/tritanopia) + +/datum/quirk/colorblind/remove() + switch(colorblind_type) + if(COLORBLINDNESS_PROTANOPIA) + quirk_holder.remove_client_colour(/datum/client_colour/colorblind/protanopia) + if(COLORBLINDNESS_DEUTERANOPIA) + quirk_holder.remove_client_colour(/datum/client_colour/colorblind/deuteranopia) + if(COLORBLINDNESS_TRITANOPIA) + quirk_holder.remove_client_colour(/datum/client_colour/colorblind/tritanopia) + +/datum/quirk_constant_data/colorblind + associated_typepath = /datum/quirk/colorblind + customization_options = list(/datum/preference/choiced/colorblindedness) + +/datum/preference/choiced/colorblindedness + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "colorblindedness" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + +/datum/preference/choiced/colorblindedness/create_default_value() + return COLORBLINDNESS_DEUTERANOPIA // most common type + +/datum/preference/choiced/colorblindedness/init_possible_values() + return list(COLORBLINDNESS_PROTANOPIA, COLORBLINDNESS_DEUTERANOPIA, COLORBLINDNESS_TRITANOPIA) + +/datum/preference/choiced/colorblindedness/is_accessible(datum/preferences/preferences) + if(!..(preferences)) + return FALSE + + return /datum/quirk/colorblind::name in preferences.all_quirks + +/datum/preference/choiced/colorblindedness/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/client_colour/colorblind + priority = 10 // PRIORITY_HIGH + +/datum/client_colour/colorblind/protanopia + colour = list(0.56,0.43,0,0, 0.55,0.44,0,0, 0,0.24,0.75,0, 0,0,0,1, 0,0,0,0) + +/datum/client_colour/colorblind/deuteranopia + colour = list(0.62,0.37,0,0, 0.70,0.30,0,0, 0,0.30,0.70,0, 0,0,0,1, 0,0,0,0) + +/datum/client_colour/colorblind/tritanopia + colour = list(0.95,0.5,0,0, 0,0.43,0.56,0, 0,0.47,0.52,0, 0,0,0,1, 0,0,0,0) + +#undef COLORBLINDNESS_PROTANOPIA +#undef COLORBLINDNESS_DEUTERANOPIA +#undef COLORBLINDNESS_TRITANOPIA diff --git a/maplestation_modules/code/game/objects/effects/posters.dm b/maplestation_modules/code/game/objects/effects/posters.dm new file mode 100644 index 000000000000..1449bcde1158 --- /dev/null +++ b/maplestation_modules/code/game/objects/effects/posters.dm @@ -0,0 +1,21 @@ +/obj/structure/sign/poster/official/puppets_3 + name = "The Puppets 3: Goobit's Revenge" + desc = "A poster for the award-winning box-office-megabomb culmination of The Puppets franchise. \ + The film is notable for being both the highest-rated and lowest-earning movie of all time, due to the production company being legally required to refund every ticket \ + at 3 times the original price." + icon_state = "puppets" + icon = 'maplestation_modules/icons/obj/posters.dmi' + +/obj/structure/sign/poster/official/puppets_3/examine(mob/user) + . = ..() + . += notice("A tagline on the bottom reads: \"The City needs a hero, but all they could find were these guys...\"") + +/obj/structure/sign/poster/contraband/goobit + name = "Goobit's Gambit" + desc = "A poster of Goobit from the movie \"The Puppets 3: Goobit's Revenge\". This poster is notable for its use by eco-terrorist groups for propaganda. \ + These groups would regularly mimic the actions of Goobit by flooding entire planets water supply with vegetable oil in order to \"Make the planet strong\", \ + usually resulting in the deaths of all life on said planet. Possession of any pro-Goobit contraband is an act of high treason in most governments, with the average \ + felon found guilty of this being 3 years of age. Punishment for the crime tends to be excommunication via spaceraft, with all 1,659 recovered rafts being found empty, \ + but otherwise in expected condition." + icon_state = "goobit" + icon = 'maplestation_modules/icons/obj/posters.dmi' diff --git a/maplestation_modules/code/modules/client/preferences/languages.dm b/maplestation_modules/code/modules/client/preferences/languages.dm index b14600bdb78d..cd1d4fa62f62 100644 --- a/maplestation_modules/code/modules/client/preferences/languages.dm +++ b/maplestation_modules/code/modules/client/preferences/languages.dm @@ -39,7 +39,6 @@ can_randomize = FALSE /// List of languages you can pick. - /// You only need to add languagues here that are not spoken by selectable roundstart species. var/list/selectable_languages = list( /datum/language/common, /datum/language/impdraconic, diff --git a/maplestation_modules/code/modules/client/preferences/loadout_preference.dm b/maplestation_modules/code/modules/client/preferences/loadout_preference.dm index eef81b74dd9f..cf224e4d7508 100644 --- a/maplestation_modules/code/modules/client/preferences/loadout_preference.dm +++ b/maplestation_modules/code/modules/client/preferences/loadout_preference.dm @@ -36,13 +36,9 @@ // Sanitize on load to ensure no invalid paths from older saves get in /datum/preference/loadout/deserialize(input, datum/preferences/preferences) - // Sanitize on load to ensure no invalid paths from older saves get in - var/slot = preferences.read_preference(/datum/preference/numeric/active_loadout) - for(var/i in 1 to length(input)) if(islist(input[i])) - // Pass in the prefernce owner so they can get feedback messages on stuff that failed to load (if they exist) - input[i] = sanitize_loadout_list(input[i], preferences.parent?.mob, slot) + input[i] = sanitize_loadout_list(input[i]) return input @@ -52,25 +48,14 @@ * * Returns a list, or null if empty */ -/datum/preference/loadout/proc/sanitize_loadout_list(list/passed_list, mob/optional_loadout_owner) as /list +/datum/preference/loadout/proc/sanitize_loadout_list(list/passed_list) as /list var/list/sanitized_list for(var/path in passed_list) // Loading from json has each path in the list as a string that we need to convert back to typepath var/obj/item/real_path = istext(path) ? text2path(path) : path if(!ispath(real_path, /obj/item)) - if(optional_loadout_owner) - to_chat(optional_loadout_owner, span_boldnotice("The following invalid item path was found \ - in your character loadout: [real_path || "null"]. \ - It has been removed, renamed, or is otherwise missing - \ - You may want to check your loadout settings.")) continue - - else if(!istype(GLOB.all_loadout_datums[real_path], /datum/loadout_item)) - if(optional_loadout_owner) - to_chat(optional_loadout_owner, span_boldnotice("The following invalid loadout item was found \ - in your character loadout: [real_path || "null"]. \ - It has been removed, renamed, or is otherwise missing - \ - You may want to check your loadout settings.")) + if(!istype(GLOB.all_loadout_datums[real_path], /datum/loadout_item)) continue // Set into sanitize list using converted path key diff --git a/maplestation_modules/code/modules/clothing/suits/armor.dm b/maplestation_modules/code/modules/clothing/suits/armor.dm index f29aa8bc59d7..a3f20a1bbdd1 100644 --- a/maplestation_modules/code/modules/clothing/suits/armor.dm +++ b/maplestation_modules/code/modules/clothing/suits/armor.dm @@ -84,6 +84,8 @@ name = "tailored parade jacket" desc = "No armor, all fashion, unfortunately." icon_state = "formal" + icon_preview = 'maplestation_modules/icons/obj/clothing/suit.dmi' + icon_state_preview = "formal" inhand_icon_state = "labcoat" body_parts_covered = CHEST|GROIN|ARMS allowed = list( diff --git a/maplestation_modules/code/modules/clothing/under/loadout_under.dm b/maplestation_modules/code/modules/clothing/under/loadout_under.dm index 5529e94cd770..3407a4ea5564 100644 --- a/maplestation_modules/code/modules/clothing/under/loadout_under.dm +++ b/maplestation_modules/code/modules/clothing/under/loadout_under.dm @@ -36,6 +36,8 @@ icon = 'maplestation_modules/icons/obj/clothing/under/spacer_turtleneck.dmi' worn_icon = 'maplestation_modules/icons/mob/clothing/under/spacer_turtleneck.dmi' icon_state = "turtleneck" + icon_preview = 'maplestation_modules/icons/obj/clothing/under/spacer_turtleneck.dmi' + icon_state_preview = "greyscale_sweater" greyscale_config = /datum/greyscale_config/spacer_turtleneck greyscale_config_worn = /datum/greyscale_config/spacer_turtleneck_worn greyscale_colors = "#5e483c#1c1c1c#4fb4e6" @@ -46,6 +48,7 @@ name = "spacer's uniform" desc = "An old ship uniform from the days of spacefarers past. In the old days, engineering wore red and command wore gold." icon_state = "turtlefool" + icon_state_preview = "greyscale_shirt" /obj/item/clothing/under/spacer_turtleneck/skirt name = "spacer's skirtleneck" @@ -59,6 +62,7 @@ name = "spacer's skirt" desc = "An old ship uniform from the days of spacefarers past. In the old days, engineering wore red and command wore gold. And women wore less." icon_state = "turtlefool_skirt" + icon_state_preview = "greyscale_shirt" /obj/item/clothing/under/arbitersuit name = "arbiter's suit" @@ -76,6 +80,14 @@ icon_state = "chesed_suit" clothing_traits = list(TRAIT_CAFFEINE_LOVER) +/obj/item/clothing/under/mvfjumpsuit + name = "pale jumpsuit" + desc = "An old-fashioned pale white jumpsuit. Common in spaces within the Mira-Vodyanoy Foundation's sphere of influence." + icon = 'maplestation_modules/icons/obj/clothing/under/jumpsuit.dmi' + worn_icon = 'maplestation_modules/icons/mob/clothing/under/jumpsuit.dmi' + icon_state = "mvf_jumpsuit" + can_adjust = FALSE + // https://github.com/Skyrat-SS13/Skyrat-tg/pull/17098 /obj/item/clothing/under/dress/countess name = "countess dress" diff --git a/maplestation_modules/code/modules/jobs/job_types/stowaway.dm b/maplestation_modules/code/modules/jobs/job_types/stowaway.dm index d1c96b23760c..6963ad143dc8 100644 --- a/maplestation_modules/code/modules/jobs/job_types/stowaway.dm +++ b/maplestation_modules/code/modules/jobs/job_types/stowaway.dm @@ -137,6 +137,7 @@ desc = "Not sure what to do? Click here for a random backstory and some extra equipment. \ This will go away shortly, so don't worry if you don't want it." icon_state = "surrender" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/backstory/Click(location, control, params) . = ..() diff --git a/maplestation_modules/code/modules/loadouts/loadout_items/_loadout_datum.dm b/maplestation_modules/code/modules/loadouts/loadout_items/_loadout_datum.dm index 348e9007ea28..b0cf6d0ade23 100644 --- a/maplestation_modules/code/modules/loadouts/loadout_items/_loadout_datum.dm +++ b/maplestation_modules/code/modules/loadouts/loadout_items/_loadout_datum.dm @@ -1,11 +1,11 @@ /// Global list of ALL loadout datums instantiated. /// Loadout datums are created by loadout categories. -GLOBAL_LIST_EMPTY(all_loadout_datums) +GLOBAL_LIST_EMPTY_TYPED(all_loadout_datums, /datum/loadout_item) /// Global list of all loadout categories /// Doesn't really NEED to be a global but we need to init this early for preferences, /// as the categories instantiate all the loadout datums -GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) +GLOBAL_LIST_INIT_TYPED(all_loadout_categories, /datum/loadout_category, init_loadout_categories()) /// Inits the global list of loadout category singletons /// Also inits loadout item singletons @@ -46,6 +46,8 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) /// Whether this item can be reskinned. /// Only works if the item has a "unique reskin" list set. var/can_be_reskinned = FALSE + /// If set, this item can only be selected during the holiday specified. + var/required_holiday /// The abstract parent of this loadout item, to determine which items to not instantiate var/abstract_type = /datum/loadout_item /// The actual item path of the loadout item. @@ -225,10 +227,11 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) * At this point the item is in the mob's contents * * Arguments: + * * equipped_item - the item that was equipped - may be null for certain items (pocket items) * * preference_source - the datum/preferences our loadout item originated from - cannot be null + * * preference_list - what the raw loadout list looks like in the preferences * * equipper - the mob we're equipping this item onto - cannot be null * * visuals_only - whether or not this is only concerned with visual things (not backpack, not renaming, etc) - * * preference_list - what the raw loadout list looks like in the preferences * * Return a bitflag of slot flags to update */ @@ -239,7 +242,8 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) mob/living/carbon/human/equipper, visuals_only = FALSE, ) - ASSERT(!isnull(equipped_item)) + if(isnull(equipped_item)) + return NONE //if(!visuals_only) // ADD_TRAIT(equipped_item, TRAIT_ITEM_OBJECTIVE_BLOCKED, "Loadout") @@ -293,8 +297,15 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) formatted_item["reskins"] = get_reskin_options() formatted_item["icon"] = ui_icon formatted_item["icon_state"] = ui_icon_state + formatted_item["disabled"] = is_disabled() return formatted_item +/** + * Checks if this item is disabled and cannot be selected or granted + */ +/datum/loadout_item/proc/is_disabled() + return required_holiday && !check_holidays(required_holiday) + /** * Returns a list of information to display about this item in the loadout UI. * @@ -304,7 +315,11 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) SHOULD_CALL_PARENT(TRUE) var/list/displayed_text = list() - displayed_text += (additional_displayed_text || list()) + if(LAZYLEN(additional_displayed_text)) + displayed_text += additional_displayed_text + + if(required_holiday) + displayed_text += required_holiday if(can_be_greyscale) displayed_text += "Recolorable" @@ -321,7 +336,7 @@ GLOBAL_LIST_INIT(all_loadout_categories, init_loadout_categories()) * Returns a list of buttons that are shown in the loadout UI for customizing this item. * * Buttons contain - * - 'L'abel: The text displayed beside the button + * - Label: The text displayed beside the button * - act_key: The key that is sent to the loadout manager when the button is clicked, * for use in handle_loadout_action * - button_icon: The FontAwesome icon to display on the button diff --git a/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_heads.dm b/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_heads.dm index 1a5094ec4d25..c6d495836eff 100644 --- a/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_heads.dm +++ b/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_heads.dm @@ -268,3 +268,8 @@ name = "Violet Nurse Cap" item_path = /obj/item/clothing/head/costume/vince additional_displayed_text = list("Character Item") + +/datum/loadout_item/head/santa + name = "Santa Hat" + item_path = /obj/item/clothing/head/costume/santa/gags + required_holiday = FESTIVE_SEASON diff --git a/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_pocket.dm b/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_pocket.dm index 6542c88842eb..db57d7fa6fdb 100644 --- a/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_pocket.dm +++ b/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_pocket.dm @@ -116,42 +116,71 @@ name = "Pack of HP+ Gum" item_path = /obj/item/storage/box/gum/happiness -/datum/loadout_item/pocket_items/lipstick_black - name = "Lipstick (Black)" - item_path = /obj/item/lipstick/black - additional_displayed_text = list("Black") - -/datum/loadout_item/pocket_items/lipstick_blue - name = "Lipstick (Blue)" - item_path = /obj/item/lipstick/blue - additional_displayed_text = list("Blue") - - -/datum/loadout_item/pocket_items/lipstick_green - name = "Lipstick (Green)" - item_path = /obj/item/lipstick/green - additional_displayed_text = list("Green") - - -/datum/loadout_item/pocket_items/lipstick_jade - name = "Lipstick (Jade)" - item_path = /obj/item/lipstick/jade - additional_displayed_text = list("Jade") - -/datum/loadout_item/pocket_items/lipstick_purple - name = "Lipstick (Purple)" - item_path = /obj/item/lipstick/purple - additional_displayed_text = list("Purple") - -/datum/loadout_item/pocket_items/lipstick_red - name = "Lipstick (Red)" +/datum/loadout_item/pocket_items/lipstick + name = "Lipstick" item_path = /obj/item/lipstick - additional_displayed_text = list("Red") + additional_displayed_text = list("Recolorable") -/datum/loadout_item/pocket_items/lipstick_white - name = "Lipstick (White)" - item_path = /obj/item/lipstick/white - additional_displayed_text = list("White") +/datum/loadout_item/pocket_items/lipstick/on_equip_item( + obj/item/lipstick/equipped_item, + datum/preferences/preference_source, + list/preference_list, + mob/living/carbon/human/equipper, + visuals_only, +) + . = ..() + var/picked_style = style_to_style(preference_list[item_path]?[INFO_LAYER]) + var/picked_color = preference_list[item_path]?[INFO_GREYSCALE] || /obj/item/lipstick::lipstick_color + if(istype(equipped_item)) // can be null for visuals_only + equipped_item.style = picked_style + equipped_item.lipstick_color = picked_color + equipper.update_lips(picked_style, picked_color) + +/// Converts style (readable) to style (internal) +/datum/loadout_item/pocket_items/lipstick/proc/style_to_style(style) + switch(style) + if(UPPER_LIP) + return "lipstick_upper" + if(LOWER_LIP) + return "lipstick_lower" + return "lipstick" + +/datum/loadout_item/pocket_items/lipstick/get_ui_buttons() + . = ..() + UNTYPED_LIST_ADD(., list( + "label" = "Style", + "act_key" = "select_lipstick_style", + "button_icon" = FA_ICON_ARROWS_ROTATE, + "active_key" = INFO_LAYER, + )) + UNTYPED_LIST_ADD(., list( + "label" = "Color", + "act_key" = "select_lipstick_color", + "button_icon" = FA_ICON_PALETTE, + "active_key" = INFO_GREYSCALE, + )) + +/datum/loadout_item/pocket_items/lipstick/handle_loadout_action(datum/preference_middleware/loadout/manager, mob/user, action, params) + switch(action) + if("select_lipstick_style") + var/old_style = get_active_loadout(manager.preferences)[item_path][INFO_LAYER] || MIDDLE_LIP + var/chosen = tgui_input_list(user, "Pick a lipstick style. This determines where it goes on your sprite.", "Pick a style", list(UPPER_LIP, MIDDLE_LIP, LOWER_LIP), old_style) + var/list/loadout = get_active_loadout(manager.preferences) // after sleep: sanity check + if(loadout?[item_path]) // Validate they still have it equipped + loadout[item_path][INFO_LAYER] = chosen + update_loadout(manager.preferences, loadout) + return TRUE // Update UI + + if("select_lipstick_color") + var/old_color = get_active_loadout(manager.preferences)[item_path][INFO_GREYSCALE] || /obj/item/lipstick::lipstick_color + var/chosen = input(user, "Pick a lipstick color.", "Pick a color", old_color) as color|null + var/list/loadout = get_active_loadout(manager.preferences) // after sleep: sanity check + if(loadout?[item_path]) // Validate they still have it equipped + loadout[item_path][INFO_GREYSCALE] = chosen + update_loadout(manager.preferences, loadout) + return TRUE // Update UI + + return ..() /datum/loadout_item/pocket_items/razor name = "Razor" diff --git a/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_under.dm b/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_under.dm index e53546e88820..5ddbb16f1f81 100644 --- a/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_under.dm +++ b/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_under.dm @@ -48,7 +48,7 @@ mob/living/carbon/human/equipper, visuals_only = FALSE, ) - return NONE + return NONE // acts funky /datum/loadout_item/under/jumpsuit/random/skirt name = "Random Jumpskirt" @@ -187,11 +187,11 @@ item_path = /obj/item/clothing/under/rank/civilian/lawyer/black/skirt /datum/loadout_item/under/formal/blue_suit - name = "Blue Suit" + name = "Blue Button Down with Slacks" item_path = /obj/item/clothing/under/rank/civilian/lawyer/bluesuit /datum/loadout_item/under/formal/blue_suitskirt - name = "Blue Suitskirt" + name = "Blue Button Down with Skirt" item_path = /obj/item/clothing/under/rank/civilian/lawyer/bluesuit/skirt /datum/loadout_item/under/formal/blue_lawyer_suit @@ -262,7 +262,7 @@ name = "Purple Suitskirt" item_path = /obj/item/clothing/under/rank/civilian/lawyer/purpsuit/skirt -/datum/loadout_item/under/formal/red_lawyer_skirt +/datum/loadout_item/under/formal/red_lawyer name = "Red Lawyer Suit" item_path = /obj/item/clothing/under/rank/civilian/lawyer/red @@ -409,3 +409,7 @@ name = "Violet Nurse Uniform" item_path = /obj/item/clothing/under/dress/vince additional_displayed_text = list("Character Item") + +/datum/loadout_item/under/jumpsuit/mvfjumpsuit + name = "Pale Jumpsuit" + item_path = /obj/item/clothing/under/mvfjumpsuit diff --git a/maplestation_modules/code/modules/loadouts/loadout_ui/loadout_outfit_helpers.dm b/maplestation_modules/code/modules/loadouts/loadout_ui/loadout_outfit_helpers.dm index 94acebd9a08a..b9a6a06523da 100644 --- a/maplestation_modules/code/modules/loadouts/loadout_ui/loadout_outfit_helpers.dm +++ b/maplestation_modules/code/modules/loadouts/loadout_ui/loadout_outfit_helpers.dm @@ -30,7 +30,7 @@ CRASH("Invalid outfit passed to equip_outfit_and_loadout ([outfit])") var/list/preference_list = get_active_loadout(preference_source) - var/list/loadout_datums = loadout_list_to_datums(preference_list) + var/list/loadout_datums = loadout_list_to_datums(preference_list, skip_disabled = TRUE) // Slap our things into the outfit given for(var/datum/loadout_item/item as anything in loadout_datums) item.insert_path_into_outfit( @@ -46,11 +46,8 @@ var/list/new_contents = get_all_gear() var/update = NONE for(var/datum/loadout_item/item as anything in loadout_datums) - var/obj/item/equipped = locate(item.item_path) in new_contents - if(isnull(equipped)) - continue update |= item.on_equip_item( - equipped_item = equipped, + equipped_item = locate(item.item_path) in new_contents, preference_source = preference_source, preference_list = preference_list, equipper = src, @@ -65,21 +62,24 @@ * Takes a list of paths (such as a loadout list) * and returns a list of their singleton loadout item datums * - * loadout_list - the list being checked + * * loadout_list - the list being checked + * * skip_disabled - whether to skip disabled items (like holiday items during non-holiday seasons) * * Returns a list of singleton datums */ -/proc/loadout_list_to_datums(list/loadout_list) as /list +/proc/loadout_list_to_datums(list/loadout_list, skip_disabled = FALSE) as /list var/list/datums = list() if(!length(GLOB.all_loadout_datums)) CRASH("No loadout datums in the global loadout list!") for(var/path in loadout_list) - var/actual_datum = GLOB.all_loadout_datums[path] - if(!istype(actual_datum, /datum/loadout_item)) + var/datum/loadout_item/actual_datum = GLOB.all_loadout_datums[path] + if(!istype(actual_datum)) stack_trace("Could not find ([path]) loadout item in the global list of loadout datums!") continue + if(skip_disabled && actual_datum.is_disabled()) + continue datums += actual_datum @@ -90,7 +90,7 @@ * * Returns a loadout lazylist */ -/proc/get_active_loadout(datum/preferences/preferences) +/proc/get_active_loadout(datum/preferences/preferences) as /list RETURN_TYPE(/list) var/slot = preferences.read_preference(/datum/preference/numeric/active_loadout) var/list/all_loadouts = preferences.read_preference(/datum/preference/loadout) diff --git a/maplestation_modules/code/modules/magic/story_spells/illusion.dm b/maplestation_modules/code/modules/magic/story_spells/illusion.dm index add158d7d3d5..117b08b1c3f5 100644 --- a/maplestation_modules/code/modules/magic/story_spells/illusion.dm +++ b/maplestation_modules/code/modules/magic/story_spells/illusion.dm @@ -150,6 +150,7 @@ Or you can click this to cancel it." icon = 'maplestation_modules/icons/hud/screen_alert.dmi' icon_state = "illusion" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/maintaining_illusion/Click(location, control, params) . = ..() diff --git a/maplestation_modules/code/modules/magic/story_spells/soothe.dm b/maplestation_modules/code/modules/magic/story_spells/soothe.dm index c6d18edc92e2..c1803f3ddab3 100644 --- a/maplestation_modules/code/modules/magic/story_spells/soothe.dm +++ b/maplestation_modules/code/modules/magic/story_spells/soothe.dm @@ -129,6 +129,7 @@ desc = "Some force is being exerted on you, suddenly quieting your rage, fear, and doubt. \ You can resist this effect, if your feelings are stronger than this force lets on." icon_state = "high" + mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/alert/status_effect/being_soothed/Click(location, control, params) if(usr != owner || !isliving(owner)) diff --git a/maplestation_modules/code/modules/mob/dead/new_player/sprite_accessories.dm b/maplestation_modules/code/modules/mob/dead/new_player/sprite_accessories.dm index 2520d30660e4..3597dfc07391 100644 --- a/maplestation_modules/code/modules/mob/dead/new_player/sprite_accessories.dm +++ b/maplestation_modules/code/modules/mob/dead/new_player/sprite_accessories.dm @@ -513,3 +513,9 @@ name = "High Black Stockings" icon_state = "highblackstocking" icon = 'maplestation_modules/icons/mob/clothing/underwear.dmi' + +/// --- Facial Hair --- +/datum/sprite_accessory/facial_hair/foxmarkings // not exactly hair but i'm not coding a unique system for this *yet* + name = "Facial Markings" + icon_state = "facial_foxmarkings" + icon = 'maplestation_modules/icons/mob/human_face.dmi' diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/skrell.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/skrell.dm index ec2e9d71c8e1..f310fa97bc7f 100644 --- a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/skrell.dm +++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/skrell.dm @@ -37,14 +37,6 @@ GLOBAL_LIST_EMPTY(head_tentacles_list) else return string_assoc_list(list('maplestation_modules/sound/voice/huff.ogg' = 120)) -/datum/species/skrell/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) - . = ..() - C.missing_eye_file = 'maplestation_modules/icons/mob/skrell_eyes.dmi' - -/datum/species/skrell/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) - C.missing_eye_file = initial(C.missing_eye_file) - return ..() - /datum/species/skrell/spec_life(mob/living/carbon/human/skrell_mob, seconds_per_tick, times_fired) . = ..() if(skrell_mob.nutrition > NUTRITION_LEVEL_ALMOST_FULL) @@ -132,6 +124,7 @@ GLOBAL_LIST_EMPTY(head_tentacles_list) limb_id = SPECIES_SKRELL icon_greyscale = 'maplestation_modules/icons/mob/skrell_parts_greyscale.dmi' head_flags = HEAD_LIPS|HEAD_EYESPRITES|HEAD_EYEHOLES|HEAD_DEBRAIN + missing_eye_file = 'maplestation_modules/icons/mob/skrell_eyes.dmi' /obj/item/bodypart/leg/left/skrell limb_id = SPECIES_SKRELL diff --git a/maplestation_modules/code/modules/surgery/organs/eyes.dm b/maplestation_modules/code/modules/surgery/organs/eyes.dm deleted file mode 100644 index 1515021eb4b6..000000000000 --- a/maplestation_modules/code/modules/surgery/organs/eyes.dm +++ /dev/null @@ -1,7 +0,0 @@ -/obj/item/organ/internal/eyes - /// Overlay file to take eye icons from - var/eye_overlay_file = 'icons/mob/human/human_face.dmi' - -/mob/living/carbon - /// Overlay file to take (missing) eye icons from - var/missing_eye_file = 'icons/mob/human/human_face.dmi' diff --git a/maplestation_modules/code/modules/surgery/organs/tails.dm b/maplestation_modules/code/modules/surgery/organs/tails.dm index 4b74371ab8d6..f19b9f3c48cb 100644 --- a/maplestation_modules/code/modules/surgery/organs/tails.dm +++ b/maplestation_modules/code/modules/surgery/organs/tails.dm @@ -8,3 +8,14 @@ icon_state = "fox" icon = 'maplestation_modules/icons/mob/mutant_bodyparts.dmi' color_src = HAIR_COLOR + +/obj/item/organ/external/tail/cat/fivefox + name = "five fox tails" + icon = 'maplestation_modules/icons/obj/surgery.dmi' + icon_state = "severedfivefoxtail" + +/datum/sprite_accessory/tails/human/fivefox + name = "Five Fox" + icon_state = "fivefox" + icon = 'maplestation_modules/icons/mob/mutant_bodyparts.dmi' + color_src = HAIR_COLOR diff --git a/maplestation_modules/code/modules/vending/clothesmate.dm b/maplestation_modules/code/modules/vending/clothesmate.dm index 8748b25ce97d..0e6a669b2e78 100644 --- a/maplestation_modules/code/modules/vending/clothesmate.dm +++ b/maplestation_modules/code/modules/vending/clothesmate.dm @@ -16,6 +16,7 @@ /obj/item/clothing/under/spacer_turtleneck/plain = 3, /obj/item/clothing/under/spacer_turtleneck/skirt = 3, /obj/item/clothing/under/spacer_turtleneck/skirt/plain = 3, + /obj/item/clothing/under/mvfjumpsuit = 3, /obj/item/clothing/under/arbitersuit = 2, /obj/item/clothing/under/chesedsuit = 2, ), diff --git a/maplestation_modules/icons/mob/clothing/under/jumpsuit.dmi b/maplestation_modules/icons/mob/clothing/under/jumpsuit.dmi new file mode 100644 index 000000000000..3f11e54623a9 Binary files /dev/null and b/maplestation_modules/icons/mob/clothing/under/jumpsuit.dmi differ diff --git a/maplestation_modules/icons/mob/human_face.dmi b/maplestation_modules/icons/mob/human_face.dmi index 5d3959da2151..de86dbc81977 100644 Binary files a/maplestation_modules/icons/mob/human_face.dmi and b/maplestation_modules/icons/mob/human_face.dmi differ diff --git a/maplestation_modules/icons/mob/mutant_bodyparts.dmi b/maplestation_modules/icons/mob/mutant_bodyparts.dmi index eb3e768f68d7..f80e69165898 100644 Binary files a/maplestation_modules/icons/mob/mutant_bodyparts.dmi and b/maplestation_modules/icons/mob/mutant_bodyparts.dmi differ diff --git a/maplestation_modules/icons/obj/clothing/under/jumpsuit.dmi b/maplestation_modules/icons/obj/clothing/under/jumpsuit.dmi new file mode 100644 index 000000000000..05009c164358 Binary files /dev/null and b/maplestation_modules/icons/obj/clothing/under/jumpsuit.dmi differ diff --git a/maplestation_modules/icons/obj/posters.dmi b/maplestation_modules/icons/obj/posters.dmi new file mode 100644 index 000000000000..24b6d10ae223 Binary files /dev/null and b/maplestation_modules/icons/obj/posters.dmi differ diff --git a/maplestation_modules/icons/obj/surgery.dmi b/maplestation_modules/icons/obj/surgery.dmi index 3c7b2e2b5a42..429cf7214e45 100644 Binary files a/maplestation_modules/icons/obj/surgery.dmi and b/maplestation_modules/icons/obj/surgery.dmi differ diff --git a/maplestation_modules/sound/attribution.txt b/maplestation_modules/sound/attribution.txt index 7d52f1491f43..940677841e2d 100644 --- a/maplestation_modules/sound/attribution.txt +++ b/maplestation_modules/sound/attribution.txt @@ -13,6 +13,7 @@ - the contents of `item/storage` - the contents of `item/pickup` - all healthscanner_x.oggs +-tile1.ogg through tile4.ogg Have been ported from other stations, and given a lack of existing attribution, are assumed to be CC-BY-SA 3.0 unless stated otherwise below diff --git a/maplestation_modules/sound/footstep/tile1.ogg b/maplestation_modules/sound/footstep/tile1.ogg new file mode 100644 index 000000000000..6c54acc7decf Binary files /dev/null and b/maplestation_modules/sound/footstep/tile1.ogg differ diff --git a/maplestation_modules/sound/footstep/tile2.ogg b/maplestation_modules/sound/footstep/tile2.ogg new file mode 100644 index 000000000000..910a4cde6dae Binary files /dev/null and b/maplestation_modules/sound/footstep/tile2.ogg differ diff --git a/maplestation_modules/sound/footstep/tile3.ogg b/maplestation_modules/sound/footstep/tile3.ogg new file mode 100644 index 000000000000..0746d5702bfa Binary files /dev/null and b/maplestation_modules/sound/footstep/tile3.ogg differ diff --git a/maplestation_modules/sound/footstep/tile4.ogg b/maplestation_modules/sound/footstep/tile4.ogg new file mode 100644 index 000000000000..e473e52b9ae1 Binary files /dev/null and b/maplestation_modules/sound/footstep/tile4.ogg differ diff --git a/maplestation_modules/story_content/wollys_items/code/wollysitems.dm b/maplestation_modules/story_content/wollys_items/code/wollysitems.dm index b2a559973fd6..72d4a55f091f 100644 --- a/maplestation_modules/story_content/wollys_items/code/wollysitems.dm +++ b/maplestation_modules/story_content/wollys_items/code/wollysitems.dm @@ -84,6 +84,23 @@ since some of them are two per character or singleton, i'm gonna save space and // clothing & armor +/obj/item/clothing/under/elijumpsuit + name = "modified pale jumpsuit" + desc = "An old-fashioned pale white jumpsuit. This one has been modified with peculiar markings." + icon = 'maplestation_modules/story_content/wollys_items/icons/obj/clothing/jumpsuit.dmi' + worn_icon = 'maplestation_modules/story_content/wollys_items/icons/mob/clothing/jumpsuit.dmi' + icon_state = "eli_suit" + can_adjust = FALSE + +/obj/item/clothing/mask/elikitsune + name = "advanced kitsune mask" // todo + desc = "todo" + w_class = WEIGHT_CLASS_SMALL + flags_inv = HIDEFACE|HIDEFACIALHAIR + icon = 'maplestation_modules/story_content/wollys_items/icons/obj/clothing/mask.dmi' + worn_icon = 'maplestation_modules/story_content/wollys_items/icons/mob/clothing/mask.dmi' + icon_state = "eli_mask" + /obj/item/clothing/suit/toggle/cyrilcloak name = "Claw-Sewn Cloak" desc = "A warm cloak hand sewn by a tailor's hand. Its meant for cold winter climates, not brooding in a dark corner, mind you." @@ -137,6 +154,16 @@ since some of them are two per character or singleton, i'm gonna save space and item_path = /obj/item/clothing/suit/matthewjacket additional_displayed_text = list("Character Item") +/datum/loadout_item/under/jumpsuit/elijumpsuit + name = "Modified Pale Jumpsuit" + item_path = /obj/item/clothing/under/elijumpsuit + additional_displayed_text = list("Character Item") + +/datum/loadout_item/mask/elimask + name = "Advanced Kitsune Mask" + item_path = /obj/item/clothing/mask/elikitsune + additional_displayed_text = list("Character Item") + // sheathes /obj/item/storage/belt/sheathe/maugrim diff --git a/maplestation_modules/story_content/wollys_items/icons/mob/clothing/jumpsuit.dmi b/maplestation_modules/story_content/wollys_items/icons/mob/clothing/jumpsuit.dmi new file mode 100644 index 000000000000..ef5cd1790ff7 Binary files /dev/null and b/maplestation_modules/story_content/wollys_items/icons/mob/clothing/jumpsuit.dmi differ diff --git a/maplestation_modules/story_content/wollys_items/icons/mob/clothing/mask.dmi b/maplestation_modules/story_content/wollys_items/icons/mob/clothing/mask.dmi new file mode 100644 index 000000000000..4e25ab9681fd Binary files /dev/null and b/maplestation_modules/story_content/wollys_items/icons/mob/clothing/mask.dmi differ diff --git a/maplestation_modules/story_content/wollys_items/icons/obj/clothing/jumpsuit.dmi b/maplestation_modules/story_content/wollys_items/icons/obj/clothing/jumpsuit.dmi new file mode 100644 index 000000000000..eb239a941782 Binary files /dev/null and b/maplestation_modules/story_content/wollys_items/icons/obj/clothing/jumpsuit.dmi differ diff --git a/maplestation_modules/story_content/wollys_items/icons/obj/clothing/mask.dmi b/maplestation_modules/story_content/wollys_items/icons/obj/clothing/mask.dmi new file mode 100644 index 000000000000..ac46e46a3141 Binary files /dev/null and b/maplestation_modules/story_content/wollys_items/icons/obj/clothing/mask.dmi differ diff --git a/sound/attributions.txt b/sound/attributions.txt index 5625579ec138..0818ac88bced 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -179,6 +179,10 @@ liquid_pour2.ogg and liquid_pour3.ogg were cut from https://freesound.org/people/MattRuthSound/sounds/561896/ https://freesound.org/people/MattRuthSound/sounds/561895/ + +roaring_fire.ogg made from: 10835 big fire loop.wav by Robinhood76 -- https://freesound.org/s/612277/ -- License: Attribution NonCommercial 4.0 +fire_puff made from: Bonfire Being Lit by samararaine -- https://freesound.org/s/186374/ -- License: Creative Commons 0 + ayylien.ogg was made by remixing: SCIRetro_Energy Swells Synth_Funky Audio_Sonics Spices by Funky_Audio under CC0 -- https://freesound.org/people/realtheremin/sounds/119011/ scifi_scare_a.aiff by realtheremin under CC0 -- https://freesound.org/people/Funky_Audio/sounds/729392/ diff --git a/sound/effects/fire_puff.ogg b/sound/effects/fire_puff.ogg new file mode 100644 index 000000000000..c238584f55a6 Binary files /dev/null and b/sound/effects/fire_puff.ogg differ diff --git a/sound/effects/fireclip1.ogg b/sound/effects/fireclip1.ogg new file mode 100644 index 000000000000..89ba2395a4d9 Binary files /dev/null and b/sound/effects/fireclip1.ogg differ diff --git a/sound/effects/fireclip2.ogg b/sound/effects/fireclip2.ogg new file mode 100644 index 000000000000..c60990cd5bd7 Binary files /dev/null and b/sound/effects/fireclip2.ogg differ diff --git a/sound/effects/fireclip3.ogg b/sound/effects/fireclip3.ogg new file mode 100644 index 000000000000..cd6860895987 Binary files /dev/null and b/sound/effects/fireclip3.ogg differ diff --git a/sound/effects/fireclip4.ogg b/sound/effects/fireclip4.ogg new file mode 100644 index 000000000000..9ae01a8d3ade Binary files /dev/null and b/sound/effects/fireclip4.ogg differ diff --git a/sound/effects/fireclip5.ogg b/sound/effects/fireclip5.ogg new file mode 100644 index 000000000000..855cc4b820d5 Binary files /dev/null and b/sound/effects/fireclip5.ogg differ diff --git a/sound/effects/fireclip6.ogg b/sound/effects/fireclip6.ogg new file mode 100644 index 000000000000..061cc42993d8 Binary files /dev/null and b/sound/effects/fireclip6.ogg differ diff --git a/sound/effects/fireclip7.ogg b/sound/effects/fireclip7.ogg new file mode 100644 index 000000000000..3a0f9840f3c5 Binary files /dev/null and b/sound/effects/fireclip7.ogg differ diff --git a/sound/effects/roaring_fire.ogg b/sound/effects/roaring_fire.ogg new file mode 100644 index 000000000000..b3927b69feb8 Binary files /dev/null and b/sound/effects/roaring_fire.ogg differ diff --git a/sound/effects/writing_pen/attribution.txt b/sound/effects/writing_pen/attribution.txt new file mode 100644 index 000000000000..7af5720c2fc4 --- /dev/null +++ b/sound/effects/writing_pen/attribution.txt @@ -0,0 +1,2 @@ +writing_pen made by sadboysuss +license: CC-BY-SA 3.0 \ No newline at end of file diff --git a/sound/effects/writing_pen/writing_pen1.ogg b/sound/effects/writing_pen/writing_pen1.ogg new file mode 100644 index 000000000000..1041e026e6b7 Binary files /dev/null and b/sound/effects/writing_pen/writing_pen1.ogg differ diff --git a/sound/effects/writing_pen/writing_pen2.ogg b/sound/effects/writing_pen/writing_pen2.ogg new file mode 100644 index 000000000000..855cf2c852ed Binary files /dev/null and b/sound/effects/writing_pen/writing_pen2.ogg differ diff --git a/sound/effects/writing_pen/writing_pen3.ogg b/sound/effects/writing_pen/writing_pen3.ogg new file mode 100644 index 000000000000..2e9362c99db7 Binary files /dev/null and b/sound/effects/writing_pen/writing_pen3.ogg differ diff --git a/sound/effects/writing_pen/writing_pen4.ogg b/sound/effects/writing_pen/writing_pen4.ogg new file mode 100644 index 000000000000..cbd095ef3f2a Binary files /dev/null and b/sound/effects/writing_pen/writing_pen4.ogg differ diff --git a/sound/effects/writing_pen/writing_pen5.ogg b/sound/effects/writing_pen/writing_pen5.ogg new file mode 100644 index 000000000000..c3382cb1f593 Binary files /dev/null and b/sound/effects/writing_pen/writing_pen5.ogg differ diff --git a/sound/effects/writing_pen/writing_pen6.ogg b/sound/effects/writing_pen/writing_pen6.ogg new file mode 100644 index 000000000000..cffdc2810beb Binary files /dev/null and b/sound/effects/writing_pen/writing_pen6.ogg differ diff --git a/sound/effects/writing_pen/writing_pen7.ogg b/sound/effects/writing_pen/writing_pen7.ogg new file mode 100644 index 000000000000..9f753efff68e Binary files /dev/null and b/sound/effects/writing_pen/writing_pen7.ogg differ diff --git a/sound/mobs/humanoids/human/attribution.txt b/sound/mobs/humanoids/human/attribution.txt new file mode 100644 index 000000000000..86b91fa8afca --- /dev/null +++ b/sound/mobs/humanoids/human/attribution.txt @@ -0,0 +1 @@ +The male sharp gasps are from https://freesound.org/people/bacruz666/sounds/341908/ and https://freesound.org/people/nettoi/sounds/677540/, the female sharp gasps are from https://freesound.org/people/drotzruhn/sounds/405203/ diff --git a/sound/voice/credits.txt b/sound/voice/attribution.txt similarity index 61% rename from sound/voice/credits.txt rename to sound/voice/attribution.txt index b54e6ad53196..7bfe5c4a9ce1 100644 --- a/sound/voice/credits.txt +++ b/sound/voice/attribution.txt @@ -3,3 +3,10 @@ borg_deathsound.ogg is spliced from two clips, both of which are under the CC At all complianator sounds are licensed under CC-BY-SA by Michael Haugh (supermichael) The male sharp gasps in /sound/voice/human/ are from https://freesound.org/people/bacruz666/sounds/341908/ and https://freesound.org/people/nettoi/sounds/677540/, the female sharp gasps are from https://freesound.org/people/drotzruhn/sounds/405203/ + +{ +human/male_sniff.ogg - https://freesound.org/people/Fluffayfish/sounds/327799/ , License: CC BY-NC 3.0 +human/male_sigh.ogg - https://freesound.org/people/giddster/sounds/336540/ , License: CC0 +human/female_sniff.ogg - https://freesound.org/people/SpliceSound/sounds/218307/ , License: CC0 +human/female_sigh.ogg - https://freesound.org/people/biawinter/sounds/408090/ , License: CC BY-NC 4.0 +} modified by grungussuss \ No newline at end of file diff --git a/sound/voice/human/female_sigh.ogg b/sound/voice/human/female_sigh.ogg new file mode 100644 index 000000000000..3c338a868baf Binary files /dev/null and b/sound/voice/human/female_sigh.ogg differ diff --git a/sound/voice/human/male_sigh.ogg b/sound/voice/human/male_sigh.ogg new file mode 100644 index 000000000000..ec61683d68e9 Binary files /dev/null and b/sound/voice/human/male_sigh.ogg differ diff --git a/sound/voice/human/sigh/attribution.txt b/sound/voice/human/sigh/attribution.txt new file mode 100644 index 000000000000..c25e9bfa4057 --- /dev/null +++ b/sound/voice/human/sigh/attribution.txt @@ -0,0 +1,2 @@ +male sighs voiced by sadboysuss, license: CC-BY-SA 3.0 +female sighs voiced by redemptionarc, license: CC-BY-SA 3.0 diff --git a/sound/voice/human/sigh/female_sigh1.ogg b/sound/voice/human/sigh/female_sigh1.ogg new file mode 100644 index 000000000000..a2eee87932f5 Binary files /dev/null and b/sound/voice/human/sigh/female_sigh1.ogg differ diff --git a/sound/voice/human/sigh/female_sigh2.ogg b/sound/voice/human/sigh/female_sigh2.ogg new file mode 100644 index 000000000000..14462bca9147 Binary files /dev/null and b/sound/voice/human/sigh/female_sigh2.ogg differ diff --git a/sound/voice/human/sigh/female_sigh3.ogg b/sound/voice/human/sigh/female_sigh3.ogg new file mode 100644 index 000000000000..590b1cb49e7c Binary files /dev/null and b/sound/voice/human/sigh/female_sigh3.ogg differ diff --git a/sound/voice/human/sigh/male_sigh1.ogg b/sound/voice/human/sigh/male_sigh1.ogg new file mode 100644 index 000000000000..7cd64cff81a4 Binary files /dev/null and b/sound/voice/human/sigh/male_sigh1.ogg differ diff --git a/sound/voice/human/sigh/male_sigh2.ogg b/sound/voice/human/sigh/male_sigh2.ogg new file mode 100644 index 000000000000..5125ff8af984 Binary files /dev/null and b/sound/voice/human/sigh/male_sigh2.ogg differ diff --git a/sound/voice/human/sigh/male_sigh3.ogg b/sound/voice/human/sigh/male_sigh3.ogg new file mode 100644 index 000000000000..1139003d22e7 Binary files /dev/null and b/sound/voice/human/sigh/male_sigh3.ogg differ diff --git a/sound/voice/human/snore/attribution.txt b/sound/voice/human/snore/attribution.txt new file mode 100644 index 000000000000..e46271931238 --- /dev/null +++ b/sound/voice/human/snore/attribution.txt @@ -0,0 +1,2 @@ +male snores voiced by sadboysuss, license - CC-BY-SA +female snores and mimimi voiced by redemptionarc, license - CC-BY-SA diff --git a/sound/voice/human/snore/snore_female1.ogg b/sound/voice/human/snore/snore_female1.ogg new file mode 100644 index 000000000000..51cfeb0424fa Binary files /dev/null and b/sound/voice/human/snore/snore_female1.ogg differ diff --git a/sound/voice/human/snore/snore_female2.ogg b/sound/voice/human/snore/snore_female2.ogg new file mode 100644 index 000000000000..c5a9b44a4b89 Binary files /dev/null and b/sound/voice/human/snore/snore_female2.ogg differ diff --git a/sound/voice/human/snore/snore_female3.ogg b/sound/voice/human/snore/snore_female3.ogg new file mode 100644 index 000000000000..68adb30fb1e2 Binary files /dev/null and b/sound/voice/human/snore/snore_female3.ogg differ diff --git a/sound/voice/human/snore/snore_male1.ogg b/sound/voice/human/snore/snore_male1.ogg new file mode 100644 index 000000000000..3c9dfe97be8e Binary files /dev/null and b/sound/voice/human/snore/snore_male1.ogg differ diff --git a/sound/voice/human/snore/snore_male2.ogg b/sound/voice/human/snore/snore_male2.ogg new file mode 100644 index 000000000000..de5993e51879 Binary files /dev/null and b/sound/voice/human/snore/snore_male2.ogg differ diff --git a/sound/voice/human/snore/snore_male3.ogg b/sound/voice/human/snore/snore_male3.ogg new file mode 100644 index 000000000000..cd63a7fb4cfd Binary files /dev/null and b/sound/voice/human/snore/snore_male3.ogg differ diff --git a/sound/voice/human/snore/snore_male4.ogg b/sound/voice/human/snore/snore_male4.ogg new file mode 100644 index 000000000000..fce8320a6c7e Binary files /dev/null and b/sound/voice/human/snore/snore_male4.ogg differ diff --git a/sound/voice/human/snore/snore_male5.ogg b/sound/voice/human/snore/snore_male5.ogg new file mode 100644 index 000000000000..6773add51ecc Binary files /dev/null and b/sound/voice/human/snore/snore_male5.ogg differ diff --git a/sound/voice/human/snore/snore_mimimi1.ogg b/sound/voice/human/snore/snore_mimimi1.ogg new file mode 100644 index 000000000000..31f84ec2a14a Binary files /dev/null and b/sound/voice/human/snore/snore_mimimi1.ogg differ diff --git a/sound/voice/human/snore/snore_mimimi2.ogg b/sound/voice/human/snore/snore_mimimi2.ogg new file mode 100644 index 000000000000..21d4f9f07d4f Binary files /dev/null and b/sound/voice/human/snore/snore_mimimi2.ogg differ diff --git a/strings/sillytips.txt b/strings/sillytips.txt index 5aa7af7ba006..b652523bad04 100644 --- a/strings/sillytips.txt +++ b/strings/sillytips.txt @@ -2,6 +2,7 @@ As an Engineer, the Supermatter shard is an extremely dangerous piece of equipme As the Captain, you can use a whetstone to sharpen your fancy fountain pen for extra robustness. As the Lawyer, you are the last bastion of roleplay-focused jobs. Even the curator got a whip to go fight people with, that sellout! Ask and you shall receive. +Bitrunning is a crime. Blobs are weak to fire! Use a flame thrower for maximum damage! Cleanbot. Completing your objectives is good practice, but the best antagonists will strive to do more than the bare minimum to really leave an impression. @@ -35,6 +36,7 @@ This game is older than most of the people playing it. This is a game that is constantly being developed for. Expect things to be added, removed, fixed, and broken on a daily basis. To defeat the slaughter demon, shoot at it until it dies. When a round ends nearly everything about it is lost forever, leave your salt behind with it. +You can light a match with the heel of your boot. ...What's that? Friction matches went out of style in the 19th century? That's nonsense! You can win a pulse rifle from the arcade machine. Honest. Your sprite represents your hitbox, so that afro makes you easier to kill. The sacrifices we make for style. Gorillas can be killed by land mines placed along forest paths. diff --git a/strings/tips.txt b/strings/tips.txt index fd1dfd1542d1..741a1ca529c9 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -272,3 +272,20 @@ You can use a machine in the vault to deposit cash or rob Cargo's department fun You can use an upgraded microwave to charge your PDA! You'll quickly lose your interest in the game if you play to win and kill. If you find yourself doing this, take a step back and talk to people - it's a much better experience! Some areas of the station use simple nautical directions to indicate their respective locations, like Fore (Front of the ship), Aft (Back), Port (Left side), Starboard (Right), Quarter and Bow (Either sides of Aft and Fore, respectively). You can review these terms on the Notepad App of your PDA. +You don't need to destroy a Spacecoin machine to make your funds stop draining. Swiping your ID on it will stop the withdrawal. +As a Bitrunner, upgrading your quantum server will increase rewards and reduce downtime. +As a Bitrunner, your avatar has a domain info ability which will give you clues to help complete virtual domains. +You can alt-click tank transfer valves to remove a tank from them. +You can further the cycle of life by having two adult plushies play with eachother, creating a smaller junior child plushie. +Most species have only 32 teeth for use in dental implants. Moths have none. Lizards have seventy five. +You can craft peg limbs and crutches with wood for use in dire circumstances. The latter are also available in medical vendors. +Biological armor will protect your limb from a zombie's infective attack, unless the limb's more damaged than the armor value. Armor with thick material, such as firesuits and EVA suits, also partially protects, preventing at least the first attack from infection. +In a pinch, you can reduce bleeding or burn infection with several commonplace reagents - flour, salt, saltwater can all be splashed onto the wound to stall for time, and tea can be drank for a boost to your body's defences. +First-aid analyzers double the speed of wound treatment on injuries, alongside giving out normal and improvised instructions for treatment. +Syndicate Duffelbags are a lot quicker to zip and unzip, have significantly less slowdown, and can carry up to two of various bulky, objective-related items - such as fire axes, guns, or gibtonite. Examine them closely to see all the possibilities. +The Coroner's surgical tools are considered 'cruel implements', which speeds up surgery on corpses but slows it on not-yet-corpses. A few other items also have it. +As a Coroner, remember that your autopsy scanner also works as an advanced health analyzer on right-click, but only for corpses. +As the Captain, your sabre deals extra damage to Assistants (as long as they have their original liver). +You can automatically extract and retract arm implants by 'activating' the empty hand they're on. This includes integrated toolsets, cursed katanas, and vorpal scythes. +You can combine the Carpet reagent with various different reagents, such as Oil and Cyanide, to create unique carpet types. +You can bake a birthday cake and then microwave it to create a legendary cake hat. You can then combine it with an energy sword to create an energy cake. diff --git a/tgstation.dme b/tgstation.dme index 6b17fabbb451..d9aac5a5498b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1018,6 +1018,7 @@ #include "code\datums\components\chuunibyou.dm" #include "code\datums\components\cleaner.dm" #include "code\datums\components\clickbox.dm" +#include "code\datums\components\clothing_dirt.dm" #include "code\datums\components\clothing_fov_visor.dm" #include "code\datums\components\codeword_hearing.dm" #include "code\datums\components\combo_attacks.dm" @@ -1409,6 +1410,7 @@ #include "code\datums\elements\honkspam.dm" #include "code\datums\elements\hostile_machine.dm" #include "code\datums\elements\human_biter.dm" +#include "code\datums\elements\ignites_matches.dm" #include "code\datums\elements\immerse.dm" #include "code\datums\elements\item_fov.dm" #include "code\datums\elements\item_scaling.dm" @@ -1636,6 +1638,7 @@ #include "code\datums\quirks\negative_quirks\deafness.dm" #include "code\datums\quirks\negative_quirks\depression.dm" #include "code\datums\quirks\negative_quirks\family_heirloom.dm" +#include "code\datums\quirks\negative_quirks\fluoride_stare.dm" #include "code\datums\quirks\negative_quirks\food_allergy.dm" #include "code\datums\quirks\negative_quirks\frail.dm" #include "code\datums\quirks\negative_quirks\glass_jaw.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx index 0a95795abd18..e7f4add535f0 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/ItemDisplay.tsx @@ -60,6 +60,7 @@ export const ItemDisplay = (props: { style={{ textTransform: 'capitalize', zIndex: '1' }} tooltip={item.name} tooltipPosition={'bottom'} + disabled={item.disabled} onClick={() => act('select_item', { path: item.path, @@ -78,7 +79,7 @@ export const ItemDisplay = (props: { height="9px" key={info} fontSize="9px" - textColor={'darkgray'} + textColor={item.disabled ? 'darkred' : 'darkgray'} bold > {info} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts index 33f8cabea9cb..070ed063cc22 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts @@ -31,6 +31,7 @@ export type LoadoutItem = { buttons: LoadoutButton[]; reskins: ReskinOption[] | null; information: string[]; + disabled: BooleanLike; }; // Category of items in the loadout diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/colorblind.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/colorblind.tsx new file mode 100644 index 000000000000..c4b412bd9bb7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/colorblind.tsx @@ -0,0 +1,6 @@ +import { FeatureChoiced, FeatureDropdownInput } from '../base'; + +export const colorblindedness: FeatureChoiced = { + name: 'Colorblindness', + component: FeatureDropdownInput, +};