diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..b1d2dbdb58
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,22 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.{dme,dmf,dmm,dm}]
+end_of_line = crlf
+indent_style = tab
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.py]
+indent_style = space
+indent_size = 4
+
+[*.yml]
+indent_style = space
+indent_size = 2
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
index 5e9dfae55f..c5587f6042 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,10 +1,16 @@
-# dmm map merger hook
-# needs additional setup, see tools/mapmerge/install.txt
-# *.dmm merge=merge-dmm
-
-# dmi icon merger hook
-# needs additional setup, see tools/dmitool/merging.txt
-*.dmi merge=merge-dmi
-
-# force changelog merging to use union
-html/changelog.html merge=union
+## Enforce binary mode
+*.dll binary
+*.exe binary
+*.so binary
+*.zip binary
+
+# dmm map merger hook
+# needs additional setup, see tools/mapmerge/install.txt
+# *.dmm merge=merge-dmm
+
+# dmi icon merger hook
+# needs additional setup, see tools/dmitool/merging.txt
+*.dmi merge=merge-dmi
+
+# force changelog merging to use union
+html/changelog.html merge=union
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 4e64cf6ff7..fb33f2fafb 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -81,6 +81,12 @@ Then in our `handle_grabs_ch()` proc, if we want to avoid performing the stock g
* Reference issues and pull requests liberally.
* Use the GitHub magic words "Fixed/Fixes/Fix, Resolved/Resolves/Resolve, Closed/Closes/Close", as in, "Closes #1928", as this will automatically close that issue when the PR is merged if it is a fix for that issue.
+### Early porting
+
+* You may earlyport.
+* Follow standard chompcomments incase upstream ends up closing their PR for any reason.
+* If it does get merged upstream and the mirror appears on our repo, you are responsible for unfucking the comments situation, because it'll have to say VORE edits instead of CHOMP edits.
+
## Licensing
CHOMPStation is licensed under the GNU Affero General Public License version 3, which can be found in full in LICENSE-AGPL3.txt.
diff --git a/.github/ISSUE_TEMPLATE/map_report.md b/.github/ISSUE_TEMPLATE/map_report.md
new file mode 100644
index 0000000000..a3aa174357
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/map_report.md
@@ -0,0 +1,29 @@
+---
+name: Map Bug report
+about: Create a report, specific to any map related things.
+title: '[MAPPING] '
+labels: ['Type: Bug', 'Type: Map']
+assignees: ''
+
+---
+
+
+
+
+
+
+#### Brief description of the bug
+
+
+#### What you expected to happen
+
+
+#### What actually happened
+
+
+#### Code Revision
+- (Found using the "Show Server Revision" verb under the OOC tab.)
+
+
+#### Anything else you may wish to add:
+- (Location if it's a mapping issue, screenshots, sprites, etc.)
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..9d69be5ecb
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+version: 2
+
+updates:
+ - package-ecosystem: github-actions
+ directory: "/"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: npm
+ directory: "/tools"
+ schedule:
+ interval: "daily"
diff --git a/.github/workflows/autochangelog.yml b/.github/workflows/autochangelog.yml
index 71a53a5b2d..cb6ecabe46 100644
--- a/.github/workflows/autochangelog.yml
+++ b/.github/workflows/autochangelog.yml
@@ -1,43 +1,43 @@
name: Autochangelog
-on:
- pull_request_target:
- types: closed
- branches:
- - master
-
+on:
+ pull_request_target:
+ types: closed
+ branches:
+ - master
+
env:
- BASENAME: "polaris"
+ BASENAME: "vorestation"
jobs:
- autochangelog:
- name: Autochangelog
- runs-on: ubuntu-20.04
- if: github.event.pull_request.merged == true
- steps:
- - uses: /actions/checkout@v2
- with:
- ref: master
- - name: Update repository to master
- run: git pull "origin" master
- - name: Ensure +x on CI directory
- run: |
- chmod -R +x ./tools/ci
- - uses: actions/setup-python@v2
- with:
- python-version: '3.7'
- - name: Generate Changelog
- run: |
- pip install pyyaml
- python tools/GenerateChangelog/ss13_autochangelog.py \
- html/changelogs \
- ${{ github.event.pull_request.number }} \
- "${{ github.event.pull_request.user.login }}" \
- "${{ github.event.pull_request.body }}"
- python tools/GenerateChangelog/ss13_genchangelog.py \
- html/changelog.html \
- html/changelogs
- - uses: stefanzweifel/git-auto-commit-action@v4
- with:
- commit_message: Automatic changelog generation for ${{ github.events.pull_request.number }}
- branch: ${{ github.events.pull_request.base }}
- commit_user_name: Autochangelog Bot
+ autochangelog:
+ name: Autochangelog
+ runs-on: ubuntu-latest
+ if: github.event.pull_request.merged == true
+ steps:
+ - uses: /actions/checkout@v3
+ with:
+ ref: master
+ - name: Update repository to master
+ run: git pull "origin" master
+ - name: Ensure +x on CI directory
+ run: |
+ chmod -R +x ./tools/ci
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.7'
+ - name: Generate Changelog
+ run: |
+ pip install pyyaml
+ python tools/GenerateChangelog/ss13_autochangelog.py \
+ html/changelogs \
+ ${{ github.event.pull_request.number }} \
+ "${{ github.event.pull_request.user.login }}" \
+ "${{ github.event.pull_request.body }}"
+ python tools/GenerateChangelog/ss13_genchangelog.py \
+ html/changelog.html \
+ html/changelogs
+ - uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ commit_message: Automatic changelog generation for ${{ github.events.pull_request.number }}
+ branch: ${{ github.events.pull_request.base }}
+ commit_user_name: Autochangelog Bot
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 13bddb2a37..c531d1ffd9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,58 +10,68 @@ env:
jobs:
file_tests:
name: Run Linters
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Ensure +x on CI directory
run: |
chmod -R +x ./tools/ci
- name: Install Tools
run: |
bash tools/ci/install_build_deps.sh
+ - name: Restore Yarn cache
+ if: "${{ contains(github.event.pull_request.labels.*.name, 'Type: TGUI Bundle') }}"
+ uses: actions/cache@v3
+ with:
+ path: tgui/.yarn/cache
+ key: ${{ runner.os }}-yarn-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('tgui/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}-
+ ${{ runner.os }}-build-
+ ${{ runner.os }}-
- name: Run Tests
run: |
tools/ci/validate_files.sh
tools/ci/build_tgui.sh
-# dreamchecker:
-# name: DreamChecker
-# runs-on: ubuntu-20.04
-# steps:
-# - uses: actions/checkout@v2
-#
-# - name: Cache SpacemanDMM
-# uses: actions/cache@v2
-# with:
-# path: ~/SpacemanDMM
-# key: ${{ runner.os }}-dreamchecker-${{ hashFiles('dependencies.sh')}}
-# restore-keys: ${{ runner.os }}-dreamchecker
-#
-# - name: Install Dependencies
-# run: |
-# tools/ci/install_spaceman_dmm.sh dreamchecker
-#
-# - name: Run Linter
-# id: linter
-# run: |
-# ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1
-#
-# - name: Annotate Linter
-# uses: yogstation13/DreamAnnotate@v1
-# if: always()
-# with:
-# outputFile: output-annotations.txt
+ dreamchecker:
+ name: DreamChecker
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Cache SpacemanDMM
+ uses: actions/cache@v3
+ with:
+ path: ~/SpacemanDMM
+ key: ${{ runner.os }}-dreamchecker-${{ hashFiles('dependencies.sh')}}
+ restore-keys: ${{ runner.os }}-dreamchecker
+
+ - name: Install Dependencies
+ run: |
+ tools/ci/install_spaceman_dmm.sh dreamchecker
+
+ - name: Run Linter
+ id: linter
+ run: |
+ ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1
+
+ - name: Annotate Linter
+ uses: yogstation13/DreamAnnotate@v1
+ if: always()
+ with:
+ outputFile: output-annotations.txt
unit_tests:
name: Integration Tests
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Ensure +x on CI directory
run: |
chmod -R +x ./tools/ci
- name: Setup Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: $HOME/BYOND
key: ${{ runner.os }}-byond
@@ -79,7 +89,7 @@ jobs:
TEST_DEFINE: "UNIT_TEST"
TEST_FILE: "code/_unit_tests.dm"
RUN: "1"
- - name: Compile POIs (no run)
+ - name: Compile POIs
run: |
tools/ci/install_byond.sh
tools/ci/compile_and_run.sh
@@ -87,7 +97,7 @@ jobs:
TEST_DEFINE: "MAP_TEST"
TEST_FILE: "code/_map_tests.dm"
RUN: "0"
- - name: Compile away missions (no run)
+ - name: Compile away missions
run: |
tools/ci/install_byond.sh
tools/ci/compile_and_run.sh
diff --git a/.github/workflows/render_nanomaps.yml b/.github/workflows/render_nanomaps.yml
index fd5536ea48..57f305772c 100644
--- a/.github/workflows/render_nanomaps.yml
+++ b/.github/workflows/render_nanomaps.yml
@@ -14,10 +14,10 @@ on:
jobs:
generate_maps:
name: 'Generate NanoMaps'
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Clone
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Branch
run: |
diff --git a/.gitignore b/.gitignore
index 04e3bdf8d7..282f3eabf8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,31 +22,10 @@ cfg/
!/.vscode/settings.json
!/.vscode/tasks.json
-ch-merge-upstream-pull-request.sh
code/game/gamemodes/technomancer/spells/projectile/overload.dm
code/game/gamemodes/technomancer/spells/projectile/overload.dm
code/modules/client/preference_setup/loadout/loadout_xeno.dm
temp.dmi
-/maps/RandomZLevels/backup/blackmarketpackers.dmm
-/maps/backup/virgo-1.dmm
-/maps/backup/virgo-2.dmm
-/tools/midi2piano/.vs/midi2piano/v14/.suo
-/tools/midi2piano/midi2piano/bin/x86/Debug/Sanford.Multimedia.Midi.dll
-/tools/midi2piano/midi2piano/bin/x86/Debug/midi2piano.exe
-/tools/midi2piano/midi2piano/bin/x86/Debug/midi2piano.pdb
-/tools/midi2piano/midi2piano/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache
-/tools/midi2piano/midi2piano/obj/x86/Debug/midi2piano.Form1.resources
-/tools/midi2piano/midi2piano/obj/x86/Debug/midi2piano.csproj.FileListAbsolute.txt
-/tools/midi2piano/midi2piano/obj/x86/Debug/midi2piano.csproj.GenerateResource.Cache
-/tools/midi2piano/midi2piano/obj/x86/Debug/midi2piano.csprojResolveAssemblyReference.cache
-/tools/midi2piano/midi2piano/obj/x86/Debug/midi2piano.exe
-/tools/midi2piano/midi2piano/obj/x86/Debug/midi2piano.pdb
-/maps/backup
-/maps/original
-/maps/RandomZLevels/backup
-/tools/midi2piano.zip
-/maps/yw/backup
-icons/mecha/mecha_ch.dmi
-
-.vscode/settings.json
+node_modules/
+package-lock.json
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 19a0ceb7de..4b96db2f5a 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -9,6 +9,7 @@
"dbaeumer.vscode-eslint",
"editorconfig.editorconfig",
"donkie.vscode-tgstation-test-adapter",
- "icrawl.discord-vscode"
+ "icrawl.discord-vscode",
+ "esbenp.prettier-vscode"
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 64cfc2bb26..8e110ef9bd 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,8 +1,7 @@
{
"eslint.nodePath": "./tgui/.yarn/sdks",
- "eslint.workingDirectories": [
- "./tgui"
- ],
+ "eslint.workingDirectories": ["./tgui"],
+ "prettier.prettierPath": "./tgui/.yarn/sdks/prettier/index.js",
"typescript.tsdk": "./tgui/.yarn/sdks/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"search.exclude": {
@@ -13,24 +12,63 @@
"*.dmi": "imagePreview.previewEditor"
},
"files.eol": "\n",
+ "files.encoding": "utf8",
+ "files.insertFinalNewline": true,
+ "files.trimFinalNewlines": true,
+ "files.trimTrailingWhitespace": true,
+ "files.associations": {
+ "*.{dme,dmf,dmm,dm}": "dm",
+ },
"gitlens.advanced.blame.customArguments": [
- "-w"
+ "-w", "--ignore-revs-file", ".git-blame-ignore-revs"
],
"tgstationTestExplorer.project.resultsType": "json",
+ "[dm]": {
+ "files.eol": "\r\n",
+ "editor.detectIndentation": false,
+ "editor.insertSpaces": false
+ },
+ "[markdown]": {
+ "files.trimTrailingWhitespace": false
+ },
+ "[python]": {
+ "editor.detectIndentation": false,
+ "editor.insertSpaces": true,
+ "editor.tabSize": 4
+ },
+ "[yaml]": {
+ "editor.detectIndentation": false,
+ "editor.insertSpaces": true,
+ "editor.tabSize": 2
+ },
"[javascript]": {
- "editor.rulers": [
- 120
- ]
+ "editor.rulers": [120],
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true
+ },
+ "[javascriptreact]": {
+ "editor.rulers": [120],
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true
},
"[typescript]": {
- "editor.rulers": [
- 120
- ]
+ "editor.rulers": [120],
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true
+ },
+ "[typescriptreact]": {
+ "editor.rulers": [120],
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true
},
"[scss]": {
- "editor.rulers": [
- 120
- ]
+ "editor.rulers": [120],
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true
},
+ "debug.onTaskErrors": "abort",
+ "dreammaker.objectTreePane": true,
+ "dreammaker.autoUpdate": true,
+ "dreammaker.tickOnCreate": true,
"tgstationTestExplorer.project.DMEName": "tgmc.dme"
-}
\ No newline at end of file
+}
diff --git a/code/__defines/belly_modes_ch.dm b/code/__defines/belly_modes_ch.dm
index e4b04aa87a..e1bb06b753 100644
--- a/code/__defines/belly_modes_ch.dm
+++ b/code/__defines/belly_modes_ch.dm
@@ -7,3 +7,8 @@
#define DM_FLAG_REAGENTSDIGEST 0x2
#define DM_FLAG_REAGENTSABSORB 0x4
#define DM_FLAG_REAGENTSDRAIN 0x8
+
+//Vore Sprite Flags
+#define DM_FLAG_VORESPRITE_BELLY 0x1
+#define DM_FLAG_VORESPRITE_TAIL 0x2
+#define DM_FLAG_VORESPRITE_MARKING 0x4
\ No newline at end of file
diff --git a/code/__defines/belly_modes_vr.dm b/code/__defines/belly_modes_vr.dm
index 2d5ba3e308..2d8f714fc4 100644
--- a/code/__defines/belly_modes_vr.dm
+++ b/code/__defines/belly_modes_vr.dm
@@ -1,4 +1,5 @@
// Normal digestion modes
+#define DM_DEFAULT "Default" // Not a real bellymode, used for handling on 'selective' bellymode prefs.
#define DM_HOLD "Hold"
#define DM_HOLD_ABSORBED "Hold Absorbed" // Not a real bellymode, used for handling different idle messages for absorbed prey.
#define DM_DIGEST "Digest"
@@ -10,6 +11,7 @@
#define DM_SIZE_STEAL "Size Steal"
#define DM_HEAL "Heal"
#define DM_EGG "Encase In Egg"
+#define DM_SELECT "Selective"
//Addon mode flags
#define DM_FLAG_NUMBING 0x1
diff --git a/code/__defines/machinery.dm b/code/__defines/machinery.dm
index 8a27e7c4c4..9d882883a4 100644
--- a/code/__defines/machinery.dm
+++ b/code/__defines/machinery.dm
@@ -79,7 +79,6 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define NETWORK_ALARM_FIRE "Fire Alarms"
#define NETWORK_TALON_HELMETS "TalonHelmets" //VOREStation Add
#define NETWORK_TALON_SHIP "TalonShip" //VOREStation Add
-#define NETWORK_EXPLORATION "Exploration"
// Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them.
var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret", NETWORK_COMMUNICATORS, NETWORK_EXPLORATION)
@@ -174,3 +173,17 @@ if (!(DATUM.datum_flags & DF_ISPROCESSING)) {\
#define LOGIN_TYPE_NORMAL 1
#define LOGIN_TYPE_AI 2
#define LOGIN_TYPE_ROBOT 3
+
+// Computer Hardware
+#define PART_CPU /obj/item/weapon/computer_hardware/processor_unit // CPU. Without it the computer won't run. Better CPUs can run more programs at once.
+#define PART_NETWORK /obj/item/weapon/computer_hardware/network_card // Network Card component of this computer. Allows connection to NTNet
+#define PART_HDD /obj/item/weapon/computer_hardware/hard_drive // Hard Drive component of this computer. Stores programs and files.
+
+// Optional hardware (improves functionality, but is not critical for computer to work in most cases)
+#define PART_BATTERY /obj/item/weapon/computer_hardware/battery_module // An internal power source for this computer. Can be recharged.
+#define PART_CARD /obj/item/weapon/computer_hardware/card_slot // ID Card slot component of this computer. Mostly for HoP modification console that needs ID slot for modification.
+#define PART_PRINTER /obj/item/weapon/computer_hardware/nano_printer // Nano Printer component of this computer, for your everyday paperwork needs.
+//#define PART_DRIVE /obj/item/weapon/computer_hardware/hard_drive/portable // Portable data storage
+//#define PART_AI /obj/item/weapon/computer_hardware/ai_slot // AI slot, an intellicard housing that allows modifications of AIs.
+#define PART_TESLA /obj/item/weapon/computer_hardware/tesla_link // Tesla Link, Allows remote charging from nearest APC.
+//#define PART_SCANNER /obj/item/weapon/computer_hardware/scanner // One of several optional scanner attachments.
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index db25cb850e..fb0e4ecd51 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -149,10 +149,25 @@
#define PROGRAM_STATE_BACKGROUND 1
#define PROGRAM_STATE_ACTIVE 2
+#define PROG_MISC "Miscellaneous"
+#define PROG_ENG "Engineering"
+#define PROG_OFFICE "Office Work"
+#define PROG_COMMAND "Command"
+#define PROG_SUPPLY "Supply and Shuttles"
+#define PROG_ADMIN "NTNet Administration"
+#define PROG_UTIL "Utility"
+#define PROG_SEC "Security"
+#define PROG_MONITOR "Monitoring"
+
// Caps for NTNet logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it.
#define MAX_NTNET_LOGS 500
#define MIN_NTNET_LOGS 10
+//Built-in email accounts
+#define EMAIL_DOCUMENTS "document.server@virgo.local"
+#define EMAIL_SYSADMIN "admin@virgo.local"
+#define EMAIL_BROADCAST "broadcast@virgo.local"
+
// Special return values from bullet_act(). Positive return values are already used to indicate the blocked level of the projectile.
#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act()
diff --git a/code/__defines/misc_vr.dm b/code/__defines/misc_vr.dm
index 9a9d7ba3f4..4d1aba706e 100644
--- a/code/__defines/misc_vr.dm
+++ b/code/__defines/misc_vr.dm
@@ -58,6 +58,7 @@
#define PTO_CARGO "Cargo"
#define PTO_CIVILIAN "Civilian"
#define PTO_CYBORG "Cyborg"
+#define PTO_TALON "Talon Contractor"
#define DEPARTMENT_TALON "ITV Talon"
diff --git a/code/__defines/mobs_vr.dm b/code/__defines/mobs_vr.dm
index be17f09c39..51c65f532b 100644
--- a/code/__defines/mobs_vr.dm
+++ b/code/__defines/mobs_vr.dm
@@ -25,6 +25,7 @@
#define SPECIES_PROTEAN "Protean"
#define SPECIES_RAPALA "Rapala"
#define SPECIES_SERGAL "Sergal"
+#define SPECIES_ALTEVIAN "Altevian"
#define SPECIES_SHADEKIN_CREW "Black-Eyed Shadekin"
#define SPECIES_VASILISSAN "Vasilissan"
#define SPECIES_VULPKANIN "Vulpkanin"
diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm
index f81e48b044..b133acc9ec 100644
--- a/code/__defines/species_languages.dm
+++ b/code/__defines/species_languages.dm
@@ -86,18 +86,15 @@
#define LANGUAGE_ROOTLOCAL "Local Rootspeak"
#define LANGUAGE_ROOTGLOBAL "Global Rootspeak"
#define LANGUAGE_CULT "Cult"
-#define LANGUAGE_OCCULT "Occult"
#define LANGUAGE_CHANGELING "Changeling"
#define LANGUAGE_VOX "Vox-Pidgin"
#define LANGUAGE_TERMINUS "Terminus"
-#define LANGUAGE_SKRELLIANFAR "High Skrellian"
#define LANGUAGE_MINBUS "Minbus"
#define LANGUAGE_EVENT1 "Occursus"
#define LANGUAGE_AKHANI "Akhani"
#define LANGUAGE_ALAI "Alai"
#define LANGUAGE_ZADDAT "Vedahq"
#define LANGUAGE_PROMETHEAN "Promethean Biolinguistics"
-#define LANGUAGE_BLOB "Chemosense Transmission"
#define LANGUAGE_GIBBERISH "Babel"
// Language flags.
diff --git a/code/__defines/species_languages_vr.dm b/code/__defines/species_languages_vr.dm
index 1a5fbdab4c..b8f3ed3429 100644
--- a/code/__defines/species_languages_vr.dm
+++ b/code/__defines/species_languages_vr.dm
@@ -1,7 +1,7 @@
#define SPECIES_WHITELIST_SELECTABLE 0x20 // Can select and customize, but not join as
#define LANGUAGE_DRUDAKAR "D'Rudak'Ar"
-#define LANGUAGE_SLAVIC "Pan-Slavic"
+#define LANGUAGE_SLAVIC "Pan-Slavic" //CHOMP reAdd
#define LANGUAGE_BIRDSONG "Birdsong"
#define LANGUAGE_SAGARU "Sagaru"
#define LANGUAGE_CANILUNZT "Canilunzt"
@@ -10,13 +10,9 @@
#define LANGUAGE_ENOCHIAN "Enochian"
#define LANGUAGE_VESPINAE "Vespinae"
#define LANGUAGE_SPACER "Spacer"
-#define LANGUAGE_CLOWNISH "Coulrian"
#define LANGUAGE_TAVAN "Tavan"
#define LANGUAGE_ECHOSONG "Echo Song"
-#define LANGUAGE_CHIMPANZEE "Chimpanzee"
-#define LANGUAGE_NEAERA "Neaera"
-#define LANGUAGE_STOK "Stok"
-#define LANGUAGE_FARWA "Farwa"
+#define LANGUAGE_ANIMAL "Animal"
#define LANGUAGE_SHADEKIN "Shadekin Empathy"
diff --git a/code/__defines/sprite_sheets.dm b/code/__defines/sprite_sheets.dm
index 603bb82d5f..2194efca23 100644
--- a/code/__defines/sprite_sheets.dm
+++ b/code/__defines/sprite_sheets.dm
@@ -11,7 +11,8 @@ SPECIES_SERGAL = 'icons/inventory/suit/mob_vr_sergal.dmi',\
SPECIES_NEVREAN = 'icons/inventory/suit/mob_vr_sergal.dmi',\
SPECIES_VULPKANIN = 'icons/inventory/suit/mob_vr_vulpkanin.dmi',\
SPECIES_ZORREN_HIGH = 'icons/inventory/suit/mob_vr_vulpkanin.dmi',\
-SPECIES_FENNEC = 'icons/inventory/suit/mob_vr_vulpkanin.dmi')
+SPECIES_FENNEC = 'icons/inventory/suit/mob_vr_vulpkanin.dmi',\
+SPECIES_ALTEVIAN = 'icons/inventory/suit/mob_vr_altevian.dmi')
#define VR_SPECIES_SPRITE_SHEETS_HEAD_MOB list(\
SPECIES_HUMAN = 'icons/inventory/head/mob.dmi',\
SPECIES_TAJ = 'icons/inventory/head/mob_tajaran.dmi',\
@@ -24,7 +25,8 @@ SPECIES_SERGAL = 'icons/inventory/head/mob_vr_sergal.dmi',\
SPECIES_NEVREAN = 'icons/inventory/head/mob_vr_sergal.dmi',\
SPECIES_VULPKANIN = 'icons/inventory/head/mob_vr_vulpkanin.dmi',\
SPECIES_ZORREN_HIGH = 'icons/inventory/head/mob_vr_vulpkanin.dmi',\
-SPECIES_FENNEC = 'icons/inventory/head/mob_vr_vulpkanin.dmi')
+SPECIES_FENNEC = 'icons/inventory/head/mob_vr_vulpkanin.dmi',\
+SPECIES_ALTEVIAN = 'icons/inventory/head/mob_vr_altevian.dmi')
#define VR_SPECIES_SPRITE_SHEETS_HANDS_MOB list(\
SPECIES_HUMAN = 'icons/inventory/hands/mob.dmi',\
SPECIES_TAJ = 'icons/inventory/hands/mob_tajaran.dmi',\
@@ -64,7 +66,8 @@ SPECIES_SERGAL = 'icons/inventory/suit/item_vr_sergal.dmi',\
SPECIES_NEVREAN = 'icons/inventory/suit/item_vr_sergal.dmi',\
SPECIES_VULPKANIN = 'icons/inventory/suit/item_vr_vulpkanin.dmi',\
SPECIES_ZORREN_HIGH = 'icons/inventory/suit/item_vr_vulpkanin.dmi',\
-SPECIES_FENNEC = 'icons/inventory/suit/item_vr_vulpkanin.dmi')
+SPECIES_FENNEC = 'icons/inventory/suit/item_vr_vulpkanin.dmi',\
+SPECIES_ALTEVIAN = 'icons/inventory/suit/item_vr_altevian.dmi')
#define VR_SPECIES_SPRITE_SHEETS_HEAD_ITEM list(\
SPECIES_HUMAN = 'icons/inventory/head/item.dmi',\
SPECIES_TAJ = 'icons/inventory/head/item_tajaran.dmi',\
@@ -77,7 +80,8 @@ SPECIES_SERGAL = 'icons/inventory/head/item_vr_sergal.dmi',\
SPECIES_NEVREAN = 'icons/inventory/head/item_vr_sergal.dmi',\
SPECIES_VULPKANIN = 'icons/inventory/head/item_vr_vulpkanin.dmi',\
SPECIES_ZORREN_HIGH = 'icons/inventory/head/item_vr_vulpkanin.dmi',\
-SPECIES_FENNEC = 'icons/inventory/head/item_vr_vulpkanin.dmi')
+SPECIES_FENNEC = 'icons/inventory/head/item_vr_vulpkanin.dmi',\
+SPECIES_ALTEVIAN = 'icons/inventory/head/item_vr_altevian.dmi')
#define VR_SPECIES_SPRITE_SHEETS_HANDS_ITEM list(\
SPECIES_HUMAN = 'icons/inventory/hands/item.dmi',\
SPECIES_TAJ = 'icons/inventory/hands/item_tajaran.dmi',\
@@ -118,7 +122,8 @@ SPECIES_SERGAL = 'icons/inventory/suit/mob_vr_sergal.dmi',\
SPECIES_NEVREAN = 'icons/inventory/suit/mob_vr_sergal.dmi',\
SPECIES_VULPKANIN = 'icons/inventory/suit/mob_vr_vulpkanin.dmi',\
SPECIES_ZORREN_HIGH = 'icons/inventory/suit/mob_vr_vulpkanin.dmi',\
-SPECIES_FENNEC = 'icons/inventory/suit/mob_vr_vulpkanin.dmi')
+SPECIES_FENNEC = 'icons/inventory/suit/mob_vr_vulpkanin.dmi',\
+SPECIES_ALTEVIAN = 'icons/inventory/suit/mob_vr_altevian.dmi')
#define ALL_VR_SPRITE_SHEETS_HEAD_MOB list(\
SPECIES_HUMAN = 'icons/inventory/head/mob_vr.dmi',\
SPECIES_TAJ = 'icons/inventory/head/mob_vr_tajaran.dmi',\
@@ -131,7 +136,8 @@ SPECIES_SERGAL = 'icons/inventory/head/mob_vr_sergal.dmi',\
SPECIES_NEVREAN = 'icons/inventory/head/mob_vr_sergal.dmi',\
SPECIES_VULPKANIN = 'icons/inventory/head/mob_vr_vulpkanin.dmi',\
SPECIES_ZORREN_HIGH = 'icons/inventory/head/mob_vr_vulpkanin.dmi',\
-SPECIES_FENNEC = 'icons/inventory/head/mob_vr_vulpkanin.dmi')
+SPECIES_FENNEC = 'icons/inventory/head/mob_vr_vulpkanin.dmi',\
+SPECIES_ALTEVIAN = 'icons/inventory/head/mob_vr_altevian.dmi')
#define ALL_VR_SPRITE_SHEETS_HANDS_MOB list(\
SPECIES_HUMAN = 'icons/inventory/hands/mob_vr.dmi',\
SPECIES_TAJ = 'icons/inventory/hands/mob_vr_tajaran.dmi',\
@@ -171,7 +177,8 @@ SPECIES_SERGAL = 'icons/inventory/suit/item_vr_sergal.dmi',\
SPECIES_NEVREAN = 'icons/inventory/suit/item_vr_sergal.dmi',\
SPECIES_VULPKANIN = 'icons/inventory/suit/item_vr_vulpkanin.dmi',\
SPECIES_ZORREN_HIGH = 'icons/inventory/suit/item_vr_vulpkanin.dmi',\
-SPECIES_FENNEC = 'icons/inventory/suit/item_vr_vulpkanin.dmi')
+SPECIES_FENNEC = 'icons/inventory/suit/item_vr_vulpkanin.dmi',\
+SPECIES_ALTEVIAN = 'icons/inventory/suit/item_vr_altevian.dmi')
#define ALL_VR_SPRITE_SHEETS_HEAD_ITEM list(\
SPECIES_HUMAN = 'icons/inventory/head/item_vr.dmi',\
SPECIES_TAJ = 'icons/inventory/head/item_vr_tajaran.dmi',\
@@ -184,7 +191,8 @@ SPECIES_SERGAL = 'icons/inventory/head/item_vr_sergal.dmi',\
SPECIES_NEVREAN = 'icons/inventory/head/item_vr_sergal.dmi',\
SPECIES_VULPKANIN = 'icons/inventory/head/item_vr_vulpkanin.dmi',\
SPECIES_ZORREN_HIGH = 'icons/inventory/head/item_vr_vulpkanin.dmi',\
-SPECIES_FENNEC = 'icons/inventory/head/item_vr_vulpkanin.dmi')
+SPECIES_FENNEC = 'icons/inventory/head/item_vr_vulpkanin.dmi',\
+SPECIES_ALTEVIAN = 'icons/inventory/head/item_vr_altevian.dmi')
#define ALL_VR_SPRITE_SHEETS_HANDS_ITEM list(\
SPECIES_HUMAN = 'icons/inventory/hands/item_vr.dmi',\
SPECIES_TAJ = 'icons/inventory/hands/item_vr_tajaran.dmi',\
diff --git a/code/_helpers/_lists.dm b/code/_helpers/_lists.dm
index c359227f05..5631fa8807 100644
--- a/code/_helpers/_lists.dm
+++ b/code/_helpers/_lists.dm
@@ -53,7 +53,7 @@
// atoms/items/objects can be pretty and whatnot
var/atom/A = item
if(output_icons && isicon(A.icon) && !ismob(A)) // mobs tend to have unusable icons
- item_str += "[bicon(A)] "
+ item_str += "\icon[A][bicon(A)] "
switch(determiners)
if(DET_NONE) item_str += A.name
if(DET_DEFINITE) item_str += "\the [A]"
@@ -217,6 +217,17 @@ This actually tests if they have the same entries and values.
return 0
return 1
+/*
+Checks if a list has the same entries and values as an element of big.
+*/
+/proc/in_as_list(var/list/little, var/list/big)
+ if(!islist(big))
+ return 0
+ for(var/element in big)
+ if(same_entries(little, element))
+ return 1
+ return 0
+
/*
* Returns list containing entries that are in either list but not both.
* If skipref = 1, repeated elements are treated as one.
@@ -870,4 +881,3 @@ var/global/list/json_cache = list()
else
used_key_list[input_key] = 1
return input_key
-
\ No newline at end of file
diff --git a/code/_helpers/global_lists_vr.dm b/code/_helpers/global_lists_vr.dm
index 8088eaa5e1..94bfbbc232 100644
--- a/code/_helpers/global_lists_vr.dm
+++ b/code/_helpers/global_lists_vr.dm
@@ -5,8 +5,10 @@
var/global/list/hair_accesories_list= list()// Stores /datum/sprite_accessory/hair_accessory indexed by type
var/global/list/negative_traits = list() // Negative custom species traits, indexed by path
var/global/list/neutral_traits = list() // Neutral custom species traits, indexed by path
-var/global/list/everyone_traits = list() // Neutral traits available to all species, indexed by path
var/global/list/positive_traits = list() // Positive custom species traits, indexed by path
+var/global/list/everyone_traits_positive = list() // Neutral traits available to all species, indexed by path
+var/global/list/everyone_traits_neutral = list() // Neutral traits available to all species, indexed by path
+var/global/list/everyone_traits_negative = list() // Neutral traits available to all species, indexed by path
var/global/list/traits_costs = list() // Just path = cost list, saves time in char setup
var/global/list/all_traits = list() // All of 'em at once (same instances)
var/global/list/active_ghost_pods = list()
@@ -63,6 +65,7 @@ var/global/list/classic_vore_sounds = list(
"Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg',
"Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg',
"Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg',
+ "Zipper" = 'sound/items/zip.ogg',
"None" = null)
var/global/list/classic_release_sounds = list(
@@ -71,6 +74,7 @@ var/global/list/classic_release_sounds = list(
"Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg',
"Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg',
"Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg',
+ "Zipper" = 'sound/items/zip.ogg',
"Splatter" = 'sound/effects/splat.ogg',
"None" = null
)
@@ -93,6 +97,7 @@ var/global/list/fancy_vore_sounds = list(
"Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg',
"Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg',
"Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg',
+ "Zipper" = 'sound/items/zip.ogg',
"None" = null
)
@@ -102,6 +107,7 @@ var/global/list/fancy_release_sounds = list(
"Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg',
"Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg',
"Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg',
+ "Zipper" = 'sound/items/zip.ogg',
"Stomach Move" = 'sound/vore/sunesound/pred/stomachmove.ogg',
"Pred Escape" = 'sound/vore/sunesound/pred/escape.ogg',
"Splatter" = 'sound/effects/splat.ogg',
@@ -254,7 +260,8 @@ var/global/list/edible_trash = list(/obj/item/broken_device,
/obj/item/weapon/folder,
/obj/item/weapon/clipboard,
/obj/item/weapon/coin,
- /obj/item/clothing/ears //chompstation addition end
+ /obj/item/clothing/ears, //chompstation addition end
+ //CHOMPedit: disabled because this is in a file we don't use /obj/item/roulette_ball
)
var/global/list/contamination_flavors = list(
@@ -563,12 +570,16 @@ var/global/list/remainless_species = list(SPECIES_PROMETHEAN,
switch(category)
if(-INFINITY to -0.1)
negative_traits[traitpath] = T
+ if(!(T.custom_only))
+ everyone_traits_negative[traitpath] = T
if(0)
neutral_traits[traitpath] = T
if(!(T.custom_only))
- everyone_traits[traitpath] = T
+ everyone_traits_neutral[traitpath] = T
if(0.1 to INFINITY)
positive_traits[traitpath] = T
+ if(!(T.custom_only))
+ everyone_traits_positive[traitpath] = T
// Weaver recipe stuff
@@ -838,4 +849,4 @@ var/global/list/xenobio_rainbow_extracts = list(
/obj/item/slime_extract/ruby = 3,
/obj/item/slime_extract/emerald = 3,
/obj/item/slime_extract/light_pink = 1,
- /obj/item/slime_extract/rainbow = 1)
\ No newline at end of file
+ /obj/item/slime_extract/rainbow = 1)
diff --git a/code/_helpers/sanitize_values.dm b/code/_helpers/sanitize_values.dm
index 4b521f9bfb..3d04200269 100644
--- a/code/_helpers/sanitize_values.dm
+++ b/code/_helpers/sanitize_values.dm
@@ -6,6 +6,16 @@
return number
return default
+// Checks if the given input is a valid list index; returns true/false and doesn't change anything.
+/proc/is_valid_index(input, list/given_list)
+ if(!isnum(input))
+ return FALSE
+ if(input != round(input))
+ return FALSE
+ if(input < 1 || input > length(given_list))
+ return FALSE
+ return TRUE
+
/proc/sanitize_text(text, default="")
if(istext(text))
return text
@@ -44,3 +54,60 @@
if(65 to 70) . += ascii2text(ascii+32) //letters A to F - translates to lowercase
else return default
return .
+
+//Valid format codes: YY, YEAR, MM, DD, hh, mm, ss, :, -. " " (space). Invalid format will return default.
+/proc/sanitize_time(time, default, format = "hh:mm")
+ if(!istext(time) || !(length(time) == length(format)))
+ return default
+ var/fragment = ""
+ . = list()
+ for(var/i = 1, i <= length(format), i++)
+ fragment += copytext(format,i,i+1)
+ if(fragment in list("YY", "YEAR", "MM", "DD", "hh", "mm", "ss"))
+ . += sanitize_one_time(copytext(time, i - length(fragment) + 1, i + 1), copytext(default, i - length(fragment) + 1, i + 1), fragment)
+ fragment = ""
+ else if(fragment in list(":", "-", " "))
+ . += fragment
+ fragment = ""
+ if(fragment)
+ return default //This means the format was improper.
+ return JOINTEXT(.)
+
+//Internal proc, expects valid format and text input of equal length to format.
+/proc/sanitize_one_time(input, default, format)
+ var/list/ainput = list()
+ for(var/i = 1, i <= length(input), i++)
+ ainput += text2ascii(input, i)
+ switch(format)
+ if("YY")
+ if(!(ainput[1] in 48 to 57) || !(ainput[2] in 48 to 57))//0 to 9
+ return (default || "00")
+ return input
+ if("YEAR")
+ for(var/i = 1, i <= 4, i++)
+ if(!(ainput[i] in 48 to 57))//0 to 9
+ return (default || "0000")
+ return input
+ if("MM")
+ var/early = (ainput[1] == 48) && (ainput[2] in 49 to 57) //01 to 09
+ var/late = (ainput[1] == 49) && (ainput[2] in 48 to 50) //10 to 12
+ if(!(early || late))
+ return (default || "01")
+ return input
+ if("DD")
+ var/early = (ainput[1] == 48) && (ainput[2] in 49 to 57) //01 to 09
+ var/mid = (ainput[1] in 49 to 50) && (ainput[2] in 48 to 57) //10 to 29
+ var/late = (ainput[1] == 51) && (ainput[2] in 48 to 49) //30 to 31
+ if(!(early || mid || late))
+ return (default || "01")
+ return input
+ if("hh")
+ var/early = (ainput[1] in 48 to 49) && (ainput[2] in 48 to 57) //00 to 19
+ var/late = (ainput[1] == 50) && (ainput[2] in 48 to 51) //20 to 23
+ if(!(early || late))
+ return (default || "00")
+ return input
+ if("mm", "ss")
+ if(!(ainput[1] in 48 to 53) || !(ainput[2] in 48 to 57)) //0 to 5, 0 to 9
+ return (default || "00")
+ return input
diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm
index 85ec20087f..e2bc37d93c 100644
--- a/code/_helpers/text.dm
+++ b/code/_helpers/text.dm
@@ -345,8 +345,15 @@
if(!text_tag_cache[tagname])
var/icon/tag = icon(text_tag_icons, tagname)
text_tag_cache[tagname] = bicon(tag, TRUE, "text_tag")
+ if(C.chatOutput.broken)
+ return ""
return text_tag_cache[tagname]
+/proc/create_text_tag_old(var/tagname, var/tagdesc = tagname, var/client/C = null)
+ if(!(C && C.is_preference_enabled(/datum/client_preference/chat_tags)))
+ return tagdesc
+ return "
"
+
/proc/contains_az09(var/input)
for(var/i=1, i<=length(input), i++)
var/ascii_char = text2ascii(input,i)
@@ -410,6 +417,58 @@
t = replacetext(t, "\[editorbr\]", "")
return t
+//pencode translation to html for tags exclusive to digital files (currently email, nanoword, report editor fields,
+//modular scanner data and txt file printing) and prints from them
+/proc/digitalPencode2html(var/text)
+ text = replacetext(text, "\[pre\]", "
") + text = replacetext(text, "\[/pre\]", "") + text = replacetext(text, "\[fontred\]", "") // to pass html tag integrity unit test + text = replacetext(text, "\[fontblue\]", "")// to pass html tag integrity unit test + text = replacetext(text, "\[fontgreen\]", "") + text = replacetext(text, "\[/font\]", "") + text = replacetext(text, "\[redacted\]", "R E D A C T E D") + return pencode2html(text) + +//Will kill most formatting; not recommended. +/proc/html2pencode(t) + t = replacetext(t, "
", "\[pre\]") + t = replacetext(t, "", "\[/pre\]") + t = replacetext(t, "", "\[fontred\]")// to pass html tag integrity unit test + t = replacetext(t, "", "\[fontblue\]")// to pass html tag integrity unit test + t = replacetext(t, "", "\[fontgreen\]") + t = replacetext(t, "", "\[/font\]") + t = replacetext(t, "
", "\[logo\]")
+ t = replacetext(t, "
", "\[redlogo\]")
+ t = replacetext(t, "
", "\[sglogo\]")
+ t = replacetext(t, "", "\[field\]")
+ t = replacetext(t, "R E D A C T E D", "\[redacted\]")
+ t = strip_html_properly(t)
+ return t
+
// Random password generator
/proc/GenerateKey()
//Feel free to move to Helpers.
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 717d7a927b..4c60b7a9bc 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -1154,7 +1154,7 @@ var/list/WALLITEMS = list(
if(length(temp_col )<2)
temp_col = "0[temp_col]"
colour += temp_col
- return colour
+ return "#[colour]"
/proc/color_square(red, green, blue, hex)
var/color = hex ? hex : "#[num2hex(red, 2)][num2hex(green, 2)][num2hex(blue, 2)]"
@@ -1171,7 +1171,7 @@ var/mob/dview/dview_mob = new
log_error("Had to recreate the dview mob!")
dview_mob.loc = center
-
+
dview_mob.see_invisible = invis_flags
. = view(range, dview_mob)
@@ -1490,7 +1490,7 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
. += new /obj/screen/plane_master/lighting //Lighting system (but different!)
. += new /obj/screen/plane_master/o_light_visual //Object lighting (using masks)
. += new /obj/screen/plane_master/emissive //Emissive overlays
-
+
. += new /obj/screen/plane_master/ghosts //Ghosts!
. += new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye!
diff --git a/code/_helpers/unsorted_vr.dm b/code/_helpers/unsorted_vr.dm
index daf4db48d7..0890c1f9c6 100644
--- a/code/_helpers/unsorted_vr.dm
+++ b/code/_helpers/unsorted_vr.dm
@@ -18,7 +18,8 @@
continue
if(vent.welded)
continue
- if(istype(get_area(vent), /area/crew_quarters/sleep)) //No going to dorms
+ var/area/A = get_area(vent)
+ if(A.forbid_events)
continue
vent_list += vent
if(!vent_list.len)
diff --git a/code/_macros.dm b/code/_macros.dm
index d122d9045f..737b317abe 100644
--- a/code/_macros.dm
+++ b/code/_macros.dm
@@ -42,4 +42,6 @@
#define WORLD_ICON_SIZE 32 //Needed for the R-UST port
-#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 //Needed for the R-UST port
\ No newline at end of file
+#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 //Needed for the R-UST port
+
+#define JOINTEXT(X) jointext(X, null)
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 03fd9bac74..8954bf45bc 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -19,7 +19,7 @@
/obj/screen/Destroy()
master = null
return ..()
-
+
/obj/screen/proc/component_click(obj/screen/component_button/component, params)
return
@@ -46,9 +46,8 @@
object_overlays.Cut()
/obj/screen/inventory/proc/add_overlays()
- var/mob/user = hud.mymob
-
- if(hud && user && slot_id)
+ if(hud && hud.mymob && slot_id)
+ var/mob/user = hud.mymob
var/obj/item/holding = user.get_active_hand()
if(!holding || user.get_equipped_item(slot_id))
@@ -619,7 +618,7 @@
var/mob/living/carbon/C = hud.mymob
if(C.handcuffed)
add_overlay(handcuff_overlay)
-
+
// PIP stuff
/obj/screen/component_button
var/obj/screen/parent
@@ -634,7 +633,7 @@
// Character setup stuff
/obj/screen/setup_preview
-
+
var/datum/preferences/pref
/obj/screen/setup_preview/Destroy()
@@ -704,7 +703,7 @@
* size of the screen. This is not ideal, as filter() is faster, and has
* alpha masks, but the alpha masks it has can't be animated, so the 'ping'
* mode of this device isn't possible using that technique.
- *
+ *
* The markers use that technique, though, so at least there's that.
*/
/obj/screen/movable/mapper_holder
@@ -722,7 +721,7 @@
var/obj/screen/mapper/mask_full/mask_full
var/obj/screen/mapper/mask_ping/mask_ping
var/obj/screen/mapper/bg/bg
-
+
var/obj/screen/mapper/frame/frame
var/obj/screen/mapper/powbutton/powbutton
var/obj/screen/mapper/mapbutton/mapbutton
@@ -732,7 +731,7 @@
/obj/screen/movable/mapper_holder/Initialize(mapload, newowner)
owner = newowner
-
+
mask_full = new(src) // Full white square mask
mask_ping = new(src) // Animated 'pinging' mask
bg = new(src) // Background color, holds map in vis_contents, uses mult against masks
@@ -740,19 +739,19 @@
frame = new(src) // Decorative frame
powbutton = new(src) // Clickable button
mapbutton = new(src) // Clickable button
-
+
frame.icon_state = initial(frame.icon_state)+owner.hud_frame_hint
/**
* The vis_contents layout is: this(frame,extras_holder,mask(bg(map)))
* bg is set to BLEND_MULTIPLY against the mask to crop it.
*/
-
+
mask_full.vis_contents.Add(bg)
mask_ping.vis_contents.Add(bg)
frame.vis_contents.Add(powbutton,mapbutton)
vis_contents.Add(frame)
-
+
/obj/screen/movable/mapper_holder/Destroy()
qdel_null(mask_full)
@@ -772,12 +771,12 @@
running = TRUE
if(ping)
vis_contents.Add(mask_ping)
- else
+ else
vis_contents.Add(mask_full)
bg.vis_contents.Cut()
bg.vis_contents.Add(map)
-
+
if(extras && !extras_holder)
extras_holder = extras
vis_contents += extras_holder
@@ -790,7 +789,7 @@
off()
else
on()
-
+
/obj/screen/movable/mapper_holder/proc/mapClick()
if(owner)
if(running)
@@ -818,7 +817,7 @@
mouse_opacity = 0
var/obj/screen/movable/mapper_holder/parent
-/obj/screen/mapper/New()
+/obj/screen/mapper/New()
..()
parent = loc
@@ -921,10 +920,10 @@
var/static/list/ammo_screen_loc_list = list(ui_ammo_hud1, ui_ammo_hud2, ui_ammo_hud3 ,ui_ammo_hud4)
/obj/screen/ammo/proc/add_hud(var/mob/living/user, var/obj/item/weapon/gun/G)
-
+
if(!user?.client)
return
-
+
if(!G)
CRASH("/obj/screen/ammo/proc/add_hud() has been called from [src] without the required param of G")
diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm
index 3839853567..acfa32d52f 100644
--- a/code/controllers/communications.dm
+++ b/code/controllers/communications.dm
@@ -126,6 +126,7 @@ var/const/MED_I_FREQ = 1485
var/const/SEC_I_FREQ = 1475
var/const/TALON_FREQ = 1363 //VOREStation Add
+var/const/CSN_FREQ = 1365 //VOREStation Add
var/list/radiochannels = list(
"Common" = PUB_FREQ,
@@ -145,7 +146,8 @@ var/list/radiochannels = list(
"Entertainment" = ENT_FREQ,
"Medical(I)" = MED_I_FREQ,
"Security(I)" = SEC_I_FREQ,
- "Talon" = TALON_FREQ //VOREStation Add
+ "Talon" = TALON_FREQ, //VOREStation Add
+ "Casino" = CSN_FREQ,
)
// Hey, if anyone ever needs to update tgui/packages/tgui/constants.js with new radio channels
@@ -155,7 +157,7 @@ var/list/radiochannels = list(
set category = "Generate TGUI Radio Constants"
var/list/channel_info = list()
-
+
for(var/i in RADIO_LOW_FREQ to RADIO_HIGH_FREQ)
for(var/key in radiochannels)
if(i == radiochannels[key])
@@ -192,7 +194,7 @@ var/list/ANTAG_FREQS = list(SYND_FREQ, RAID_FREQ)
//Department channels, arranged lexically
var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ)
-var/list/OFFMAP_FREQS = list(TALON_FREQ) //VOREStation Add
+var/list/OFFMAP_FREQS = list(TALON_FREQ, CSN_FREQ) //VOREStation Add
/proc/frequency_span_class(var/frequency)
// Antags!
diff --git a/code/controllers/subsystems/job.dm b/code/controllers/subsystems/job.dm
index f265f39955..2aa6d84cb6 100644
--- a/code/controllers/subsystems/job.dm
+++ b/code/controllers/subsystems/job.dm
@@ -131,12 +131,13 @@ SUBSYSTEM_DEF(job)
return department_datums[primary_department]
+/datum/controller/subsystem/job/proc/get_ping_role(var/role)
+ var/datum/job/J = get_job(role)
+ if(J.requestable)
+ return get_primary_department_of_job(J)
+
// Someday it might be good to port code/game/jobs/job_controller.dm to here and clean it up.
-
-
-
-
/datum/controller/subsystem/job/proc/job_debug_message(message)
if(debug_messages)
log_debug("JOB DEBUG: [message]")
\ No newline at end of file
diff --git a/code/controllers/subsystems/persist_vr.dm b/code/controllers/subsystems/persist_vr.dm
index ea29ae2238..0bde0599cb 100644
--- a/code/controllers/subsystems/persist_vr.dm
+++ b/code/controllers/subsystems/persist_vr.dm
@@ -59,6 +59,8 @@ SUBSYSTEM_DEF(persist)
var/client/C = M.client
var/wait_in_hours = wait / (1 HOUR)
var/pto_factored = wait_in_hours * J.timeoff_factor
+ if(J.playtime_only)
+ pto_factored = 0
LAZYINITLIST(C.department_hours)
LAZYINITLIST(C.play_hours)
var/dept_hours = C.department_hours
diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm
index 20a9ffeaa4..ea8873e717 100644
--- a/code/controllers/subsystems/ticker.dm
+++ b/code/controllers/subsystems/ticker.dm
@@ -50,9 +50,9 @@ var/global/datum/controller/subsystem/ticker/ticker
pregame_timeleft = config.pregame_time
send2mainirc("Server lobby is loaded and open at byond://[config.serverurl ? config.serverurl : (config.server ? config.server : "[world.address]:[world.port]")]")
SSwebhooks.send(
- WEBHOOK_ROUNDPREP,
+ WEBHOOK_ROUNDPREP,
list(
- "map" = station_name(),
+ "map" = station_name(),
"url" = get_world_url()
)
)
@@ -397,14 +397,19 @@ var/global/datum/controller/subsystem/ticker/ticker
if(player && player.ready && player.mind?.assigned_role)
var/datum/job/J = SSjob.get_job(player.mind.assigned_role)
+ // Ask their new_player mob to spawn them
+ if(!player.spawn_checks_vr(player.mind.assigned_role))
+ var/datum/job/job_datum = job_master.GetJob(J.title)
+ job_datum.current_positions--
+ player.mind.assigned_role = null
+ continue //VOREStation Add
+
// Snowflakey AI treatment
if(J?.mob_type & JOB_SILICON_AI)
player.close_spawn_windows()
player.AIize(move = TRUE)
continue
- // Ask their new_player mob to spawn them
- if(!player.spawn_checks_vr(player.mind.assigned_role)) continue //VOREStation Add
var/mob/living/carbon/human/new_char = player.create_character()
// Created their playable character, delete their /mob/new_player
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index 8da8bab272..fef1bcd25d 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -68,7 +68,7 @@
names += componentsubtypes
names += "---Elements---"
names += sortTim(subtypesof(/datum/element), /proc/cmp_typepaths_asc)
- var/result = tgui_input_text(usr, "Choose a component/element to add:", "Add Component/Element", names)
+ var/result = tgui_input_list(usr, "Choose a component/element to add:", "Add Component/Element", names)
if(!usr || !result || result == "---Components---" || result == "---Elements---")
return
if(QDELETED(src))
diff --git a/code/datums/uplink/badassery.dm b/code/datums/uplink/badassery.dm
index 8addcc3f64..8208894af4 100644
--- a/code/datums/uplink/badassery.dm
+++ b/code/datums/uplink/badassery.dm
@@ -91,4 +91,4 @@
var/obj/structure/largecrate/C = /obj/structure/largecrate
icon = image(initial(C.icon), initial(C.icon_state))
- return "[bicon(icon)]"
\ No newline at end of file
+ return "\icon[icon][bicon(icon)]"
\ No newline at end of file
diff --git a/code/datums/uplink/uplink_items.dm b/code/datums/uplink/uplink_items.dm
index 2abb5a1d1a..e5defa6023 100644
--- a/code/datums/uplink/uplink_items.dm
+++ b/code/datums/uplink/uplink_items.dm
@@ -130,7 +130,7 @@ var/datum/uplink/uplink = new()
/datum/uplink_item/item/log_icon()
var/obj/I = path
- return "[bicon(I)]"
+ return "\icon[I][bicon(I)]"
/********************************
* *
@@ -144,7 +144,7 @@ var/datum/uplink/uplink = new()
if(!default_abstract_uplink_icon)
default_abstract_uplink_icon = image('icons/obj/pda.dmi', "pda-syn")
- return "[bicon(default_abstract_uplink_icon)]"
+ return "\icon[default_abstract_uplink_icon][bicon(default_abstract_uplink_icon)]"
/*
* Crated goods.
diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm
index 571e2a22e6..c572ad8d27 100644
--- a/code/datums/wires/camera.dm
+++ b/code/datums/wires/camera.dm
@@ -57,7 +57,7 @@
C.light_disabled = !C.light_disabled
if(WIRE_CAM_ALARM)
- C.visible_message("[bicon(C)] *beep*", "[bicon(C)] *beep*")
+ C.visible_message("\icon[C][bicon(C)] *beep*", "\icon[C][bicon(C)] *beep*")
..()
/datum/wires/camera/proc/CanDeconstruct()
diff --git a/code/datums/wires/jukebox.dm b/code/datums/wires/jukebox.dm
index 125bbd78ef..cec0f4d370 100644
--- a/code/datums/wires/jukebox.dm
+++ b/code/datums/wires/jukebox.dm
@@ -31,16 +31,16 @@
var/obj/machinery/media/jukebox/A = holder
switch(wire)
if(WIRE_MAIN_POWER1)
- holder.visible_message("[bicon(holder)] The power light flickers.")
+ holder.visible_message("\icon[holder][bicon(holder)] The power light flickers.")
A.shock(usr, 90)
if(WIRE_JUKEBOX_HACK)
- holder.visible_message("[bicon(holder)] The parental guidance light flickers.")
+ holder.visible_message("\icon[holder][bicon(holder)] The parental guidance light flickers.")
if(WIRE_REVERSE)
- holder.visible_message("[bicon(holder)] The data light blinks ominously.")
+ holder.visible_message("\icon[holder][bicon(holder)] The data light blinks ominously.")
if(WIRE_SPEEDUP)
- holder.visible_message("[bicon(holder)] The speakers squeaks.")
+ holder.visible_message("\icon[holder][bicon(holder)] The speakers squeaks.")
if(WIRE_SPEEDDOWN)
- holder.visible_message("[bicon(holder)] The speakers rumble.")
+ holder.visible_message("\icon[holder][bicon(holder)] The speakers rumble.")
if(WIRE_START)
A.StartPlaying()
if(WIRE_STOP)
diff --git a/code/datums/wires/mines.dm b/code/datums/wires/mines.dm
index 5e757ad16c..55ea718c3f 100644
--- a/code/datums/wires/mines.dm
+++ b/code/datums/wires/mines.dm
@@ -21,15 +21,15 @@
switch(wire)
if(WIRE_EXPLODE)
- C.visible_message("[bicon(C)] *BEEE-*", "[bicon(C)] *BEEE-*")
+ C.visible_message("\icon[C][bicon(C)] *BEEE-*", "\icon[C][bicon(C)] *BEEE-*")
C.explode()
if(WIRE_EXPLODE_DELAY)
- C.visible_message("[bicon(C)] *BEEE-*", "[bicon(C)] *BEEE-*")
+ C.visible_message("\icon[C][bicon(C)] *BEEE-*", "\icon[C][bicon(C)] *BEEE-*")
C.explode()
if(WIRE_DISARM)
- C.visible_message("[bicon(C)] *click!*", "[bicon(C)] *click!*")
+ C.visible_message("\icon[C][bicon(C)] *click!*", "\icon[C][bicon(C)] *click!*")
var/obj/effect/mine/MI = new C.mineitemtype(get_turf(C))
if(C.trap)
@@ -41,15 +41,15 @@
qdel(C)
if(WIRE_BADDISARM)
- C.visible_message("[bicon(C)] *BEEPBEEPBEEP*", "[bicon(C)] *BEEPBEEPBEEP*")
+ C.visible_message("\icon[C][bicon(C)] *BEEPBEEPBEEP*", "\icon[C][bicon(C)] *BEEPBEEPBEEP*")
spawn(20)
C.explode()
if(WIRE_TRAP)
- C.visible_message("[bicon(C)] *click!*", "[bicon(C)] *click!*")
+ C.visible_message("\icon[C][bicon(C)] *click!*", "\icon[C][bicon(C)] *click!*")
if(mend)
- C.visible_message("[bicon(C)] - The mine recalibrates[C.camo_net ? ", revealing \the [C.trap] inside." : "."]")
+ C.visible_message("\icon[C][bicon(C)] - The mine recalibrates[C.camo_net ? ", revealing \the [C.trap] inside." : "."]")
C.alpha = 255
@@ -61,21 +61,21 @@
return
switch(wire)
if(WIRE_EXPLODE)
- C.visible_message("[bicon(C)] *beep*", "[bicon(C)] *beep*")
+ C.visible_message("\icon[C][bicon(C)] *beep*", "\icon[C][bicon(C)] *beep*")
if(WIRE_EXPLODE_DELAY)
- C.visible_message("[bicon(C)] *BEEPBEEPBEEP*", "[bicon(C)] *BEEPBEEPBEEP*")
+ C.visible_message("\icon[C][bicon(C)] *BEEPBEEPBEEP*", "\icon[C][bicon(C)] *BEEPBEEPBEEP*")
spawn(20)
C.explode()
if(WIRE_DISARM)
- C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
+ C.visible_message("\icon[C][bicon(C)] *ping*", "\icon[C][bicon(C)] *ping*")
if(WIRE_BADDISARM)
- C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
+ C.visible_message("\icon[C][bicon(C)] *ping*", "\icon[C][bicon(C)] *ping*")
if(WIRE_TRAP)
- C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
+ C.visible_message("\icon[C][bicon(C)] *ping*", "\icon[C][bicon(C)] *ping*")
..()
diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm
index e3fd198b3b..1787039622 100644
--- a/code/datums/wires/particle_accelerator.dm
+++ b/code/datums/wires/particle_accelerator.dm
@@ -26,7 +26,7 @@
C.interface_control = !C.interface_control
if(WIRE_PARTICLE_POWER_LIMIT)
- C.visible_message("[bicon(C)][C] makes a large whirring noise.")
+ C.visible_message("\icon[C][bicon(C)][C] makes a large whirring noise.")
/datum/wires/particle_acc/control_box/on_cut(wire, mend)
var/obj/machinery/particle_accelerator/control_box/C = holder
diff --git a/code/defines/procs/announce.dm b/code/defines/procs/announce.dm
index eac4e10ea0..033183a639 100644
--- a/code/defines/procs/announce.dm
+++ b/code/defines/procs/announce.dm
@@ -40,7 +40,7 @@
if(!msg_sanitized)
message = sanitize(message, extra = 0)
- message_title = sanitizeSafe(message_title)
+ message_title = sanitizeSafe(message_title)
var/list/zlevels
if(zlevel)
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index d86e526e39..d08c7a7246 100755
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -806,11 +806,13 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "\improper Shuttle Dock Hallway - Dock One"
icon_state = "entry_D1"
base_turf = /turf/space
+ forbid_events = TRUE
/area/hallway/secondary/entry/D2
name = "\improper Shuttle Dock Hallway - Dock Two"
icon_state = "entry_D2"
base_turf = /turf/space
+ forbid_events = TRUE
/area/hallway/secondary/entry/D2/arrivals
name = "\improper Shuttle Dock Hallway - Dock Two"
@@ -822,6 +824,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "\improper Shuttle Dock Hallway - Dock Three"
icon_state = "entry_D3"
base_turf = /turf/space
+ forbid_events = TRUE
/area/hallway/secondary/entry/D4
name = "\improper Shuttle Dock Hallway - Dock Four"
@@ -963,6 +966,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
icon_state = "Sleep"
ambience = AMBIENCE_GENERIC
forbid_events = TRUE
+ forbid_singulo = TRUE
/area/crew_quarters/toilet
name = "\improper Dormitory Toilets"
diff --git a/code/game/area/Space Station 13 areas_ch.dm b/code/game/area/Space Station 13 areas_ch.dm
index 473b7fb02d..4d69fe8e4e 100644
--- a/code/game/area/Space Station 13 areas_ch.dm
+++ b/code/game/area/Space Station 13 areas_ch.dm
@@ -29,6 +29,7 @@
/area/surface/outpost/main/dorms
name = "\improper Main Outpost Dorms"
soundproofed = TRUE
+ forbid_events = TRUE
/area/surface/outpost/main/dorms/dorm_1
name = "\improper Main Outpost Dorm One"
@@ -72,6 +73,7 @@
/area/crew_quarters/sleep
soundproofed = TRUE
+ forbid_events = TRUE
/area/crew_quarters/sleep/vistor_room_1
limit_mob_size = FALSE
@@ -110,4 +112,5 @@
limit_mob_size = FALSE
/area/medical/cryo/autoresleeve
- name = "\improper Medical Autoresleeving"
\ No newline at end of file
+ name = "\improper Medical Autoresleeving"
+ forbid_events = TRUE
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index ad9ef7a6dd..31d1d07f2b 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -51,6 +51,7 @@
var/sound_env = STANDARD_STATION
var/turf/base_turf //The base turf type of the area, which can be used to override the z-level's base turf
var/forbid_events = FALSE // If true, random events will not start inside this area.
+ var/forbid_singulo = FALSE // If true singulo will not move in.
var/no_spoilers = FALSE // If true, makes it much more difficult to see what is inside an area with things like mesons.
var/soundproofed = FALSE // If true, blocks sounds from other areas and prevents hearers on other areas from hearing the sounds within.
@@ -379,7 +380,7 @@ var/list/mob/living/forced_ambiance_list = new
/area/Entered(mob/M)
if(!istype(M) || !M.ckey)
return
-
+
if(!isliving(M))
M.lastarea = src
return
@@ -450,6 +451,8 @@ var/list/mob/living/forced_ambiance_list = new
return
if(H.incorporeal_move) // VOREstation edit - Phaseshifted beings should not be affected by gravity
return
+ if(H.species.can_zero_g_move || H.species.can_space_freemove)
+ return
if(H.m_intent == "run")
H.AdjustStunned(6)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 5ef2fd6818..d1640d64cd 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -225,7 +225,7 @@
else
f_name += "oil-stained [name][infix]."
- var/list/output = list("[bicon(src)] That's [f_name] [suffix]", desc)
+ var/list/output = list("\icon[src.examine_icon()][bicon(src)] That's [f_name] [suffix]", desc)
if(user.client?.prefs.examine_text_mode == EXAMINE_MODE_INCLUDE_USAGE)
output += description_info
diff --git a/code/game/gamemodes/cult/construct_spells.dm b/code/game/gamemodes/cult/construct_spells.dm
index 62cdd5bf48..5bd8929555 100644
--- a/code/game/gamemodes/cult/construct_spells.dm
+++ b/code/game/gamemodes/cult/construct_spells.dm
@@ -512,7 +512,7 @@
var/obj/item/projectile/new_projectile = make_projectile(spell_projectile, user)
new_projectile.old_style_target(hit_atom)
new_projectile.fire()
- log_and_message_admins("has casted [src] at \the [hit_atom].")
+ log_attack("has casted [src] at \the [hit_atom].")//CHOMPEdit from log_and_message_admins
if(fire_sound)
playsound(src, fire_sound, 75, 1)
return 1
diff --git a/code/game/jobs/job/assistant_vr.dm b/code/game/jobs/job/assistant_vr.dm
index bfcf3037b4..1aa1f7cb55 100644
--- a/code/game/jobs/job/assistant_vr.dm
+++ b/code/game/jobs/job/assistant_vr.dm
@@ -27,6 +27,7 @@
job_description = "An Intern does whatever is requested of them, often doing so in process of learning \
another job. Though they are part of the crew, they have no real authority."
timeoff_factor = 0 // Interns, noh
+ requestable = FALSE
/datum/alt_title/intern_eng
title = "Apprentice Engineer"
@@ -96,6 +97,7 @@
supervisors = "nobody! You don't work here"
job_description = "A Visitor is just there to visit the place. They have no real authority or responsibility."
timeoff_factor = 0
+ requestable = FALSE
alt_titles = list("Guest" = /datum/alt_title/guest, "Traveler" = /datum/alt_title/traveler)
/datum/job/assistant/New()
diff --git a/code/game/jobs/job/engineering_vr.dm b/code/game/jobs/job/engineering_vr.dm
index 0c698587b6..e0ca7bac7e 100644
--- a/code/game/jobs/job/engineering_vr.dm
+++ b/code/game/jobs/job/engineering_vr.dm
@@ -23,17 +23,28 @@
/datum/alt_title/maintenance_manager
title = "Maintenance Manager"
+/datum/job/chief_engineer/get_request_reasons()
+ return list("Engine setup", "Construction project", "Repairs necessary")
+
/datum/job/engineer
pto_type = PTO_ENGINEERING
alt_titles = list("Maintenance Technician" = /datum/alt_title/maint_tech, "Engine Technician" = /datum/alt_title/engine_tech,
- "Electrician" = /datum/alt_title/electrician, "Construction Engineer" = /datum/alt_title/construction_engi)
+ "Electrician" = /datum/alt_title/electrician, "Construction Engineer" = /datum/alt_title/construction_engi, "Engineering Contractor" = /datum/alt_title/engineering_contractor)
/datum/alt_title/construction_engi
title = "Construction Engineer"
title_blurb = "A Construction Engineer fulfills similar duties to other engineers, but usually occupies spare time with construction of extra facilities in dedicated areas or \
as additions to station layout."
+/datum/alt_title/engineering_contractor
+ title = "Engineering Contractor"
+ title_blurb = "An Engineering Contractor fulfills similar duties to other engineers, but isn't directly employed by NT proper."
+
+/datum/job/engineer/get_request_reasons()
+ return list("Engine setup", "Construction project", "Repairs necessary")
+
+
/datum/job/atmos
@@ -50,3 +61,6 @@
/datum/alt_title/disposals_tech
title = "Disposals Technician"
title_blurb = "A Disposals Technician is an Atmospheric Technician still and can fulfill all the same duties, although specializes more in disposals delivery system's operations and configurations."
+
+/datum/job/atmos/get_request_reasons()
+ return list("Construction project", "Repairs necessary")
\ No newline at end of file
diff --git a/code/game/jobs/job/job_vr.dm b/code/game/jobs/job/job_vr.dm
index a416a3af48..ac8b6be0b4 100644
--- a/code/game/jobs/job/job_vr.dm
+++ b/code/game/jobs/job/job_vr.dm
@@ -17,6 +17,11 @@
//Time required in the department as other jobs before playing this one (in hours)
var/dept_time_required = 0
+ //Do we forbid ourselves from earning PTO?
+ var/playtime_only = FALSE
+
+ var/requestable = TRUE
+
// Check client-specific availability rules.
/datum/job/proc/player_has_enough_pto(client/C)
return timeoff_factor >= 0 || (C && LAZYACCESS(C.department_hours, pto_type) > 0)
@@ -39,7 +44,7 @@
if(C && config.use_playtime_restriction_for_jobs && dept_time_required)
var/remaining_time_needed = dept_time_required
for(var/key in C.play_hours)
- if(isnum(C.play_hours[key]))
+ if(isnum(C.play_hours[key]) && !(key == PTO_TALON))
remaining_time_needed = max(0, remaining_time_needed - C.play_hours[key])
return remaining_time_needed
return 0
@@ -55,4 +60,7 @@
if(isnum(C.play_hours[PTO_EXPLORATION]))
remaining_time_needed = max(0, remaining_time_needed - C.play_hours[PTO_EXPLORATION])
return remaining_time_needed
- return 0
\ No newline at end of file
+ return 0
+
+/datum/job/proc/get_request_reasons()
+ return list()
\ No newline at end of file
diff --git a/code/game/jobs/job/medical_vr.dm b/code/game/jobs/job/medical_vr.dm
index 120d538e4a..5fc2081ebd 100644
--- a/code/game/jobs/job/medical_vr.dm
+++ b/code/game/jobs/job/medical_vr.dm
@@ -21,14 +21,16 @@
/datum/alt_title/healthcare_manager
title = "Healthcare Manager"
+/datum/job/cmo/get_request_reasons()
+ return list("Surgery pending", "Viral outbreak")
+
/datum/job/doctor
spawn_positions = 5
pto_type = PTO_MEDICAL
alt_titles = list("Physician" = /datum/alt_title/physician, "Medical Practitioner" = /datum/alt_title/medical_practitioner, "Surgeon" = /datum/alt_title/surgeon,
"Emergency Physician" = /datum/alt_title/emergency_physician, "Nurse" = /datum/alt_title/nurse, "Orderly" = /datum/alt_title/orderly,
- "Virologist" = /datum/alt_title/virologist)
-
+ "Virologist" = /datum/alt_title/virologist, "Medical Contractor" = /datum/alt_title/medical_contractor)
/datum/alt_title/physician
title = "Physician"
@@ -42,6 +44,13 @@
and dirty labor around the department."
title_outfit = /decl/hierarchy/outfit/job/medical/doctor/nurse
+/datum/alt_title/medical_contractor
+ title = "Medical Contractor"
+ title_blurb = "A Medical Contractor can be anything from a full-blown doctor to the likes of a nurse or orderly, but isn't directly employed by NT proper."
+
+/datum/job/doctor/get_request_reasons()
+ return list("Surgery pending", "Viral outbreak")
+
/datum/job/chemist
pto_type = PTO_MEDICAL
@@ -71,10 +80,15 @@
/datum/job/paramedic
pto_type = PTO_MEDICAL
- alt_titles = list("Emergency Medical Technician" = /datum/alt_title/emt, "Medical Responder" = /datum/alt_title/medical_responder)
+ alt_titles = list("Emergency Medical Technician" = /datum/alt_title/emt, "Medical Responder" = /datum/alt_title/medical_responder) //CHOMPedit: Removed SAR because that's an actual job here
/datum/alt_title/medical_responder
title = "Medical Responder"
title_blurb = "A Medical Responder is primarily concerned with the recovery of patients who are unable to make it to the Medical Department on their \
own. They are capable of keeping a patient stabilized until they reach the hands of someone with more training."
title_outfit = /decl/hierarchy/outfit/job/medical/paramedic/emt
+
+/* //CHOMPedit: Commented out because this is an actual job here
+/datum/alt_title/sar
+ title = "Search and Rescue"
+*/
diff --git a/code/game/jobs/job/security_vr.dm b/code/game/jobs/job/security_vr.dm
index b6b704660f..22de747d7b 100644
--- a/code/game/jobs/job/security_vr.dm
+++ b/code/game/jobs/job/security_vr.dm
@@ -16,6 +16,9 @@
/datum/alt_title/security_manager
title = "Security Manager"
+/datum/job/hos/get_request_reasons()
+ return list("Wildlife management", "Forensic investigation")
+
/datum/job/warden
pto_type = PTO_SECURITY
@@ -28,6 +31,9 @@
/datum/alt_title/armory_superintendent
title = "Armory Superintendent"
+/datum/job/warden/get_request_reasons()
+ return list("Wildlife management")
+
/datum/job/detective
pto_type = PTO_SECURITY
@@ -39,13 +45,16 @@
/datum/alt_title/security_inspector
title = "Security Inspector"
+/datum/job/detective/get_request_reasons()
+ return list("Forensic investigation")
+
/datum/job/officer
total_positions = 5
spawn_positions = 5
pto_type = PTO_SECURITY
alt_titles = list("Patrol Officer" = /datum/alt_title/patrol_officer, "Security Guard" = /datum/alt_title/security_guard,
- "Security Deputy" = /datum/alt_title/security_guard, "Junior Officer" = /datum/alt_title/junior_officer)
+ "Security Deputy" = /datum/alt_title/security_guard, "Junior Officer" = /datum/alt_title/junior_officer, "Security Contractor" = /datum/alt_title/security_contractor)
/datum/alt_title/patrol_officer
title = "Patrol Officer"
@@ -55,3 +64,9 @@
/datum/alt_title/security_deputy
title = "Security Deputy"
+
+/datum/alt_title/security_contractor
+ title = "Security Contractor"
+
+/datum/job/officer/get_request_reasons()
+ return list("Wildlife management")
diff --git a/code/game/jobs/job/special_vr.dm b/code/game/jobs/job/special_vr.dm
index 54e8c157da..3a10a23df5 100644
--- a/code/game/jobs/job/special_vr.dm
+++ b/code/game/jobs/job/special_vr.dm
@@ -113,6 +113,7 @@
job_description = "A Clown is there to entertain the crew and keep high morale using various harmless pranks and ridiculous jokes!"
whitelist_only = 1
latejoin_only = 0
+ requestable = FALSE
outfit_type = /decl/hierarchy/outfit/job/clown
pto_type = PTO_CIVILIAN
alt_titles = list("Jester" = /datum/alt_title/jester, "Fool" = /datum/alt_title/fool)
@@ -144,6 +145,7 @@
alt_titles = list("Poseur" = /datum/alt_title/poseur)
whitelist_only = 1
latejoin_only = 0
+ requestable = FALSE
outfit_type = /decl/hierarchy/outfit/job/mime
pto_type = PTO_CIVILIAN
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 046db35f33..5a414430ea 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -355,7 +355,7 @@ var/global/datum/controller/occupations/job_master
return 1
-/datum/controller/occupations/proc/EquipRank(var/mob/living/carbon/human/H, var/rank, var/joined_late = 0)
+/datum/controller/occupations/proc/EquipRank(var/mob/living/carbon/human/H, var/rank, var/joined_late = 0, var/announce = TRUE)
if(!H) return null
var/datum/job/job = GetJob(rank)
@@ -494,7 +494,7 @@ var/global/datum/controller/occupations/job_master
return H
// TWEET PEEP
- if(rank == "Site Manager")
+ if(rank == "Site Manager" && announce)
var/sound/announce_sound = (ticker.current_state <= GAME_STATE_SETTING_UP) ? null : sound('sound/misc/boatswain.ogg', volume=20)
captain_announcement.Announce("All hands, [alt_title ? alt_title : "Site Manager"] [H.real_name] on deck!", new_sound = announce_sound, zlevel = H.z)
diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm
index ca40f0dc53..8d3933faca 100644
--- a/code/game/machinery/air_alarm.dm
+++ b/code/game/machinery/air_alarm.dm
@@ -835,7 +835,18 @@
TLV["temperature"] = list(T0C - 40, T0C - 20, T0C + 40, T0C + 66) // K, Lower Temperature for Freezer Air Alarms (This is because TLV is hardcoded to be generated on first_run, and therefore the only way to modify this without changing TLV generation)
-// VOREStation Edit End
+// VOREStation Edit End, CHOMPEdit START
+/obj/machinery/alarm/sifwilderness
+ breach_detection = 0
+ report_danger_level = 0
+
+/obj/machinery/alarm/sifwilderness/first_run()
+ . = ..()
+
+ TLV["oxygen"] = list(16, 17, 135, 140)
+ TLV["pressure"] = list(0,ONE_ATMOSPHERE*0.10,ONE_ATMOSPHERE*1.50,ONE_ATMOSPHERE*1.60)
+ TLV["temperature"] = list(T0C - 40, T0C - 31, T0C + 40, T0C + 120)
+// CHOMPEdit END
#undef LOAD_TLV_VALUES
#undef TEST_TLV_VALUES
#undef DECLARE_TLV_VALUES
\ No newline at end of file
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 7def7f8b8e..188fd356dc 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -1125,7 +1125,7 @@
// This is not a status display message, since it's something the character
// themselves is meant to see BEFORE putting the money in
- to_chat(usr, "[bicon(cashmoney)] That is not enough money.")
+ to_chat(usr, "\icon[cashmoney][bicon(cashmoney)] That is not enough money.")
return 0
if(istype(cashmoney, /obj/item/weapon/spacecash))
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 137d3a7adb..6ceab53895 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -111,7 +111,7 @@ Class Procs:
var/clickvol = 40 // volume
var/interact_offline = 0 // Can the machine be interacted with while de-powered.
var/obj/item/weapon/circuitboard/circuit = null
-
+
// 0.0 - 1.0 multipler for prob() based on bullet structure damage
// So if this is 1.0 then a 100 damage bullet will always break this structure
// If this is 0.5 then a 50 damage bullet will break this structure 25% of the time
@@ -284,7 +284,7 @@ Class Procs:
/obj/machinery/proc/state(var/msg)
for(var/mob/O in hearers(src, null))
- O.show_message("[bicon(src)] [msg]", 2)
+ O.show_message("\icon[src][bicon(src)] [msg]", 2)
/obj/machinery/proc/ping(text=null)
if(!text)
@@ -439,7 +439,7 @@ Class Procs:
for(var/obj/I in contents)
if(istype(I,/obj/item/weapon/card/id))
I.forceMove(src.loc)
-
+
if(!circuit)
return 0
var/obj/structure/frame/A = new /obj/structure/frame(src.loc)
@@ -499,7 +499,7 @@ Class Procs:
var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system.attach(src)
-
+
var/atom/droploc = drop_location()
if(!droploc || !contents.len) // not even a circuit?
playsound(src, 'sound/machines/machine_die_short.ogg')
@@ -513,17 +513,17 @@ Class Procs:
if(severity != 1)
for(var/obj/item/weapon/card/id/I in contents)
surviving_parts |= I
-
+
// May populate some items to throw around
if(!LAZYLEN(component_parts) && circuit)
circuit.apply_default_parts(src)
-
+
var/survivability
switch(severity)
// No survivors
if(1)
survivability = 0
-
+
// 1 part survives
if(2)
survivability = 0
@@ -534,15 +534,15 @@ Class Procs:
// 50% of parts destroyed on average
if(3)
survivability = 50
-
+
// No parts destroyed, but you lose the frame
else
survivability = 100
-
+
for(var/atom/movable/P in contents)
if(prob(survivability))
surviving_parts |= P
-
+
if(circuit && severity >= 2)
var/datum/frame/frame_types/FT = circuit.board_type
if(istype(FT))
diff --git a/code/game/machinery/overview.dm b/code/game/machinery/overview.dm
index 705914f794..c63ea1f1d8 100644
--- a/code/game/machinery/overview.dm
+++ b/code/game/machinery/overview.dm
@@ -138,7 +138,7 @@
var/icon/I = imap[1+(ix + icx*iy)*2]
var/icon/I2 = imap[2+(ix + icx*iy)*2]
- //to_world("icon: [bicon(I)]")
+ //to_world("icon: \icon[I][bicon(I)]")
I.DrawBox(colour, rx, ry, rx+1, ry+1)
@@ -153,7 +153,7 @@
H.screen_loc = "[5 + i%icx],[6+ round(i/icx)]"
- //to_world("[bicon(I)] at [H.screen_loc]")
+ //to_world("\icon[I][bicon(I)] at [H.screen_loc]")
H.name = (i==0)?"maprefresh":"map"
@@ -266,7 +266,7 @@
//to_world("trying [ix],[iy] : [ix+icx*iy]")
var/icon/I = imap[1+(ix + icx*iy)]
- //to_world("icon: [bicon(I)]")
+ //to_world("icon: \icon[I][bicon(I)]")
I.DrawBox(colour, rx, ry, rx, ry)
@@ -279,7 +279,7 @@
H.screen_loc = "[5 + i%icx],[6+ round(i/icx)]"
- //to_world("[bicon(I)] at [H.screen_loc]")
+ //to_world("\icon[I][bicon(I)] at [H.screen_loc]")
H.name = (i==0)?"maprefresh":"map"
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index eaad936be4..81e04792c1 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -419,7 +419,7 @@
return
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, "PortableTurret", name, 500, 400)
+ ui = new(user, src, "PortableTurret", name, ui_x = 500, ui_y = 400)
ui.open()
/obj/machinery/porta_turret/tgui_data(mob/user)
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index f52c14da46..115e5e710a 100644
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -10,7 +10,7 @@
active_power_usage = 40000 //40 kW
var/efficiency = 40000 //will provide the modified power rate when upgraded
var/obj/item/charging = null
- var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/modular_computer, /obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/cell, /obj/item/device/suit_cooling_unit/emergency, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric, /obj/item/ammo_magazine/smart, /obj/item/device/flash, /obj/item/device/defib_kit, /obj/item/ammo_casing/microbattery, /obj/item/ammo_magazine/cell_mag, /obj/item/weapon/gun/projectile/cell_loaded) //VOREStation Add - NSFW Batteries
+ var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/modular_computer, /obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/cell, /obj/item/device/suit_cooling_unit/emergency, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric, /obj/item/ammo_magazine/smart, /obj/item/device/flash, /obj/item/device/defib_kit, /obj/item/ammo_casing/microbattery, /obj/item/device/paicard, /obj/item/ammo_magazine/cell_mag, /obj/item/weapon/gun/projectile/cell_loaded) // CHOMPedit: medigun stuff
var/icon_state_charged = "recharger2"
var/icon_state_charging = "recharger1"
var/icon_state_idle = "recharger0" //also when unpowered
@@ -68,7 +68,7 @@
if(EW.use_external_power)
to_chat(user, "\The [EW] has no recharge port.")
return
- else if(istype(G, /obj/item/ammo_magazine/cell_mag))
+ else if(istype(G, /obj/item/ammo_magazine/cell_mag)) // CHOMPedit start
var/obj/item/ammo_magazine/cell_mag/maggy = G
if(maggy.stored_ammo.len < 1)
to_chat(user, "\The [G] does not have any cells installed.")
@@ -81,7 +81,18 @@
to_chat(user, "\The [G] does not have any cell in its magazine installed.")
return
else
- to_chat(user, "\The [G] does not have a magazine installed..")
+ to_chat(user, "\The [G] does not have a magazine installed..") // CHOMPedit end
+ if(istype(G, /obj/item/device/paicard))
+ var/obj/item/device/paicard/ourcard = G
+ if(ourcard.panel_open)
+ to_chat(user, "\The [ourcard] won't fit in the recharger with its panel open.")
+ return
+ if(ourcard.pai)
+ if(ourcard.pai.stat == CONSCIOUS)
+ to_chat(user, "\The [ourcard] boops... it doesn't need to be recharged!")
+ return
+ else
+ to_chat(user, "\The [ourcard] doesn't have a personality!")
return
user.drop_item()
@@ -134,6 +145,25 @@
if(!charging)
update_use_power(USE_POWER_IDLE)
icon_state = icon_state_idle
+ //VOREStation Edit Start - pAI revival!
+ else if(istype(charging, /obj/item/device/paicard))
+ var/obj/item/device/paicard/pcard = charging
+ if(pcard.is_damage_critical())
+ pcard.forceMove(get_turf(src))
+ charging = null
+ pcard.damage_random_component()
+ update_icon()
+ else if(pcard.pai.bruteloss)
+ pcard.pai.adjustBruteLoss(-5)
+ else if(pcard.pai.fireloss)
+ pcard.pai.adjustFireLoss(-5)
+ else
+ charging = null
+ update_icon()
+ src.visible_message("\The [src] ejects the [pcard]!")
+ pcard.forceMove(get_turf(src))
+ pcard.pai.full_restore()
+ //VOREStation Edit End
else
var/obj/item/weapon/cell/C = charging.get_cell()
if(istype(C))
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index a1d44b9838..d2adbad8da 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -198,7 +198,7 @@
desc += "| Installed Personality: | -[pai.name] | +[pai.name] | +
| Integrity: [pai.health] | ||
| Prime directive: | @@ -511,6 +533,5 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard) return pick(/obj/item/device/paicard ,/obj/item/device/paicard/typeb) /obj/item/device/paicard/digest_act(var/atom/movable/item_storage = null) - if(!pai.digestable) - return - . = ..() + if(pai.digestable) + return ..() diff --git a/code/game/objects/items/devices/paicard_vr.dm b/code/game/objects/items/devices/paicard_vr.dm new file mode 100644 index 0000000000..7283966d47 --- /dev/null +++ b/code/game/objects/items/devices/paicard_vr.dm @@ -0,0 +1,385 @@ +#define PP_FUNCTIONAL 0 +#define PP_BROKEN 1 +#define PP_MISSING 2 + +var/global/list/paikeys = list() + +/obj/item/device/paicard + var/panel_open = FALSE + var/cell = PP_FUNCTIONAL //critical- power + var/processor = PP_FUNCTIONAL //critical- the thinky part + var/board = PP_FUNCTIONAL //critical- makes everything work + var/capacitor = PP_FUNCTIONAL //critical- power processing + var/projector = PP_FUNCTIONAL //non-critical- affects unfolding + var/emitter = PP_FUNCTIONAL //non-critical- affects unfolding + var/speech_synthesizer = PP_FUNCTIONAL //non-critical- affects speech + +/obj/item/device/paicard/attackby(var/obj/item/I as obj, mob/user as mob) + if(istype(I,/obj/item/weapon/tool/screwdriver)) + if(panel_open) + panel_open = FALSE + user.visible_message("\The [user] secured \the [src]'s maintenance panel.") + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) + else if(pai) + if(do_after(user, 3 SECONDS)) + panel_open = TRUE + user.visible_message("\The [user] opened \the [src]'s maintenance panel.") + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) + if(istype(I,/obj/item/device/robotanalyzer)) + if(!panel_open) + to_chat(user, "The panel isn't open. You will need to unscrew it to open it.") + else + if(cell == PP_FUNCTIONAL) + to_chat(user,"Power cell: functional") + else if(cell == PP_BROKEN) + to_chat(user,"Power cell: damaged - CRITICAL") + else + to_chat(user,"Power cell: missing - CRITICAL") + + if(processor == PP_FUNCTIONAL) + to_chat(user,"Processor: functional") + else if(processor == PP_BROKEN) + to_chat(user,"Processor: damaged - CRITICAL") + else + to_chat(user,"Processor: missing - CRITICAL") + + if(board == PP_FUNCTIONAL) + to_chat(user,"Board: functional") + else if(board == PP_BROKEN) + to_chat(user,"Board: damaged - CRITICAL") + else + to_chat(user,"Board: missing - CRITICAL") + + if(capacitor == PP_FUNCTIONAL) + to_chat(user,"Capacitors: functional") + else if(capacitor == PP_BROKEN) + to_chat(user,"Capacitors: damaged - CRITICAL") + else + to_chat(user,"Capacitors: missing - CRITICAL") + + if(projector == PP_FUNCTIONAL) + to_chat(user,"Projectors: functional") + else if(projector == PP_BROKEN) + to_chat(user,"Projectors: damaged") + else + to_chat(user,"Projectors: missing") + + if(emitter == PP_FUNCTIONAL) + to_chat(user,"Emitters: functional") + else if(emitter == PP_BROKEN) + to_chat(user,"Emitters: damaged") + else + to_chat(user,"Emitters: missing") + + if(speech_synthesizer == PP_FUNCTIONAL) + to_chat(user,"Speech Synthesizer: functional") + else if(speech_synthesizer == PP_BROKEN) + to_chat(user,"Speech Synthesizer: damaged") + else + to_chat(user,"Speech Synthesizer: missing") + + if(istype(I,/obj/item/device/multitool)) + if(!panel_open) + to_chat(user, "You can't do that in this state.") + else + var/list/parts = list() + if(cell != PP_MISSING) + parts |= "cell" + if(processor != PP_MISSING) + parts |= "processor" + if(board != PP_MISSING) + parts |= "board" + if(capacitor != PP_MISSING) + parts |= "capacitor" + if(projector != PP_MISSING) + parts |= "projector" + if(emitter != PP_MISSING) + parts |= "emitter" + if(speech_synthesizer != PP_MISSING) + parts |= "speech synthesizer" + + var/choice = tgui_input_list(user, "Which part would you like to check?", "Check part", parts) + switch(choice) + if("cell") + if(cell == PP_FUNCTIONAL) + to_chat(user,"Power cell: functional") + else if(speech_synthesizer == PP_BROKEN) + to_chat(user,"Power cell: damaged") + else + to_chat(user,"Power cell: missing") + + if("processor") + if(processor == PP_FUNCTIONAL) + to_chat(user,"Processor: functional") + else if(speech_synthesizer == PP_BROKEN) + to_chat(user,"Processor: damaged") + else + to_chat(user,"Processor: missing") + + if("board") + if(board == PP_FUNCTIONAL) + to_chat(user,"Board: functional") + else if(speech_synthesizer == PP_BROKEN) + to_chat(user,"Board: damaged") + else + to_chat(user,"Board: missing") + + if("capacitor") + if(capacitor == PP_FUNCTIONAL) + to_chat(user,"Capacitors: functional") + else if(speech_synthesizer == PP_BROKEN) + to_chat(user,"Capacitors: damaged") + else + to_chat(user,"Capacitors: missing") + + if("projector") + if(projector == PP_FUNCTIONAL) + to_chat(user,"Projectors: functional") + else if(speech_synthesizer == PP_BROKEN) + to_chat(user,"Projectors: damaged") + else + to_chat(user,"Projectors: missing") + + if("emitter") + if(emitter == PP_FUNCTIONAL) + to_chat(user,"Emitters: functional") + else if(speech_synthesizer == PP_BROKEN) + to_chat(user,"Emitters: damaged") + else + to_chat(user,"Emitters: missing") + + if("speech synthesizer") + if(speech_synthesizer == PP_FUNCTIONAL) + to_chat(user,"Speech Synthesizer: functional") + else if(speech_synthesizer == PP_BROKEN) + to_chat(user,"Speech Synthesizer: damaged") + else + to_chat(user,"Speech Synthesizer: missing") + + if(istype(I,/obj/item/paiparts/cell)) + if(cell == PP_MISSING) + if(do_after(user, 3 SECONDS)) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + cell = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + else + to_chat(user, "You would need to remove the installed [I] first!") + if(istype(I,/obj/item/paiparts/processor)) + if(processor == PP_MISSING) + if(do_after(user, 3 SECONDS)) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + processor = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + else + to_chat(user, "You would need to remove the installed [I] first!") + if(istype(I,/obj/item/paiparts/board)) + if(board == PP_MISSING) + if(do_after(user, 3 SECONDS)) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + board = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + else + to_chat(user, "You would need to remove the installed [I] first!") + if(istype(I,/obj/item/paiparts/capacitor)) + if(capacitor == PP_MISSING) + if(do_after(user, 3 SECONDS)) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + capacitor = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + else + to_chat(user, "You would need to remove the installed [I] first!") + if(istype(I,/obj/item/paiparts/projector)) + if(projector == PP_MISSING) + if(do_after(user, 3 SECONDS)) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + projector = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + else + to_chat(user, "You would need to remove the installed [I] first!") + if(istype(I,/obj/item/paiparts/emitter)) + if(emitter == PP_MISSING) + if(do_after(user, 3 SECONDS)) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + emitter = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + else + to_chat(user, "You would need to remove the installed [I] first!") + if(istype(I,/obj/item/paiparts/speech_synthesizer)) + if(speech_synthesizer == PP_MISSING) + if(do_after(user, 3 SECONDS)) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + speech_synthesizer = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + else + to_chat(user, "You would need to remove the installed [I] first!") + +/obj/item/device/paicard/attack_self(mob/user) + if(!panel_open) + access_screen(user) + return + var/list/parts = list() + if(cell != PP_MISSING) + parts |= "cell" + if(processor != PP_MISSING) + parts |= "processor" + if(board != PP_MISSING) + parts |= "board" + if(capacitor != PP_MISSING) + parts |= "capacitor" + if(projector != PP_MISSING) + parts |= "projector" + if(emitter != PP_MISSING) + parts |= "emitter" + if(speech_synthesizer != PP_MISSING) + parts |= "speech synthesizer" + + var/choice = tgui_input_list(user, "Which part would you like to remove?", "Remove part", parts) + if(choice) + playsound(src, 'sound/items/pickup/component.ogg', vary = TRUE) + else + return + if(!do_after(user, 3 SECONDS)) + return + switch(choice) + if("cell") + if(cell == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + cell = PP_MISSING + if("processor") + if(processor == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + processor = PP_MISSING + if("board") + board = PP_MISSING + if(board == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + + if("capacitor") + if(capacitor == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + capacitor = PP_MISSING + if("projector") + if(projector == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + projector = PP_MISSING + if("emitter") + if(emitter == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + emitter = PP_MISSING + if("speech synthesizer") + if(speech_synthesizer == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + speech_synthesizer = PP_MISSING + +/obj/item/device/paicard/proc/death_damage() + + var/number = rand(1,4) + while(number) + number -- + switch(rand(1,4)) + if(1) + cell = PP_BROKEN + if(2) + processor = PP_BROKEN + if(3) + board = PP_BROKEN + if(4) + capacitor = PP_BROKEN + + +/obj/item/device/paicard/proc/damage_random_component(nonfatal = FALSE) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + if(prob(80) || nonfatal) //Way more likely to be non-fatal part damage + switch(rand(1,3)) + if(1) + projector = PP_BROKEN + if(2) + emitter = PP_BROKEN + if(3) + speech_synthesizer = PP_BROKEN + else + switch(rand(1,4)) + if(1) + cell = PP_BROKEN + if(2) + processor = PP_BROKEN + if(3) + board = PP_BROKEN + if(4) + capacitor = PP_BROKEN + +/obj/item/device/paicard/proc/is_damage_critical() + if(cell != PP_FUNCTIONAL || processor != PP_FUNCTIONAL || board != PP_FUNCTIONAL || capacitor != PP_FUNCTIONAL) + return TRUE + return FALSE + +/obj/item/paiparts + name = "broken pAI component" + desc = "It's broken scrap from a pAI card!" + icon = 'icons/obj/paicard.dmi' + icon_state = "broken" + pickup_sound = 'sound/items/pickup/card.ogg' + drop_sound = 'sound/items/drop/card.ogg' +/obj/item/paiparts/Initialize() + . = ..() + pixel_x = rand(-10,10) + pixel_y = rand(-10,10) + +/obj/item/paiparts/cell + name = "pAI power cell" + desc = "It's very small and efficient! It powers the pAI!" + icon_state = "cell" +/obj/item/paiparts/processor + name = "pAI processor" + desc = "It's the brain of your computer friend!" + icon_state = "processor" +/obj/item/paiparts/board + name = "pAI board" + desc = "It's the thing all the other parts get attatched to!" + icon_state = "board" +/obj/item/paiparts/capacitor + name = "pAI capacitor" + desc = "It helps regulate power flow!" + icon_state = "capacitor" +/obj/item/paiparts/projector + name = "pAI projector" + desc = "It projects the pAI's form!" + icon_state = "projector" +/obj/item/paiparts/emitter + name = "pAI emitter" + desc = "It emits the fields to help the pAI get around!" + icon_state = "emitter" +/obj/item/paiparts/speech_synthesizer + name = "pAI speech synthesizer" + desc = "It's a little voice box!" + icon_state = "speech_synthesizer" diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index b7304fa8a1..e8ba830cae 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -491,7 +491,7 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer) var/list/jamming = is_jammed(src) if(jamming) var/distance = jamming["distance"] - to_chat(M, "[bicon(src)] You hear the [distance <= 2 ? "loud hiss" : "soft hiss"] of static.") + to_chat(M, "\icon[src][bicon(src)] You hear the [distance <= 2 ? "loud hiss" : "soft hiss"] of static.") return FALSE // First, we want to generate a new radio signal diff --git a/code/game/objects/items/devices/radio/radio_ch.dm b/code/game/objects/items/devices/radio/radio_ch.dm index aa4759823f..08b3b624f9 100644 --- a/code/game/objects/items/devices/radio/radio_ch.dm +++ b/code/game/objects/items/devices/radio/radio_ch.dm @@ -49,4 +49,27 @@ if(!broadcast_tiles) update_broadcast_tiles() return broadcast_tiles -#undef CANBROADCAST_INNERBOX + +//*Subspace Radio*// +/obj/item/device/radio/subspace + adhoc_fallback = 1 + canhear_range = 8 + desc = "A heavy duty radio that can pick up all manor of shortwave and subspace frequencies. It's a bit bulkier than a normal radio thanks to the extra hardware." + description_info = "This radio can broadcast over any headset frequency that the user has access to. It has a shortwave fallback to directly broadcast to all radio equipment on the same Z-Level/Map in the event of a telecommunications failure. This device requires a functioning Telecommunications Network/Relay to send and receive signals meant for headsets. Additionally, the volume knob seems to be stuck on the max setting. You could hear this thing clear across a room... Not good for discretely listening in on secure channels or being stealthy!" + icon_state = "radio" + name = "subspace radio" + subspace_transmission = 1 + throwforce = 5 + throw_range = 7 + throw_speed = 1 + +//* Bluespace Radio *// +/obj/item/device/bluespaceradio/southerncross_prelinked + name = "bluespace radio (southerncross)" + handset = /obj/item/device/radio/bluespacehandset/linked/southerncross_prelinked + +/obj/item/device/radio/bluespacehandset/linked/southerncross_prelinked + bs_tx_preload_id = "Receiver A" //Transmit to a receiver + bs_rx_preload_id = "Broadcaster A" //Recveive from a transmitter + +#undef CANBROADCAST_INNERBOX \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners/gas.dm b/code/game/objects/items/devices/scanners/gas.dm index ca35911448..9fbc319d6d 100644 --- a/code/game/objects/items/devices/scanners/gas.dm +++ b/code/game/objects/items/devices/scanners/gas.dm @@ -23,7 +23,7 @@ /obj/item/device/analyzer/attack_self(mob/user as mob) if (user.stat) return - if (!(ishuman(user) || ticker) && ticker.mode.name != "monkey") + if (!user.IsAdvancedToolUser()) to_chat(usr, "You don't have the dexterity to do this!") return diff --git a/code/game/objects/items/devices/scanners/health.dm b/code/game/objects/items/devices/scanners/health.dm index ae2683ede0..ba1c960d9d 100644 --- a/code/game/objects/items/devices/scanners/health.dm +++ b/code/game/objects/items/devices/scanners/health.dm @@ -41,7 +41,7 @@ dat += "Body Temperature: ???" user.show_message("[dat]", 1) return - if (!(ishuman(user) || ticker) && ticker.mode.name != "monkey") + if (!user.IsAdvancedToolUser()) to_chat(user, "You don't have the dexterity to do this!") return diff --git a/code/game/objects/items/devices/scanners/mass_spectrometer.dm b/code/game/objects/items/devices/scanners/mass_spectrometer.dm index fee41eb880..5c044fc535 100644 --- a/code/game/objects/items/devices/scanners/mass_spectrometer.dm +++ b/code/game/objects/items/devices/scanners/mass_spectrometer.dm @@ -30,7 +30,7 @@ /obj/item/device/mass_spectrometer/attack_self(mob/user as mob) if (user.stat) return - if (!(ishuman(user) || ticker) && ticker.mode.name != "monkey") + if (!user.IsAdvancedToolUser()) to_chat(user, "You don't have the dexterity to do this!") return if(reagents.total_volume) diff --git a/code/game/objects/items/devices/text_to_speech.dm b/code/game/objects/items/devices/text_to_speech.dm index 330ca97d73..c97693ed5f 100644 --- a/code/game/objects/items/devices/text_to_speech.dm +++ b/code/game/objects/items/devices/text_to_speech.dm @@ -24,7 +24,7 @@ var/message = sanitize(tgui_input_text(user,"Choose a message to relay to those around you.")) if(message) - audible_message("[bicon(src)] \The [src.name] states, \"[message]\"", runemessage = "synthesized speech") + audible_message("\icon[src][bicon(src)] \The [src.name] states, \"[message]\"", runemessage = "synthesized speech") if(ismob(loc)) loc.audible_message("", runemessage = "\[TTS Voice\] [message]") diff --git a/code/game/objects/items/devices/tvcamera.dm b/code/game/objects/items/devices/tvcamera.dm index 78f5a381c7..849a649894 100644 --- a/code/game/objects/items/devices/tvcamera.dm +++ b/code/game/objects/items/devices/tvcamera.dm @@ -48,7 +48,7 @@ add_fingerprint(user) user.set_machine(src) show_ui(user) - + /obj/item/device/tvcamera/proc/show_ui(mob/user) var/dat = list() dat += "Channel name is: [channel ? channel : "unidentified broadcast"]