Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into ninjasarecum
# Conflicts: # tgstation.dme
This commit is contained in:
@@ -13,11 +13,20 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup cache
|
||||
- name: Restore SpacemanDMM cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: $HOME/SpacemanDMM
|
||||
key: ${{ runner.os }}-spacemandmm
|
||||
path: ~/SpacemanDMM
|
||||
key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }}
|
||||
- name: Restore Yarn cache
|
||||
uses: actions/cache@v2
|
||||
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: Install Tools
|
||||
run: |
|
||||
pip3 install setuptools
|
||||
@@ -28,11 +37,10 @@ jobs:
|
||||
run: |
|
||||
bash tools/ci/check_filedirs.sh tgstation.dme
|
||||
bash tools/ci/check_changelogs.sh
|
||||
bash tools/ci/check_grep.sh
|
||||
find . -name "*.php" -print0 | xargs -0 -n1 php -l
|
||||
find . -name "*.json" -not -path "*/node_modules/*" -print0 | xargs -0 python3 ./tools/json_verifier.py
|
||||
tgui/bin/tgui --lint
|
||||
tgui/bin/tgui --test
|
||||
bash tools/ci/check_grep.sh
|
||||
tools/build/build --ci lint
|
||||
tools/bootstrap/python -m dmi.test
|
||||
tools/bootstrap/python -m mapmerge2.dmm_test
|
||||
~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1
|
||||
@@ -48,19 +56,16 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup cache
|
||||
- name: Restore BYOND cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: $HOME/BYOND
|
||||
key: ${{ runner.os }}-byond
|
||||
path: ~/BYOND
|
||||
key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }}
|
||||
- name: Compile All Maps
|
||||
run: |
|
||||
bash tools/ci/install_byond.sh
|
||||
source $HOME/BYOND/byond/bin/byondsetup
|
||||
python3 tools/ci/template_dm_generator.py
|
||||
tools/build/build
|
||||
env:
|
||||
CBT_BUILD_MODE : ALL_MAPS
|
||||
tools/build/build --ci dm -DCIBUILDING -DCITESTING -DALL_MAPS
|
||||
|
||||
run_all_tests:
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||
@@ -76,11 +81,20 @@ jobs:
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup cache
|
||||
- name: Restore BYOND cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: $HOME/BYOND
|
||||
key: ${{ runner.os }}-byond
|
||||
path: ~/BYOND
|
||||
key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }}
|
||||
- name: Restore Yarn cache
|
||||
uses: actions/cache@v2
|
||||
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: Setup database
|
||||
run: |
|
||||
sudo systemctl start mysql
|
||||
@@ -88,7 +102,7 @@ jobs:
|
||||
mysql -u root -proot tg_ci < SQL/tgstation_schema.sql
|
||||
mysql -u root -proot -e 'CREATE DATABASE tg_ci_prefixed;'
|
||||
mysql -u root -proot tg_ci_prefixed < SQL/tgstation_schema_prefixed.sql
|
||||
- name: Install rust dependencies
|
||||
- name: Install rust-g
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt update || true
|
||||
@@ -96,15 +110,14 @@ jobs:
|
||||
bash tools/ci/install_rust_g.sh
|
||||
- name: Install auxmos
|
||||
run: |
|
||||
sudo apt update || true
|
||||
bash tools/ci/install_auxmos.sh
|
||||
- name: Compile and run tests
|
||||
run: |
|
||||
bash tools/ci/install_byond.sh
|
||||
source $HOME/BYOND/byond/bin/byondsetup
|
||||
tools/build/build -DCIBUILDING
|
||||
tools/build/build --ci -DCIBUILDING
|
||||
bash tools/ci/run_server.sh
|
||||
env:
|
||||
CBT_BUILD_MODE: TEST_RUN
|
||||
|
||||
test_windows:
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||
@@ -112,6 +125,15 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Restore Yarn cache
|
||||
uses: actions/cache@v2
|
||||
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: Compile
|
||||
run: pwsh tools/ci/build.ps1
|
||||
env:
|
||||
|
||||
@@ -12,8 +12,8 @@ jobs:
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: $HOME/SpacemanDMM
|
||||
key: ${{ runner.os }}-spacemandmm
|
||||
path: ~/SpacemanDMM
|
||||
key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }}
|
||||
- name: Install SpacemanDMM
|
||||
run: bash tools/ci/install_spaceman_dmm.sh dmdoc
|
||||
- name: Generate documentation
|
||||
|
||||
+17
-59
@@ -7,14 +7,16 @@
|
||||
#Ignore byond config folder.
|
||||
/cfg/**/*
|
||||
|
||||
#Ignore rust-g and auxmos libraries which are compiled with scripts
|
||||
*.so
|
||||
/tools/build/binaries/**/*
|
||||
# Ignore compiled linux libs in the root folder, e.g. librust_g.so
|
||||
/*.so
|
||||
|
||||
#Ignore compiled files and other files generated during compilation.
|
||||
*.mdme
|
||||
*.mdme.*
|
||||
*.dmb
|
||||
*.rsc
|
||||
*.m.dme
|
||||
*.test.dme
|
||||
*.lk
|
||||
*.int
|
||||
*.backup
|
||||
@@ -53,27 +55,6 @@ __pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
#*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
@@ -81,8 +62,7 @@ var/
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
pip-*.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
@@ -92,7 +72,6 @@ htmlcov/
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
@@ -101,10 +80,6 @@ coverage.xml
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask instance folder
|
||||
instance/
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
@@ -112,9 +87,6 @@ instance/
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# IPython Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
@@ -127,10 +99,6 @@ celerybeat-schedule
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# IntelliJ IDEA / PyCharm (with plugin)
|
||||
.idea
|
||||
|
||||
@@ -153,12 +121,6 @@ Desktop.ini
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
#*.cab
|
||||
#*.msi
|
||||
#*.msm
|
||||
#*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
@@ -199,11 +161,10 @@ Temporary Items
|
||||
|
||||
#Visual studio stuff
|
||||
*.vscode/*
|
||||
!/.vscode/extensions.json
|
||||
tools/MapAtmosFixer/MapAtmosFixer/obj/*
|
||||
tools/MapAtmosFixer/MapAtmosFixer/bin/*
|
||||
tools/CreditsTool/bin/*
|
||||
tools/CreditsTool/obj/*
|
||||
/tools/MapAtmosFixer/MapAtmosFixer/obj/*
|
||||
/tools/MapAtmosFixer/MapAtmosFixer/bin/*
|
||||
/tools/CreditsTool/bin/*
|
||||
/tools/CreditsTool/obj/*
|
||||
|
||||
#GitHub Atom
|
||||
.atom-build.json
|
||||
@@ -228,13 +189,10 @@ tools/CreditsTool/obj/*
|
||||
!/config/title_screens/images/exclude
|
||||
|
||||
#Linux docker
|
||||
tools/LinuxOneShot/SetupProgram/obj/*
|
||||
tools/LinuxOneShot/SetupProgram/bin/*
|
||||
tools/LinuxOneShot/SetupProgram/.vs
|
||||
tools/LinuxOneShot/Database
|
||||
tools/LinuxOneShot/TGS_Config
|
||||
tools/LinuxOneShot/TGS_Instances
|
||||
tools/LinuxOneShot/TGS_Logs
|
||||
|
||||
# Common build tooling
|
||||
!/tools/build
|
||||
/tools/LinuxOneShot/SetupProgram/obj/*
|
||||
/tools/LinuxOneShot/SetupProgram/bin/*
|
||||
/tools/LinuxOneShot/SetupProgram/.vs
|
||||
/tools/LinuxOneShot/Database
|
||||
/tools/LinuxOneShot/TGS_Config
|
||||
/tools/LinuxOneShot/TGS_Instances
|
||||
/tools/LinuxOneShot/TGS_Logs
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
@call tools\build\build
|
||||
@pause
|
||||
@echo off
|
||||
call "%~dp0\tools\build\build.bat" %*
|
||||
pause
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
call "%~dp0\tools\build\build.bat" dist-clean
|
||||
pause
|
||||
@@ -1,7 +1,7 @@
|
||||
## Citadel Station 13
|
||||
Based and maintained from /tg/station.
|
||||
|
||||
[](https://travis-ci.org/Citadel-Station-13/Citadel-Station-13)
|
||||
[](https://github.com/Citadel-Station-13/Citadel-Station-13/actions?query=workflow%3A%22CI+Suite%22)
|
||||
[](http://isitmaintained.com/project/Citadel-Station-13/Citadel-Station-13 "Percentage of issues still open")
|
||||
[](http://isitmaintained.com/project/Citadel-Station-13/Citadel-Station-13 "Average time to resolve an issue")
|
||||
|
||||
@@ -100,6 +100,14 @@ install, overwriting when prompted except if we've specified otherwise, and
|
||||
recompile the game. Once you start the server up again, you should be running
|
||||
the new version.
|
||||
|
||||
## :exclamation: How to compile :exclamation:
|
||||
|
||||
On **2021-01-04** we have changed the way to compile the codebase.
|
||||
|
||||
Find `Build.cmd` in this folder, and double click it to initiate the build. It consists of multiple steps and might take around 1-5 minutes to compile. If it closes, it means it has finished its job. You can then setup the server normally by opening `tgstation.dmb` in DreamDaemon.
|
||||
|
||||
**Building tgstation in DreamMaker directly is now deprecated and might produce errors**, such as `'tgui.bundle.js': cannot find file`.
|
||||
|
||||
## HOSTING
|
||||
|
||||
If you'd like a more robust server hosting option for tgstation and its
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
call "%~dp0\tools\build\build.bat" server %*
|
||||
pause
|
||||
@@ -64,10 +64,6 @@
|
||||
/obj/item/paper/fluff/ruins/oldstation/protosing,
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/ruin/unpowered/buried_library)
|
||||
"av" = (
|
||||
/obj/structure/bookcase/random,
|
||||
/turf/open/space/basic,
|
||||
/area/ruin/unpowered/buried_library)
|
||||
"aw" = (
|
||||
/turf/open/floor/plating,
|
||||
/area/ruin/unpowered/buried_library)
|
||||
@@ -220,7 +216,6 @@
|
||||
/area/ruin/unpowered/buried_library)
|
||||
"bq" = (
|
||||
/obj/structure/mineral_door/wood,
|
||||
/obj/structure/barricade/wooden/crude/snow,
|
||||
/turf/open/floor/wood,
|
||||
/area/ruin/unpowered/buried_library)
|
||||
"br" = (
|
||||
@@ -369,7 +364,7 @@ bi
|
||||
aC
|
||||
ae
|
||||
aQ
|
||||
aq
|
||||
ah
|
||||
bi
|
||||
aq
|
||||
bg
|
||||
@@ -394,7 +389,7 @@ ae
|
||||
bi
|
||||
aM
|
||||
ae
|
||||
aq
|
||||
ah
|
||||
bm
|
||||
aq
|
||||
aA
|
||||
@@ -440,7 +435,7 @@ aa
|
||||
ad
|
||||
bi
|
||||
bi
|
||||
av
|
||||
aq
|
||||
aA
|
||||
bi
|
||||
aG
|
||||
@@ -465,7 +460,7 @@ aa
|
||||
ad
|
||||
ac
|
||||
as
|
||||
av
|
||||
aq
|
||||
aF
|
||||
aD
|
||||
aD
|
||||
@@ -550,7 +545,7 @@ aD
|
||||
bi
|
||||
ae
|
||||
bm
|
||||
ah
|
||||
aq
|
||||
ag
|
||||
br
|
||||
ac
|
||||
@@ -573,9 +568,9 @@ ae
|
||||
af
|
||||
bp
|
||||
bi
|
||||
ah
|
||||
aq
|
||||
bi
|
||||
ah
|
||||
aq
|
||||
bp
|
||||
ac
|
||||
ad
|
||||
@@ -596,9 +591,9 @@ ah
|
||||
ao
|
||||
ah
|
||||
az
|
||||
ah
|
||||
aq
|
||||
bi
|
||||
ah
|
||||
aq
|
||||
bi
|
||||
bn
|
||||
ao
|
||||
@@ -621,7 +616,7 @@ ah
|
||||
aA
|
||||
ah
|
||||
ao
|
||||
ah
|
||||
aq
|
||||
bi
|
||||
bi
|
||||
bl
|
||||
@@ -646,7 +641,7 @@ ah
|
||||
ao
|
||||
aV
|
||||
bi
|
||||
ah
|
||||
aq
|
||||
bp
|
||||
bi
|
||||
bm
|
||||
|
||||
@@ -53,8 +53,8 @@
|
||||
/turf/open/floor/wood,
|
||||
/area/ruin/unpowered)
|
||||
"m" = (
|
||||
/obj/structure/barricade/wooden/crude/snow,
|
||||
/obj/structure/mineral_door/wood,
|
||||
/obj/effect/decal/cleanable/trail_holder,
|
||||
/turf/open/floor/wood,
|
||||
/area/ruin/unpowered)
|
||||
"n" = (
|
||||
@@ -68,6 +68,7 @@
|
||||
/obj/machinery/light/broken{
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/decal/cleanable/trail_holder,
|
||||
/turf/open/floor/wood,
|
||||
/area/ruin/unpowered)
|
||||
"q" = (
|
||||
@@ -95,6 +96,10 @@
|
||||
/obj/effect/decal/cleanable/trail_holder,
|
||||
/turf/open/floor/wood,
|
||||
/area/ruin/unpowered)
|
||||
"N" = (
|
||||
/obj/effect/decal/cleanable/trail_holder,
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors)
|
||||
|
||||
(1,1,1) = {"
|
||||
i
|
||||
@@ -569,7 +574,7 @@ b
|
||||
l
|
||||
f
|
||||
f
|
||||
f
|
||||
s
|
||||
s
|
||||
b
|
||||
b
|
||||
@@ -595,7 +600,7 @@ b
|
||||
b
|
||||
b
|
||||
f
|
||||
f
|
||||
s
|
||||
p
|
||||
b
|
||||
b
|
||||
@@ -622,7 +627,7 @@ i
|
||||
b
|
||||
b
|
||||
b
|
||||
f
|
||||
s
|
||||
b
|
||||
b
|
||||
b
|
||||
@@ -649,7 +654,7 @@ i
|
||||
i
|
||||
i
|
||||
b
|
||||
f
|
||||
s
|
||||
b
|
||||
i
|
||||
i
|
||||
@@ -676,7 +681,7 @@ i
|
||||
i
|
||||
i
|
||||
b
|
||||
f
|
||||
s
|
||||
b
|
||||
i
|
||||
i
|
||||
@@ -703,7 +708,7 @@ i
|
||||
i
|
||||
i
|
||||
b
|
||||
f
|
||||
s
|
||||
b
|
||||
i
|
||||
i
|
||||
@@ -757,7 +762,7 @@ i
|
||||
i
|
||||
n
|
||||
h
|
||||
n
|
||||
N
|
||||
h
|
||||
n
|
||||
i
|
||||
|
||||
@@ -4408,7 +4408,7 @@
|
||||
/area/awaymission/cabin/caves)
|
||||
"lr" = (
|
||||
/obj/effect/decal/cleanable/blood/old,
|
||||
/obj/item/kitchen/knife/carrotshiv,
|
||||
/obj/item/kitchen/knife/shiv/carrot,
|
||||
/obj/effect/decal/cleanable/glitter/blue{
|
||||
desc = "It looks like fancy glitter to me.";
|
||||
name = "icy wind"
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
/obj/structure/mirror{
|
||||
pixel_y = 28
|
||||
},
|
||||
/turf/open/floor/wood,
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/awaymission/beach)
|
||||
"bd" = (
|
||||
/turf/open/floor/wood,
|
||||
@@ -312,7 +312,7 @@
|
||||
pixel_x = 24;
|
||||
specialfunctions = 4
|
||||
},
|
||||
/turf/open/floor/wood,
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/awaymission/beach)
|
||||
"bj" = (
|
||||
/obj/machinery/button/door{
|
||||
@@ -322,7 +322,7 @@
|
||||
pixel_x = -24;
|
||||
specialfunctions = 4
|
||||
},
|
||||
/turf/open/floor/wood,
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/awaymission/beach)
|
||||
"bk" = (
|
||||
/obj/structure/closet/secure_closet/personal/cabinet,
|
||||
@@ -392,14 +392,14 @@
|
||||
id_tag = "changlinhut2";
|
||||
name = "changing room"
|
||||
},
|
||||
/turf/open/floor/wood,
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/awaymission/beach)
|
||||
"bt" = (
|
||||
/obj/machinery/door/airlock/sandstone{
|
||||
id_tag = "changlinhut1";
|
||||
name = "changing room"
|
||||
},
|
||||
/turf/open/floor/wood,
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/awaymission/beach)
|
||||
"bu" = (
|
||||
/obj/item/reagent_containers/food/drinks/bottle/wine,
|
||||
@@ -477,9 +477,9 @@
|
||||
/turf/open/floor/plating/beach/sand,
|
||||
/area/awaymission/beach)
|
||||
"bF" = (
|
||||
/obj/structure/bedsheetbin,
|
||||
/obj/effect/turf_decal/sand,
|
||||
/obj/structure/table/wood,
|
||||
/obj/structure/bedsheetbin/towel,
|
||||
/turf/open/floor/plating/beach/sand,
|
||||
/area/awaymission/beach)
|
||||
"bG" = (
|
||||
@@ -773,7 +773,7 @@
|
||||
/area/awaymission/beach)
|
||||
"cv" = (
|
||||
/obj/effect/turf_decal/stripes/white/corner{
|
||||
dir = 4
|
||||
dir = 1
|
||||
},
|
||||
/turf/open/floor/plating/beach/sand,
|
||||
/area/awaymission/beach)
|
||||
@@ -1001,6 +1001,16 @@
|
||||
/obj/item/clothing/glasses/heat,
|
||||
/turf/open/floor/plating/beach/sand,
|
||||
/area/awaymission/beach)
|
||||
"iv" = (
|
||||
/obj/structure/dresser{
|
||||
density = 0;
|
||||
pixel_y = 18
|
||||
},
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/awaymission/beach)
|
||||
"kr" = (
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/awaymission/beach)
|
||||
"np" = (
|
||||
/obj/machinery/shower{
|
||||
dir = 8
|
||||
@@ -7586,8 +7596,8 @@ ak
|
||||
ak
|
||||
ak
|
||||
aX
|
||||
bb
|
||||
bd
|
||||
iv
|
||||
kr
|
||||
aX
|
||||
ak
|
||||
ba
|
||||
@@ -8442,7 +8452,7 @@ aJ
|
||||
aE
|
||||
ak
|
||||
aX
|
||||
bb
|
||||
iv
|
||||
bj
|
||||
bt
|
||||
ba
|
||||
@@ -8550,7 +8560,7 @@ ak
|
||||
aS
|
||||
aX
|
||||
bc
|
||||
bd
|
||||
kr
|
||||
aX
|
||||
ak
|
||||
ba
|
||||
@@ -9090,7 +9100,7 @@ ak
|
||||
ak
|
||||
ba
|
||||
ba
|
||||
ak
|
||||
bF
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
|
||||
+6393
-2211
File diff suppressed because it is too large
Load Diff
@@ -9962,6 +9962,7 @@
|
||||
/area/security/prison)
|
||||
"axk" = (
|
||||
/obj/item/storage/pill_bottle/penis_enlargement,
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel/freezer,
|
||||
/area/security/prison)
|
||||
"axl" = (
|
||||
@@ -71005,6 +71006,11 @@
|
||||
/obj/machinery/atmospherics/pipe/simple/violet/visible,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engineering/atmos)
|
||||
"kTm" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plating,
|
||||
/area/security/prison)
|
||||
"lcD" = (
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/freezer{
|
||||
dir = 1
|
||||
@@ -71078,6 +71084,11 @@
|
||||
/obj/machinery/atmospherics/pipe/simple/orange/hidden,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/tcommsat/computer)
|
||||
"mTf" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"nvn" = (
|
||||
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
|
||||
dir = 1
|
||||
@@ -95879,7 +95890,7 @@ adE
|
||||
aew
|
||||
afG
|
||||
agP
|
||||
agP
|
||||
kTm
|
||||
aiL
|
||||
ajT
|
||||
anu
|
||||
@@ -95894,7 +95905,7 @@ aHT
|
||||
aJt
|
||||
aJN
|
||||
aQg
|
||||
akv
|
||||
mTf
|
||||
aew
|
||||
ayU
|
||||
aSQ
|
||||
@@ -96395,7 +96406,7 @@ afY
|
||||
agP
|
||||
agP
|
||||
aiL
|
||||
akv
|
||||
mTf
|
||||
anw
|
||||
akv
|
||||
akv
|
||||
|
||||
@@ -10552,6 +10552,7 @@
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"aMj" = (
|
||||
@@ -12412,6 +12413,7 @@
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 8
|
||||
},
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"aUx" = (
|
||||
@@ -12458,6 +12460,7 @@
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 8
|
||||
},
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"aUA" = (
|
||||
@@ -12486,6 +12489,7 @@
|
||||
/area/security/prison)
|
||||
"aUB" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plating{
|
||||
icon_state = "panelscorched"
|
||||
},
|
||||
|
||||
@@ -55924,6 +55924,7 @@
|
||||
dir = 1;
|
||||
pixel_y = -22
|
||||
},
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel/showroomfloor,
|
||||
/area/security/prison)
|
||||
"bLR" = (
|
||||
@@ -59245,6 +59246,7 @@
|
||||
dir = 1;
|
||||
pixel_y = -22
|
||||
},
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel/showroomfloor,
|
||||
/area/security/prison)
|
||||
"bRc" = (
|
||||
@@ -61866,6 +61868,7 @@
|
||||
/obj/structure/cable{
|
||||
icon_state = "4-8"
|
||||
},
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel/showroomfloor,
|
||||
/area/security/prison)
|
||||
"bVq" = (
|
||||
@@ -79329,6 +79332,7 @@
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/turf_decal/tile/neutral,
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/security/prison)
|
||||
"czS" = (
|
||||
|
||||
@@ -443,6 +443,7 @@
|
||||
/obj/structure/cable{
|
||||
icon_state = "1-2"
|
||||
},
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"abr" = (
|
||||
@@ -63052,6 +63053,11 @@
|
||||
},
|
||||
/turf/open/space/basic,
|
||||
/area/space)
|
||||
"cZI" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"dcB" = (
|
||||
/obj/effect/turf_decal/trimline/neutral/filled/line{
|
||||
dir = 4
|
||||
@@ -112428,7 +112434,7 @@ agJ
|
||||
ahA
|
||||
ady
|
||||
bPZ
|
||||
adx
|
||||
cZI
|
||||
adx
|
||||
ama
|
||||
aNh
|
||||
@@ -113456,7 +113462,7 @@ afg
|
||||
agM
|
||||
ady
|
||||
ajM
|
||||
adx
|
||||
cZI
|
||||
adx
|
||||
asb
|
||||
baj
|
||||
@@ -115255,7 +115261,7 @@ amN
|
||||
agQ
|
||||
ady
|
||||
aiu
|
||||
adx
|
||||
cZI
|
||||
adx
|
||||
amc
|
||||
beg
|
||||
|
||||
@@ -1344,6 +1344,7 @@
|
||||
icon_state = "1-2"
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"adw" = (
|
||||
@@ -45097,6 +45098,10 @@
|
||||
/obj/effect/landmark/start/scientist,
|
||||
/turf/open/floor/plasteel/white,
|
||||
/area/science/xenobiology)
|
||||
"cUU" = (
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"cUZ" = (
|
||||
/obj/docking_port/stationary{
|
||||
dir = 8;
|
||||
@@ -81318,6 +81323,13 @@
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/command/bridge)
|
||||
"wXA" = (
|
||||
/obj/structure/cable/yellow{
|
||||
icon_state = "4-8"
|
||||
},
|
||||
/obj/effect/landmark/start/prisoner,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"wXC" = (
|
||||
/obj/machinery/light_switch{
|
||||
pixel_y = 28
|
||||
@@ -105902,7 +105914,7 @@ abC
|
||||
acr
|
||||
acE
|
||||
adb
|
||||
aaR
|
||||
cUU
|
||||
aaR
|
||||
aem
|
||||
aeN
|
||||
@@ -107181,7 +107193,7 @@ aaC
|
||||
aaI
|
||||
aaR
|
||||
abb
|
||||
aaI
|
||||
wXA
|
||||
abG
|
||||
acb
|
||||
acu
|
||||
@@ -107958,7 +107970,7 @@ aaR
|
||||
aaR
|
||||
aaR
|
||||
ade
|
||||
aaR
|
||||
cUU
|
||||
aaR
|
||||
aeo
|
||||
aeV
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -15,6 +15,7 @@
|
||||
#define BLOCK_Z_IN_UP (1<<12) // Should this object block z uprise from below?
|
||||
#define SHOVABLE_ONTO (1<<13)//called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check.
|
||||
#define EXAMINE_SKIP (1<<14) /// Makes the Examine proc not read out this item.
|
||||
#define IN_STORAGE (1<<15) //is this item in the storage item, such as backpack? used for tooltips
|
||||
|
||||
/// Integrity defines for clothing (not flags but close enough)
|
||||
#define CLOTHING_PRISTINE 0 // We have no damage on the clothing
|
||||
|
||||
@@ -155,10 +155,10 @@
|
||||
|
||||
//LAVALAND
|
||||
#define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland
|
||||
#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300"
|
||||
#define LAVALAND_DEFAULT_ATMOS "LAVALAND_ATMOS"
|
||||
|
||||
//SNOSTATION
|
||||
#define ICEMOON_DEFAULT_ATMOS "o2=17;n2=63;TEMP=180"
|
||||
#define ICEMOON_DEFAULT_ATMOS "ICEMOON_ATMOS"
|
||||
|
||||
//ATMOSIA GAS MONITOR TAGS
|
||||
#define ATMOS_GAS_MONITOR_INPUT_O2 "o2_in"
|
||||
|
||||
@@ -437,8 +437,9 @@
|
||||
#define COMPONENT_BLOCK_SHARPEN_BLOCKED 2
|
||||
#define COMPONENT_BLOCK_SHARPEN_ALREADY 4
|
||||
#define COMPONENT_BLOCK_SHARPEN_MAXED 8
|
||||
#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" //called on item when microwaved (): (obj/machinery/microwave/M)
|
||||
#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" //called on item when microwaved (): (obj/machinery/microwave/M)
|
||||
#define COMSIG_ITEM_WORN_OVERLAYS "item_worn_overlays" //from base of obj/item/worn_overlays(): (isinhands, icon_file, used_state, style_flags, list/overlays)
|
||||
#define COMSIG_ARMOR_PLATED "armor_plated" //called when an armor plate is successfully applied to an object
|
||||
// THE FOLLOWING TWO BLOCKS SHOULD RETURN BLOCK FLAGS AS DEFINED IN __DEFINES/combat.dm!
|
||||
#define COMSIG_ITEM_CHECK_BLOCK "check_block" //from base of obj/item/check_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
#define COMSIG_ITEM_RUN_BLOCK "run_block" //from base of obj/item/run_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define FOOTSTEP_LAVA "lava"
|
||||
#define FOOTSTEP_MEAT "meat"
|
||||
#define FOOTSTEP_RUST "rust"
|
||||
#define FOOTSTEP_CATWALK "catwalk"
|
||||
|
||||
//barefoot sounds
|
||||
#define FOOTSTEP_WOOD_BAREFOOT "woodbarefoot"
|
||||
@@ -94,6 +95,12 @@ GLOBAL_LIST_INIT(footstep, list(
|
||||
'sound/effects/footstep/lava3.ogg'), 100, 0),
|
||||
FOOTSTEP_MEAT = list(list(
|
||||
'sound/effects/meatslap.ogg'), 100, 0),
|
||||
FOOTSTEP_CATWALK = list(list(
|
||||
'sound/effects/footstep/catwalk1.ogg',
|
||||
'sound/effects/footstep/catwalk2.ogg',
|
||||
'sound/effects/footstep/catwalk3.ogg',
|
||||
'sound/effects/footstep/catwalk4.ogg',
|
||||
'sound/effects/footstep/catwalk5.ogg'), 100, 1),
|
||||
FOOTSTEP_RUST = list(list(
|
||||
'sound/effects/footstep/rustystep1.ogg'), 100, 0)
|
||||
))
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#define CLOWN (1<<11)
|
||||
#define MIME (1<<12)
|
||||
#define ASSISTANT (1<<13)
|
||||
#define PRISONER (1<<14)
|
||||
|
||||
#define JOB_AVAILABLE 0
|
||||
#define JOB_UNAVAILABLE_GENERIC 1
|
||||
@@ -89,3 +90,4 @@
|
||||
#define JOB_DISPLAY_ORDER_WARDEN 31
|
||||
#define JOB_DISPLAY_ORDER_DETECTIVE 32
|
||||
#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 33
|
||||
#define JOB_DISPLAY_ORDER_PRISONER 34
|
||||
|
||||
@@ -64,8 +64,9 @@
|
||||
#define GAS_PIPE_VISIBLE_LAYER 2.47
|
||||
#define GAS_FILTER_LAYER 2.48
|
||||
#define GAS_PUMP_LAYER 2.49
|
||||
|
||||
#define LOW_OBJ_LAYER 2.5
|
||||
///catwalk overlay of /turf/open/floor/plating/plating_catwalk
|
||||
#define CATWALK_LAYER 2.51
|
||||
#define LOW_SIGIL_LAYER 2.52
|
||||
#define SIGIL_LAYER 2.54
|
||||
#define HIGH_SIGIL_LAYER 2.56
|
||||
|
||||
@@ -347,3 +347,7 @@
|
||||
// / Breathing types. Lungs can access either by these or by a string, which will be considered a gas ID.
|
||||
#define BREATH_OXY /datum/breathing_class/oxygen
|
||||
#define BREATH_PLASMA /datum/breathing_class/plasma
|
||||
|
||||
//Gremlins
|
||||
#define NPC_TAMPER_ACT_FORGET 1 //Don't try to tamper with this again
|
||||
#define NPC_TAMPER_ACT_NOMSG 2 //Don't produce a visible message
|
||||
|
||||
+28
-14
@@ -1,30 +1,44 @@
|
||||
//defines that give qdel hints. these can be given as a return in destory() or by calling
|
||||
//! Defines that give qdel hints.
|
||||
//!
|
||||
//! These can be given as a return in [/atom/proc/Destroy] or by calling [/proc/qdel].
|
||||
|
||||
/// `qdel` should queue the object for deletion.
|
||||
#define QDEL_HINT_QUEUE 0
|
||||
/// `qdel` should let the object live after calling [/atom/proc/Destroy].
|
||||
#define QDEL_HINT_LETMELIVE 1
|
||||
/// Functionally the same as the above. `qdel` should assume the object will gc on its own, and not check it.
|
||||
#define QDEL_HINT_IWILLGC 2
|
||||
/// Qdel should assume this object won't GC, and queue a hard delete using a hard reference.
|
||||
#define QDEL_HINT_HARDDEL 3
|
||||
// Qdel should assume this object won't gc, and hard delete it posthaste.
|
||||
#define QDEL_HINT_HARDDEL_NOW 4
|
||||
|
||||
|
||||
#define QDEL_HINT_QUEUE 0 //qdel should queue the object for deletion.
|
||||
#define QDEL_HINT_LETMELIVE 1 //qdel should let the object live after calling destory.
|
||||
#define QDEL_HINT_IWILLGC 2 //functionally the same as the above. qdel should assume the object will gc on its own, and not check it.
|
||||
#define QDEL_HINT_HARDDEL 3 //qdel should assume this object won't gc, and queue a hard delete using a hard reference.
|
||||
#define QDEL_HINT_HARDDEL_NOW 4 //qdel should assume this object won't gc, and hard del it post haste.
|
||||
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
/** If LEGACY_REFERENCE_TRACKING is enabled, qdel will call this object's find_references() verb.
|
||||
*
|
||||
* Functionally identical to QDEL_HINT_QUEUE if GC_FAILURE_HARD_LOOKUP is not enabled in _compiler_options.dm.
|
||||
#ifdef REFERENCE_TRACKING
|
||||
/** If REFERENCE_TRACKING is enabled, qdel will call this object's find_references() verb.
|
||||
*
|
||||
* Functionally identical to [QDEL_HINT_QUEUE] if [GC_FAILURE_HARD_LOOKUP] is not enabled in _compiler_options.dm.
|
||||
*/
|
||||
#define QDEL_HINT_FINDREFERENCE 5
|
||||
/// Behavior as QDEL_HINT_FINDREFERENCE, but only if the GC fails and a hard delete is forced.
|
||||
#define QDEL_HINT_FINDREFERENCE 5
|
||||
/// Behavior as [QDEL_HINT_FINDREFERENCE], but only if the GC fails and a hard delete is forced.
|
||||
#define QDEL_HINT_IFFAIL_FINDREFERENCE 6
|
||||
#endif
|
||||
|
||||
|
||||
#define GC_QUEUE_CHECK 1
|
||||
#define GC_QUEUE_HARDDELETE 2
|
||||
#define GC_QUEUE_COUNT 2 //increase this when adding more steps.
|
||||
|
||||
#define QDEL_ITEM_ADMINS_WARNED (1<<0) //! Set when admins are told about lag causing qdels in this type.
|
||||
#define QDEL_ITEM_SUSPENDED_FOR_LAG (1<<1) //! Set when a type can no longer be hard deleted on failure because of lag it causes while this happens.
|
||||
|
||||
// Defines for the [gc_destroyed][/datum/var/gc_destroyed] var.
|
||||
#define GC_QUEUED_FOR_QUEUING -1
|
||||
#define GC_CURRENTLY_BEING_QDELETED -2
|
||||
|
||||
// Defines for the time left for an item to get its reference cleaned
|
||||
#define GC_FILTER_QUEUE 5 MINUTES
|
||||
#define GC_DEL_QUEUE 10 SECONDS
|
||||
|
||||
#define QDELING(X) (X.gc_destroyed)
|
||||
#define QDELETED(X) (!X || QDELING(X))
|
||||
#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
|
||||
@@ -76,3 +76,8 @@
|
||||
//Chemical reaction flags, for determining reaction specialties
|
||||
#define REACTION_CLEAR_IMPURE (1<<0) //Convert into impure/pure on reaction completion
|
||||
#define REACTION_CLEAR_INVERSE (1<<1) //Convert into inverse on reaction completion when purity is low enough
|
||||
|
||||
//Chemical blacklists for smartdarts
|
||||
GLOBAL_LIST_INIT(blacklisted_medchems, list(
|
||||
/datum/reagent/medicine/morphine, /datum/reagent/medicine/haloperidol, //harmful chemicals in medicine
|
||||
))
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
#define RUST_G (__rust_g || __detect_rust_g())
|
||||
#endif
|
||||
|
||||
/// Gets the version of rust_g
|
||||
/proc/rustg_get_version() return call(RUST_G, "get_version")()
|
||||
|
||||
/**
|
||||
* This proc generates a cellular automata noise grid which can be used in procedural generation methods.
|
||||
*
|
||||
@@ -77,8 +80,8 @@
|
||||
#define RUSTG_HTTP_METHOD_PATCH "patch"
|
||||
#define RUSTG_HTTP_METHOD_HEAD "head"
|
||||
#define RUSTG_HTTP_METHOD_POST "post"
|
||||
#define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers)
|
||||
#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers)
|
||||
#define rustg_http_request_blocking(method, url, body, headers, options) call(RUST_G, "http_request_blocking")(method, url, body, headers, options)
|
||||
#define rustg_http_request_async(method, url, body, headers, options) call(RUST_G, "http_request_async")(method, url, body, headers, options)
|
||||
#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id)
|
||||
|
||||
#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
|
||||
@@ -99,3 +102,11 @@
|
||||
#define rustg_sql_disconnect_pool(handle) call(RUST_G, "sql_disconnect_pool")(handle)
|
||||
#define rustg_sql_check_query(job_id) call(RUST_G, "sql_check_query")("[job_id]")
|
||||
|
||||
#define rustg_url_encode(text) call(RUST_G, "url_encode")(text)
|
||||
#define rustg_url_decode(text) call(RUST_G, "url_decode")(text)
|
||||
|
||||
#ifdef RUSTG_OVERRIDE_BUILTINS
|
||||
#define url_encode(text) rustg_url_encode(text)
|
||||
#define url_decode(text) rustg_url_decode(text)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
// RUSTG_OVERRIDE_BUILTINS is not used since the file APIs don't work well over Linux.
|
||||
#define url_encode(text) rustg_url_encode("[text]")
|
||||
#define url_decode(text) rustg_url_decode("[text]")
|
||||
@@ -49,10 +49,16 @@ When using time2text(), please use "DDD" to find the weekday. Refrain from using
|
||||
|
||||
#define TICKS *world.tick_lag
|
||||
|
||||
#define MILLISECONDS * 0.01
|
||||
|
||||
#define DS2TICKS(DS) ((DS)/world.tick_lag)
|
||||
|
||||
#define TICKS2DS(T) ((T) TICKS)
|
||||
|
||||
#define MS2DS(T) ((T) MILLISECONDS)
|
||||
|
||||
#define DS2MS(T) ((T) * 100)
|
||||
|
||||
#define GAMETIMESTAMP(format, wtime) time2text(wtime, format)
|
||||
#define WORLDTIME2TEXT(format) GAMETIMESTAMP(format, world.time)
|
||||
#define WORLDTIMEOFDAY2TEXT(format) GAMETIMESTAMP(format, world.timeofday)
|
||||
|
||||
@@ -343,3 +343,9 @@
|
||||
#define STICKY_NODROP "sticky-nodrop" //sticky nodrop sounds like a bad soundcloud rapper's name
|
||||
#define TRAIT_SACRIFICED "sacrificed" //Makes sure that people cant be cult sacrificed twice.
|
||||
#define TRAIT_SPACEWALK "spacewalk"
|
||||
|
||||
|
||||
/// obtained from mapping helper
|
||||
#define MAPPING_HELPER_TRAIT "mapping-helper"
|
||||
/// Trait associated with mafia
|
||||
#define MAFIA_TRAIT "mafia"
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
//wrapper macros for easier grepping
|
||||
#define DIRECT_OUTPUT(A, B) A << B
|
||||
#define DIRECT_INPUT(A, B) A >> B
|
||||
#define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image)
|
||||
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
|
||||
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
|
||||
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
|
||||
#define READ_FILE(file, text) DIRECT_INPUT(file, text)
|
||||
|
||||
#ifdef EXTOOLS_LOGGING
|
||||
// proc hooked, so we can just put in standard TRUE and FALSE
|
||||
#define WRITE_LOG(log, text) extools_log_write(log,text,TRUE)
|
||||
@@ -13,6 +16,7 @@
|
||||
#define WRITE_LOG(log, text) rustg_log_write(log, text, "true")
|
||||
#define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false")
|
||||
#endif
|
||||
|
||||
//print a warning message to world.log
|
||||
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [UNLINT(src)] usr: [usr].")
|
||||
/proc/warning(msg)
|
||||
@@ -38,6 +42,12 @@
|
||||
SEND_TEXT(world.log, text)
|
||||
#endif
|
||||
|
||||
#ifdef REFERENCE_TRACKING_LOG
|
||||
#define log_reftracker(msg) log_world("## REF SEARCH [msg]")
|
||||
#else
|
||||
#define log_reftracker(msg)
|
||||
#endif
|
||||
|
||||
|
||||
/* Items with ADMINPRIVATE prefixed are stripped from public logs. */
|
||||
/proc/log_admin(text)
|
||||
|
||||
@@ -78,6 +78,12 @@
|
||||
var/datum/emote/E = new path()
|
||||
E.emote_list[E.key] = E
|
||||
|
||||
// Hair Gradients - Initialise all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name
|
||||
for(var/path in subtypesof(/datum/sprite_accessory/hair_gradient))
|
||||
var/datum/sprite_accessory/hair_gradient/H = new path()
|
||||
GLOB.hair_gradients_list[H.name] = H
|
||||
|
||||
// Keybindings
|
||||
init_keybindings()
|
||||
|
||||
//Uplink Items
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#define MAXIMUM_MARKOV_LENGTH 25000
|
||||
|
||||
/proc/markov_chain(var/text, var/order = 4, var/length = 250)
|
||||
if(!text || order < 0 || order > 20 || length < 1 || length > MAXIMUM_MARKOV_LENGTH)
|
||||
return
|
||||
|
||||
var/table = markov_table(text, order)
|
||||
var/markov = markov_text(length, table, order)
|
||||
return markov
|
||||
|
||||
/proc/markov_table(var/text, var/look_forward = 4)
|
||||
if(!text)
|
||||
return
|
||||
var/list/table = list()
|
||||
|
||||
for(var/i = 1, i <= length(text), i++)
|
||||
var/char = copytext(text, i, look_forward+i)
|
||||
if(!table[char])
|
||||
table[char] = list()
|
||||
|
||||
for(var/i = 1, i <= (length(text) - look_forward), i++)
|
||||
var/char_index = copytext(text, i, look_forward+i)
|
||||
var/char_count = copytext(text, i+look_forward, (look_forward*2)+i)
|
||||
|
||||
if(table[char_index][char_count])
|
||||
table[char_index][char_count]++
|
||||
else
|
||||
table[char_index][char_count] = 1
|
||||
|
||||
return table
|
||||
|
||||
/proc/markov_text(var/length = 250, var/table, var/look_forward = 4)
|
||||
if(!table)
|
||||
return
|
||||
var/char = pick(table)
|
||||
var/o = char
|
||||
|
||||
for(var/i = 0, i <= (length / look_forward), i++)
|
||||
var/newchar = markov_weighted_char(table[char])
|
||||
|
||||
if(newchar)
|
||||
char = newchar
|
||||
o += "[newchar]"
|
||||
else
|
||||
char = pick(table)
|
||||
|
||||
return o
|
||||
|
||||
/proc/markov_weighted_char(var/list/array)
|
||||
if(!array || !array.len)
|
||||
return
|
||||
|
||||
var/total = 0
|
||||
for(var/i in array)
|
||||
total += array[i]
|
||||
var/r = rand(1, total)
|
||||
for(var/i in array)
|
||||
var/weight = array[i]
|
||||
if(r <= weight)
|
||||
return i
|
||||
r -= weight
|
||||
+13
-13
@@ -218,20 +218,14 @@
|
||||
|
||||
to_chat(world, "<BR><BR><BR><span class='big bold'>The round has ended.</span>")
|
||||
log_game("The round has ended.")
|
||||
if(LAZYLEN(GLOB.round_end_notifiees))
|
||||
world.TgsTargetedChatBroadcast("[GLOB.round_end_notifiees.Join(", ")] the round has ended.", FALSE)
|
||||
|
||||
CONFIG_SET(flag/suicide_allowed,TRUE) // EORG suicides allowed
|
||||
|
||||
for(var/I in round_end_events)
|
||||
var/datum/callback/cb = I
|
||||
cb.InvokeAsync()
|
||||
LAZYCLEARLIST(round_end_events)
|
||||
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(!C.credits)
|
||||
C.RollCredits()
|
||||
C.playtitlemusic(40)
|
||||
CONFIG_SET(flag/suicide_allowed,TRUE) // EORG suicides allowed
|
||||
|
||||
var/speed_round = FALSE
|
||||
if(world.time - SSticker.round_start_time <= 300 SECONDS)
|
||||
speed_round = TRUE
|
||||
@@ -264,12 +258,15 @@
|
||||
|
||||
send2adminchat("Server", "A round of [mode.name] just ended[mode_result == "undefined" ? "." : " with a [mode_result]."] Survival rate: [survival_rate]")
|
||||
|
||||
if(LAZYLEN(GLOB.round_end_notifiees))
|
||||
world.TgsTargetedChatBroadcast("[GLOB.round_end_notifiees.Join(", ")] the round has ended.", FALSE)
|
||||
|
||||
if(length(CONFIG_GET(keyed_list/cross_server)))
|
||||
send_news_report()
|
||||
|
||||
//tell the nice people on discord what went on before the salt cannon happens.
|
||||
world.TgsTargetedChatBroadcast("The current round has ended. Please standby for your shift interlude Nanotrasen News Network's report!", FALSE)
|
||||
world.TgsTargetedChatBroadcast(send_news_report(),FALSE)
|
||||
world.TgsTargetedChatBroadcast(send_news_report(), FALSE)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
@@ -543,21 +540,24 @@
|
||||
///Generate a report for how much money is on station, as well as the richest crewmember on the station.
|
||||
/datum/controller/subsystem/ticker/proc/market_report()
|
||||
var/list/parts = list()
|
||||
parts += "<span class='header'>Station Economic Summary:</span>"
|
||||
|
||||
///This is the richest account on station at roundend.
|
||||
var/datum/bank_account/mr_moneybags
|
||||
///This is the station's total wealth at the end of the round.
|
||||
var/station_vault = 0
|
||||
///How many players joined the round.
|
||||
var/total_players = GLOB.joined_player_list.len
|
||||
var/list/typecache_bank = typecacheof(list(/datum/bank_account/department, /datum/bank_account/remote))
|
||||
for(var/datum/bank_account/current_acc in SSeconomy.generated_accounts)
|
||||
var/static/list/typecache_bank = typecacheof(list(/datum/bank_account/department, /datum/bank_account/remote))
|
||||
for(var/i in SSeconomy.generated_accounts)
|
||||
var/datum/bank_account/current_acc = SSeconomy.generated_accounts[i]
|
||||
if(typecache_bank[current_acc.type])
|
||||
continue
|
||||
station_vault += current_acc.account_balance
|
||||
if(!mr_moneybags || mr_moneybags.account_balance < current_acc.account_balance)
|
||||
mr_moneybags = current_acc
|
||||
parts += "<div class='panel stationborder'>There were [station_vault] credits collected by crew this shift.<br>"
|
||||
parts += "<div class='panel stationborder'><span class='header'>Station Economic Summary:</span><br>"
|
||||
parts += "<b>General Statistics:</b><br>"
|
||||
parts += "There were [station_vault] credits collected by crew this shift.<br>"
|
||||
if(total_players > 0)
|
||||
parts += "An average of [station_vault/total_players] credits were collected.<br>"
|
||||
// log_econ("Roundend credit total: [station_vault] credits. Average Credits: [station_vault/total_players]")
|
||||
|
||||
+47
-23
@@ -1,7 +1,7 @@
|
||||
//#define TESTING //By using the testing("message") proc you can create debug-feedback for people with this
|
||||
//#define TESTING //By using the testing("message") proc you can create debug-feedback for people with this
|
||||
//uncommented, but not visible in the release version)
|
||||
|
||||
//#define DATUMVAR_DEBUGGING_MODE //Enables the ability to cache datum vars and retrieve later for debugging which vars changed.
|
||||
//#define DATUMVAR_DEBUGGING_MODE //Enables the ability to cache datum vars and retrieve later for debugging which vars changed.
|
||||
|
||||
// Comment this out if you are debugging problems that might be obscured by custom error handling in world/Error
|
||||
#ifdef DEBUG
|
||||
@@ -11,34 +11,44 @@
|
||||
#ifdef TESTING
|
||||
#define DATUMVAR_DEBUGGING_MODE
|
||||
|
||||
/*
|
||||
* Enables extools-powered reference tracking system, letting you see what is referencing objects that refuse to hard delete.
|
||||
*
|
||||
* * Requires TESTING to be defined to work.
|
||||
*/
|
||||
///Used to find the sources of harddels, quite laggy, don't be surpised if it freezes your client for a good while
|
||||
//#define REFERENCE_TRACKING
|
||||
#ifdef REFERENCE_TRACKING
|
||||
|
||||
///Method of tracking references without using extools. Slower, kept to avoid over-reliance on extools.
|
||||
//#define LEGACY_REFERENCE_TRACKING
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
///alternate to reftracking, extool variant
|
||||
//#define EXTOOLS_REFERENCE_TRACKING
|
||||
|
||||
///Use the legacy reference on things hard deleting by default.
|
||||
///Should we be logging our findings or not
|
||||
#define REFERENCE_TRACKING_LOG
|
||||
|
||||
///Used for doing dry runs of the reference finder, to test for feature completeness
|
||||
//#define REFERENCE_TRACKING_DEBUG
|
||||
|
||||
///Run a lookup on things hard deleting by default.
|
||||
//#define GC_FAILURE_HARD_LOOKUP
|
||||
#ifdef GC_FAILURE_HARD_LOOKUP
|
||||
#define FIND_REF_NO_CHECK_TICK
|
||||
#endif //ifdef GC_FAILURE_HARD_LOOKUP
|
||||
|
||||
#endif //ifdef LEGACY_REFERENCE_TRACKING
|
||||
#endif //ifdef REFERENCE_TRACKING
|
||||
|
||||
//#define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green
|
||||
/*
|
||||
* Enables debug messages for every single reaction step. This is 1 message per 0.5s for a SINGLE reaction. Useful for tracking down bugs/asking me for help in the main reaction handiler (equilibrium.dm).
|
||||
*
|
||||
* * Requires TESTING to be defined to work.
|
||||
*/
|
||||
//#define REAGENTS_TESTING
|
||||
|
||||
// #define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green
|
||||
// #define TRACK_MAX_SHARE //Allows max share tracking, for use in the atmos debugging ui
|
||||
#endif //ifdef TESTING
|
||||
//#define UNIT_TESTS //Enables unit tests via TEST_RUN_PARAMETER
|
||||
|
||||
#ifndef PRELOAD_RSC //set to:
|
||||
#define PRELOAD_RSC 2 // 0 to allow using external resources or on-demand behaviour;
|
||||
#endif // 1 to use the default behaviour;
|
||||
// 2 for preloading absolutely everything;
|
||||
//#define UNIT_TESTS //If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between
|
||||
|
||||
#ifndef PRELOAD_RSC //set to:
|
||||
#define PRELOAD_RSC 2 // 0 to allow using external resources or on-demand behaviour;
|
||||
#endif // 1 to use the default behaviour;
|
||||
// 2 for preloading absolutely everything;
|
||||
|
||||
#ifdef LOWMEMORYMODE
|
||||
#define FORCE_MAP "_maps/runtimestation.json"
|
||||
@@ -47,7 +57,7 @@
|
||||
//Update this whenever you need to take advantage of more recent byond features
|
||||
#define MIN_COMPILER_VERSION 513
|
||||
#define MIN_COMPILER_BUILD 1514
|
||||
#if DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD
|
||||
#if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM)
|
||||
//Don't forget to update this part
|
||||
#error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update.
|
||||
#error You need version 513.1514 or higher
|
||||
@@ -58,10 +68,6 @@
|
||||
#warn compiling in TESTING mode. testing() debug messages will be visible.
|
||||
#endif
|
||||
|
||||
#ifdef GC_FAILURE_HARD_LOOKUP
|
||||
#define FIND_REF_NO_CHECK_TICK
|
||||
#endif
|
||||
|
||||
#ifdef CIBUILDING
|
||||
#define UNIT_TESTS
|
||||
#endif
|
||||
@@ -70,6 +76,24 @@
|
||||
#define TESTING
|
||||
#endif
|
||||
|
||||
#if defined(UNIT_TESTS)
|
||||
//Hard del testing defines
|
||||
#define REFERENCE_TRACKING
|
||||
#define REFERENCE_TRACKING_DEBUG
|
||||
#define FIND_REF_NO_CHECK_TICK
|
||||
#endif
|
||||
|
||||
#ifdef TGS
|
||||
// TGS performs its own build of dm.exe, but includes a prepended TGS define.
|
||||
#define CBT
|
||||
#endif
|
||||
|
||||
// A reasonable number of maximum overlays an object needs
|
||||
// If you think you need more, rethink it
|
||||
#define MAX_ATOM_OVERLAYS 100
|
||||
|
||||
#if !defined(CBT) && !defined(SPACEMAN_DMM)
|
||||
#warn Building with Dream Maker is no longer supported and will result in errors.
|
||||
#warn In order to build, run BUILD.bat in the root directory.
|
||||
#warn Consider switching to VSCode editor instead, where you can press Ctrl+Shift+B to build.
|
||||
#endif
|
||||
|
||||
@@ -71,6 +71,7 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
"DROPDEL" = DROPDEL,
|
||||
"NOBLUDGEON" = NOBLUDGEON,
|
||||
"ABSTRACT" = ABSTRACT,
|
||||
"IN_STORAGE" = IN_STORAGE,
|
||||
"ITEM_CAN_BLOCK" = ITEM_CAN_BLOCK,
|
||||
"ITEM_CAN_PARRY" = ITEM_CAN_PARRY
|
||||
),
|
||||
|
||||
@@ -6,6 +6,7 @@ GLOBAL_LIST_EMPTY(hair_styles_female_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_list) //stores /datum/sprite_accessory/facial_hair indexed by name
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_male_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_female_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(hair_gradients_list) //stores /datum/sprite_accessory/hair_gradient indexed by name
|
||||
//Underwear
|
||||
GLOBAL_LIST_EMPTY_TYPED(underwear_list, /datum/sprite_accessory/underwear/bottom) //stores bottoms indexed by name
|
||||
GLOBAL_LIST_EMPTY(underwear_m) //stores only underwear name
|
||||
@@ -367,6 +368,7 @@ GLOBAL_LIST_INIT(job_heirlooms, list(
|
||||
"Janitor" = list(/obj/item/mop),
|
||||
"Scientist" = list(/obj/item/toy/plush/slimeplushie),
|
||||
"Assistant" = list(/obj/item/clothing/gloves/cut/family),
|
||||
"Prisoner" = list (/obj/item/pen/blue),
|
||||
"Chaplain" = list(/obj/item/camera/spooky/family),
|
||||
"Head of Personnel" = list(/obj/item/pinpointer/ian)
|
||||
))
|
||||
|
||||
@@ -112,7 +112,6 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
|
||||
/obj/item/storage/box/marshmallow = 2,
|
||||
/obj/item/clothing/gloves/tackler/offbrand = 1,
|
||||
/obj/item/stack/sticky_tape = 1,
|
||||
/obj/effect/spawner/lootdrop/grille_or_trash = 15,
|
||||
"" = 3
|
||||
))
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
return ShiftClickOn(A)
|
||||
if(modifiers["alt"]) // alt and alt-gr (rightalt)
|
||||
return AltClickOn(A)
|
||||
if(modifiers["ctrl"] && modifiers["right"]) //CIT CHANGE - right click ctrl for a new form of dropping items
|
||||
return CtrlRightClickOn(A, params) //CIT CHANGE
|
||||
if(modifiers["ctrl"])
|
||||
return CtrlClickOn(A)
|
||||
|
||||
@@ -295,6 +297,46 @@
|
||||
if(!(flags & COMPONENT_DENY_EXAMINATE) && user.client && (user.client.eye == user || user.client.eye == user.loc || flags & COMPONENT_ALLOW_EXAMINATE))
|
||||
user.examinate(src)
|
||||
|
||||
/*
|
||||
Ctrl + Right click
|
||||
Combat mode feature
|
||||
Drop item in hand at position.
|
||||
*/
|
||||
/atom/proc/CtrlRightClickOn(atom/A, params)
|
||||
if(isliving(src) && Adjacent(A)) //honestly only humans can do this given it's combat mode but if it's implemented for any other mobs...
|
||||
var/mob/living/L = src
|
||||
if(L.incapacitated())
|
||||
return
|
||||
var/obj/item/I = L.get_active_held_item()
|
||||
var/turf/T = get_turf(A)
|
||||
if(T)
|
||||
if(I) //drop item at cursor.
|
||||
if(T.density) //no, you can't use your funny blue cube or red cube to clip into the fucking wall.
|
||||
return
|
||||
for(var/atom/C in T.contents) //nor can you clip into a window or a door/false wall that's not open.
|
||||
if(C.opacity || (((C.flags_1 & PREVENT_CLICK_UNDER_1) > 0) != (istype(C,/obj/machinery/door) && !C.density))) //XOR operation within because doors always have PREVENT_CLICK_UNDER_1 flag enabled. Dumb, I know.
|
||||
return
|
||||
if(L.transferItemToLoc(I, T))
|
||||
var/list/click_params = params2list(params)
|
||||
//Center the icon where the user clicked. (shamelessly stole code from tables)
|
||||
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
|
||||
return
|
||||
//Clamp it so that the icon never moves more than 16 pixels in either direction
|
||||
I.pixel_x = clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
|
||||
I.pixel_y = clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
|
||||
return TRUE
|
||||
else if(isitem(A) && L.has_active_hand()) //if they have an open hand they'll rotate the item instead.
|
||||
var/obj/item/I2 = A
|
||||
if(!I2.anchored)
|
||||
var/matrix/ntransform = matrix(I2.transform)
|
||||
ntransform.Turn(15)
|
||||
animate(I2, transform = ntransform, time = 2)
|
||||
return TRUE
|
||||
else
|
||||
A.CtrlClick(src)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Ctrl click
|
||||
For most objects, pull
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
INVOKE_ASYNC(aicamera, /obj/item/camera.proc/captureimage, A, usr)
|
||||
return
|
||||
|
||||
var/obj/item/W = get_active_held_item()
|
||||
var/obj/item/W = get_active_held_item(TRUE)
|
||||
|
||||
if(!W && A.Adjacent(src) && (isobj(A) || ismob(A)))
|
||||
var/atom/movable/C = A
|
||||
|
||||
@@ -141,11 +141,29 @@
|
||||
/atom/movable/screen/inventory/MouseEntered()
|
||||
..()
|
||||
add_overlays()
|
||||
//Apply the outline affect
|
||||
add_stored_outline()
|
||||
|
||||
/atom/movable/screen/inventory/MouseExited()
|
||||
..()
|
||||
cut_overlay(object_overlays)
|
||||
object_overlays.Cut()
|
||||
remove_stored_outline()
|
||||
|
||||
/atom/movable/screen/inventory/proc/add_stored_outline()
|
||||
if(hud?.mymob && slot_id)
|
||||
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
|
||||
if(inv_item)
|
||||
if(hud?.mymob.incapacitated() || (slot_id in hud?.mymob.check_obscured_slots()) || !hud?.mymob.canUnEquip(inv_item))
|
||||
inv_item.apply_outline(_size = 3)
|
||||
else
|
||||
inv_item.apply_outline()
|
||||
|
||||
/atom/movable/screen/inventory/proc/remove_stored_outline()
|
||||
if(hud?.mymob && slot_id)
|
||||
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
|
||||
if(inv_item)
|
||||
inv_item.remove_outline()
|
||||
|
||||
/atom/movable/screen/inventory/update_icon_state()
|
||||
if(!icon_empty)
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
// Clickable stat() button.
|
||||
/obj/effect/statclick
|
||||
name = "Initializing..."
|
||||
// blocks_emissive = NONE
|
||||
var/target
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
|
||||
/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical
|
||||
/obj/effect/statclick/Initialize(mapload, text, target)
|
||||
. = ..()
|
||||
name = text
|
||||
src.target = target
|
||||
if(istype(target, /datum)) //Harddel man bad
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/cleanup)
|
||||
|
||||
/obj/effect/statclick/Destroy()
|
||||
target = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/statclick/proc/cleanup()
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/statclick/proc/update(text)
|
||||
name = text
|
||||
@@ -51,3 +62,30 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Restart Failsafe Controller")
|
||||
|
||||
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
|
||||
|
||||
/client/proc/debug_controller()
|
||||
set category = "Debug"
|
||||
set name = "Debug Controller"
|
||||
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
|
||||
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
var/list/controllers = list()
|
||||
var/list/controller_choices = list()
|
||||
|
||||
for (var/datum/controller/controller in world)
|
||||
if (istype(controller, /datum/controller/subsystem))
|
||||
continue
|
||||
controllers["[controller] (controller.type)"] = controller //we use an associated list to ensure clients can't hold references to controllers
|
||||
controller_choices += "[controller] (controller.type)"
|
||||
|
||||
var/datum/controller/controller_string = input("Select controller to debug", "Debug Controller") as null|anything in controller_choices
|
||||
var/datum/controller/controller = controllers[controller_string]
|
||||
|
||||
if (!istype(controller))
|
||||
return
|
||||
debug_variables(controller)
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Restart Failsafe Controller")
|
||||
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
|
||||
/datum/config_entry/flag/announce_admin_login
|
||||
|
||||
/datum/config_entry/string/centcom_ban_db // URL for the CentCom Galactic Ban DB API
|
||||
/datum/config_entry/string/centcom_ban_db // URL for the CentCom Galactic Ban DB API
|
||||
|
||||
/datum/config_entry/string/centcom_source_whitelist
|
||||
|
||||
/datum/config_entry/flag/autoadmin // if autoadmin is enabled
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
@@ -333,3 +333,15 @@
|
||||
config_entry_value = 0.333
|
||||
min_val = 0
|
||||
integer = FALSE
|
||||
|
||||
/datum/config_entry/number/hard_deletes_overrun_threshold
|
||||
integer = FALSE
|
||||
min_val = 0
|
||||
default = 0.5
|
||||
|
||||
/datum/config_entry/number/hard_deletes_overrun_limit
|
||||
default = 0
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/flag/atmos_equalize_enabled
|
||||
default = FALSE
|
||||
|
||||
@@ -15,7 +15,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
// The alert level. For every failed poke, we drop a DEFCON level. Once we hit DEFCON 1, restart the MC.
|
||||
var/defcon = 5
|
||||
//the world.time of the last check, so the mc can restart US if we hang.
|
||||
// (Real friends look out for *eachother*)
|
||||
// (Real friends look out for *eachother*)
|
||||
var/lasttick = 0
|
||||
|
||||
// Track the MC iteration to make sure its still on track.
|
||||
@@ -33,6 +33,22 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
/datum/controller/failsafe/Initialize()
|
||||
set waitfor = FALSE
|
||||
Failsafe.Loop()
|
||||
if (!Master || defcon == 0) //Master is gone/not responding and Failsafe just exited its loop
|
||||
defcon = 3 //Reset defcon level as its used inside the emergency loop
|
||||
while (defcon > 0)
|
||||
var/recovery_result = emergency_loop()
|
||||
if (recovery_result == 1) //Exit emergency loop and delete self if it was able to recover MC
|
||||
break
|
||||
else if (defcon == 1) //Exit Failsafe if we weren't able to recover the MC in the last stage
|
||||
log_game("FailSafe: Failed to recover MC while in emergency state. Failsafe exiting.")
|
||||
message_admins(span_boldannounce("Failsafe failed criticaly while trying to recreate broken MC. Please manually fix the MC or reboot the server. Failsafe exiting now."))
|
||||
message_admins(span_boldannounce("You can try manually calling these two procs:."))
|
||||
message_admins(span_boldannounce("/proc/recover_all_SS_and_recreate_master: Most stuff should still function but expect instability/runtimes/broken stuff."))
|
||||
message_admins(span_boldannounce("/proc/delete_all_SS_and_recreate_master: Most stuff will be broken but basic stuff like movement and chat should still work."))
|
||||
else if (recovery_result == -1) //Failed to recreate MC
|
||||
defcon--
|
||||
sleep(initial(processing_interval)) //Wait a bit until the next try
|
||||
|
||||
if(!QDELETED(src))
|
||||
qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us
|
||||
|
||||
@@ -45,42 +61,56 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
while(running)
|
||||
lasttick = world.time
|
||||
if(!Master)
|
||||
// Replace the missing Master! This should never, ever happen.
|
||||
new /datum/controller/master()
|
||||
// Break out of the main loop so we go into emergency state
|
||||
break
|
||||
// Only poke it if overrides are not in effect.
|
||||
if(processing_interval > 0)
|
||||
if(Master.processing && Master.iteration)
|
||||
if (defcon > 1 && (!Master.stack_end_detector || !Master.stack_end_detector.check()))
|
||||
|
||||
to_chat(GLOB.admins, span_boldannounce("ERROR: The Master Controller code stack has exited unexpectedly, Restarting..."))
|
||||
defcon = 0
|
||||
var/rtn = Recreate_MC()
|
||||
if(rtn > 0)
|
||||
master_iteration = 0
|
||||
to_chat(GLOB.admins, span_adminnotice("MC restarted successfully"))
|
||||
else if(rtn < 0)
|
||||
log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0")
|
||||
to_chat(GLOB.admins, span_boldannounce("ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying."))
|
||||
// Check if processing is done yet.
|
||||
if(Master.iteration == master_iteration)
|
||||
switch(defcon)
|
||||
if(4,5)
|
||||
--defcon
|
||||
if(3)
|
||||
message_admins("<span class='adminnotice'>Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks.</span>")
|
||||
--defcon
|
||||
if(2)
|
||||
to_chat(GLOB.admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks.</span>")
|
||||
--defcon
|
||||
if(1)
|
||||
|
||||
to_chat(GLOB.admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting...</span>")
|
||||
if(3)
|
||||
message_admins(span_adminnotice("Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks."))
|
||||
--defcon
|
||||
|
||||
if(2)
|
||||
to_chat(GLOB.admins, span_boldannounce("Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks."))
|
||||
--defcon
|
||||
|
||||
if(1)
|
||||
to_chat(GLOB.admins, span_boldannounce("Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting..."))
|
||||
--defcon
|
||||
var/rtn = Recreate_MC()
|
||||
if(rtn > 0)
|
||||
defcon = 4
|
||||
master_iteration = 0
|
||||
to_chat(GLOB.admins, "<span class='adminnotice'>MC restarted successfully</span>")
|
||||
to_chat(GLOB.admins, span_adminnotice("MC restarted successfully"))
|
||||
else if(rtn < 0)
|
||||
log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0")
|
||||
to_chat(GLOB.admins, "<span class='boldannounce'>ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying.</span>")
|
||||
to_chat(GLOB.admins, span_boldannounce("ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying."))
|
||||
//if the return number was 0, it just means the mc was restarted too recently, and it just needs some time before we try again
|
||||
//no need to handle that specially when defcon 0 can handle it
|
||||
|
||||
if(0) //DEFCON 0! (mc failed to restart)
|
||||
var/rtn = Recreate_MC()
|
||||
if(rtn > 0)
|
||||
defcon = 4
|
||||
master_iteration = 0
|
||||
to_chat(GLOB.admins, "<span class='adminnotice'>MC restarted successfully</span>")
|
||||
to_chat(GLOB.admins, span_adminnotice("MC restarted successfully"))
|
||||
else
|
||||
defcon = min(defcon + 1,5)
|
||||
master_iteration = Master.iteration
|
||||
@@ -92,6 +122,57 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
|
||||
defcon = 5
|
||||
sleep(initial(processing_interval))
|
||||
|
||||
//Emergency loop used when Master got deleted or the main loop exited while Defcon == 0
|
||||
//Loop is driven externally so runtimes only cancel the current recovery attempt
|
||||
/datum/controller/failsafe/proc/emergency_loop()
|
||||
//The code in this proc should be kept as simple as possible, anything complicated like to_chat might rely on master existing and runtime
|
||||
//The goal should always be to get a new Master up and running before anything else
|
||||
. = -1
|
||||
switch (defcon) //The lower defcon goes the harder we try to fix the MC
|
||||
if (2 to 3) //Try to normally recreate the MC two times
|
||||
. = Recreate_MC()
|
||||
if (1) //Delete the old MC first so we don't transfer any info, in case that caused any issues
|
||||
del(Master)
|
||||
. = Recreate_MC()
|
||||
|
||||
if (. == 1) //We were able to create a new master
|
||||
master_iteration = 0
|
||||
SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
|
||||
Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this
|
||||
to_chat(GLOB.admins, span_adminnotice("Failsafe recovered MC while in emergency state [defcon_pretty()]"))
|
||||
else
|
||||
log_game("FailSafe: Failsafe in emergency state and was unable to recreate MC while in defcon state [defcon_pretty()].")
|
||||
message_admins(span_boldannounce("Failsafe in emergency state and master down, trying to recreate MC while in defcon level [defcon_pretty()] failed."))
|
||||
|
||||
///Recreate all SSs which will still cause data survive due to Recover(), the new Master will then find and take them from global.vars
|
||||
/proc/recover_all_SS_and_recreate_master()
|
||||
del(Master)
|
||||
var/list/subsytem_types = subtypesof(/datum/controller/subsystem)
|
||||
sortTim(subsytem_types, /proc/cmp_subsystem_init)
|
||||
for(var/I in subsytem_types)
|
||||
new I
|
||||
. = Recreate_MC()
|
||||
if (. == 1) //We were able to create a new master
|
||||
SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
|
||||
Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this
|
||||
to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after recovering all subsystems!"))
|
||||
else
|
||||
message_admins(span_boldannounce("Failed to create new MC!"))
|
||||
|
||||
///Delete all existing SS to basically start over
|
||||
/proc/delete_all_SS_and_recreate_master()
|
||||
del(Master)
|
||||
for(var/global_var in global.vars)
|
||||
if (istype(global.vars[global_var], /datum/controller/subsystem))
|
||||
del(global.vars[global_var])
|
||||
. = Recreate_MC()
|
||||
if (. == 1) //We were able to create a new master
|
||||
SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
|
||||
Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this
|
||||
to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after deleting and recreating all subsystems!"))
|
||||
else
|
||||
message_admins(span_boldannounce("Failed to create new MC!"))
|
||||
|
||||
/datum/controller/failsafe/proc/defcon_pretty()
|
||||
return defcon
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
|
||||
var/datum/controller/exclude_these = new
|
||||
gvars_datum_in_built_vars = exclude_these.vars + list(NAMEOF(src, gvars_datum_protected_varlist), NAMEOF(src, gvars_datum_in_built_vars), NAMEOF(src, gvars_datum_init_order))
|
||||
QDEL_IN(exclude_these, 0) //signal logging isn't ready
|
||||
QDEL_IN(exclude_these, 0) //signal logging isn't ready
|
||||
|
||||
log_world("[vars.len - gvars_datum_in_built_vars.len] global variables")
|
||||
|
||||
|
||||
+59
-57
@@ -18,15 +18,17 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
/datum/controller/master
|
||||
name = "Master"
|
||||
|
||||
// Are we processing (higher values increase the processing delay by n ticks)
|
||||
/// Are we processing (higher values increase the processing delay by n ticks)
|
||||
var/processing = TRUE
|
||||
// How many times have we ran
|
||||
/// How many times have we ran
|
||||
var/iteration = 0
|
||||
/// Stack end detector to detect stack overflows that kill the mc's main loop
|
||||
var/datum/stack_end_detector/stack_end_detector
|
||||
|
||||
// world.time of last fire, for tracking lag outside of the mc
|
||||
/// world.time of last fire, for tracking lag outside of the mc
|
||||
var/last_run
|
||||
|
||||
// List of subsystems to process().
|
||||
/// List of subsystems to process().
|
||||
var/list/subsystems
|
||||
|
||||
// Vars for keeping track of tick drift.
|
||||
@@ -34,25 +36,27 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/init_time
|
||||
var/tickdrift = 0
|
||||
|
||||
/// How long is the MC sleeping between runs, read only (set by Loop() based off of anti-tick-contention heuristics)
|
||||
var/sleep_delta = 1
|
||||
|
||||
///Only run ticker subsystems for the next n ticks.
|
||||
/// Only run ticker subsystems for the next n ticks.
|
||||
var/skip_ticks = 0
|
||||
|
||||
/// makes the mc main loop runtime
|
||||
var/make_runtime = FALSE
|
||||
|
||||
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
|
||||
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
|
||||
|
||||
// The type of the last subsystem to be process()'d.
|
||||
/// The type of the last subsystem to be fire()'d.
|
||||
var/last_type_processed
|
||||
|
||||
var/datum/controller/subsystem/queue_head //Start of queue linked list
|
||||
var/datum/controller/subsystem/queue_tail //End of queue linked list (used for appending to the list)
|
||||
var/datum/controller/subsystem/queue_head //!Start of queue linked list
|
||||
var/datum/controller/subsystem/queue_tail //!End of queue linked list (used for appending to the list)
|
||||
var/queue_priority_count = 0 //Running total so that we don't have to loop thru the queue each run to split up the tick
|
||||
var/queue_priority_count_bg = 0 //Same, but for background subsystems
|
||||
var/map_loading = FALSE //Are we loading in a new map?
|
||||
var/map_loading = FALSE //!Are we loading in a new map?
|
||||
|
||||
var/current_runlevel //for scheduling different subsystems for different stages of the round
|
||||
var/current_runlevel //!for scheduling different subsystems for different stages of the round
|
||||
var/sleep_offline_after_initializations = TRUE
|
||||
|
||||
var/static/restart_clear = 0
|
||||
@@ -61,8 +65,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
var/static/random_seed
|
||||
|
||||
//current tick limit, assigned before running a subsystem.
|
||||
//used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
|
||||
///current tick limit, assigned before running a subsystem.
|
||||
///used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
|
||||
var/static/current_ticklimit = TICK_LIMIT_RUNNING
|
||||
|
||||
/datum/controller/master/New()
|
||||
@@ -81,15 +85,27 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/list/_subsystems = list()
|
||||
subsystems = _subsystems
|
||||
if (Master != src)
|
||||
if (istype(Master))
|
||||
if (istype(Master)) //If there is an existing MC take over his stuff and delete it
|
||||
Recover()
|
||||
qdel(Master)
|
||||
Master = src
|
||||
else
|
||||
//Code used for first master on game boot or if existing master got deleted
|
||||
Master = src
|
||||
var/list/subsytem_types = subtypesof(/datum/controller/subsystem)
|
||||
sortTim(subsytem_types, /proc/cmp_subsystem_init)
|
||||
//Find any abandoned subsystem from the previous master (if there was any)
|
||||
var/list/existing_subsystems = list()
|
||||
for(var/global_var in global.vars)
|
||||
if (istype(global.vars[global_var], /datum/controller/subsystem))
|
||||
existing_subsystems += global.vars[global_var]
|
||||
//Either init a new SS or if an existing one was found use that
|
||||
for(var/I in subsytem_types)
|
||||
_subsystems += new I
|
||||
Master = src
|
||||
var/datum/controller/subsystem/existing_subsystem = locate(I) in existing_subsystems
|
||||
if (istype(existing_subsystem))
|
||||
_subsystems += existing_subsystem
|
||||
else
|
||||
_subsystems += new I
|
||||
|
||||
if(!GLOB)
|
||||
new /datum/controller/global_vars
|
||||
@@ -109,7 +125,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
log_world("Shutdown complete")
|
||||
|
||||
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
|
||||
// -1 if we encountered a runtime trying to recreate it
|
||||
// -1 if we encountered a runtime trying to recreate it
|
||||
/proc/Recreate_MC()
|
||||
. = -1 //so if we runtime, things know we failed
|
||||
if (world.time < Master.restart_timeout)
|
||||
@@ -120,7 +136,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/delay = 50 * ++Master.restart_count
|
||||
Master.restart_timeout = world.time + delay
|
||||
Master.restart_clear = world.time + (delay * 2)
|
||||
Master.processing = FALSE //stop ticking this one
|
||||
if (Master) //Can only do this if master hasn't been deleted
|
||||
Master.processing = FALSE //stop ticking this one
|
||||
try
|
||||
new/datum/controller/master()
|
||||
catch
|
||||
@@ -156,22 +173,22 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined."
|
||||
BadBoy.flags |= SS_NO_FIRE
|
||||
if(msg)
|
||||
to_chat(GLOB.admins, "<span class='boldannounce'>[msg]</span>")
|
||||
to_chat(GLOB.admins, span_boldannounce("[msg]"))
|
||||
log_world(msg)
|
||||
|
||||
if (istype(Master.subsystems))
|
||||
if(FireHim)
|
||||
Master.subsystems += new BadBoy.type //NEW_SS_GLOBAL will remove the old one
|
||||
Master.subsystems += new BadBoy.type //NEW_SS_GLOBAL will remove the old one
|
||||
subsystems = Master.subsystems
|
||||
current_runlevel = Master.current_runlevel
|
||||
StartProcessing(10)
|
||||
else
|
||||
to_chat(world, "<span class='boldannounce'>The Master Controller is having some issues, we will need to re-initialize EVERYTHING</span>")
|
||||
to_chat(world, span_boldannounce("The Master Controller is having some issues, we will need to re-initialize EVERYTHING"))
|
||||
Initialize(20, TRUE)
|
||||
|
||||
|
||||
// Please don't stuff random bullshit here,
|
||||
// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in it's Initialize()
|
||||
// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in it's Initialize()
|
||||
/datum/controller/master/Initialize(delay, init_sss, tgs_prime)
|
||||
set waitfor = 0
|
||||
|
||||
@@ -181,7 +198,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
if(init_sss)
|
||||
init_subtypes(/datum/controller/subsystem, subsystems)
|
||||
|
||||
to_chat(world, "<span class='boldannounce'>Initializing subsystems...</span>")
|
||||
to_chat(world, span_boldannounce("Initializing subsystems..."))
|
||||
|
||||
// Sort subsystems by init_order, so they initialize in the correct order.
|
||||
sortTim(subsystems, /proc/cmp_subsystem_init)
|
||||
@@ -190,7 +207,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
// Initialize subsystems.
|
||||
current_ticklimit = CONFIG_GET(number/tick_limit_mc_init)
|
||||
for (var/datum/controller/subsystem/SS in subsystems)
|
||||
if (SS.flags & SS_NO_INIT)
|
||||
if (SS.flags & SS_NO_INIT || SS.initialized) //Don't init SSs with the correspondig flag or if they already are initialzized
|
||||
continue
|
||||
SS.Initialize(REALTIMEOFDAY)
|
||||
CHECK_TICK
|
||||
@@ -198,7 +215,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/time = (REALTIMEOFDAY - start_timeofday) / 10
|
||||
|
||||
var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!"
|
||||
to_chat(world, "<span class='boldannounce'>[msg]</span>")
|
||||
to_chat(world, span_boldannounce("[msg]"))
|
||||
log_world(msg)
|
||||
|
||||
if (!current_runlevel)
|
||||
@@ -255,11 +272,11 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
/datum/controller/master/proc/Loop()
|
||||
. = -1
|
||||
//Prep the loop (most of this is because we want MC restarts to reset as much state as we can, and because
|
||||
// local vars rock
|
||||
// local vars rock
|
||||
|
||||
//all this shit is here so that flag edits can be refreshed by restarting the MC. (and for speed)
|
||||
var/list/tickersubsystems = list()
|
||||
var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel
|
||||
var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel
|
||||
var/timer = world.time
|
||||
for (var/thing in subsystems)
|
||||
var/datum/controller/subsystem/SS = thing
|
||||
@@ -305,8 +322,12 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/error_level = 0
|
||||
var/sleep_delta = 1
|
||||
var/list/subsystems_to_check
|
||||
//the actual loop.
|
||||
|
||||
//setup the stack overflow detector
|
||||
stack_end_detector = new()
|
||||
var/datum/stack_canary/canary = stack_end_detector.prime_canary()
|
||||
canary.use_variable()
|
||||
//the actual loop.
|
||||
while (1)
|
||||
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
|
||||
var/starting_tick_usage = TICK_USAGE
|
||||
@@ -317,7 +338,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
//Anti-tick-contention heuristics:
|
||||
//if there are mutiple sleeping procs running before us hogging the cpu, we have to run later.
|
||||
// (because sleeps are processed in the order received, longer sleeps are more likely to run first)
|
||||
// (because sleeps are processed in the order received, longer sleeps are more likely to run first)
|
||||
if (starting_tick_usage > TICK_LIMIT_MC) //if there isn't enough time to bother doing anything this tick, sleep a bit.
|
||||
sleep_delta *= 2
|
||||
current_ticklimit = TICK_LIMIT_RUNNING * 0.5
|
||||
@@ -423,6 +444,10 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
continue
|
||||
if ((SS_flags & (SS_TICKER|SS_KEEP_TIMING)) == SS_KEEP_TIMING && SS.last_fire + (SS.wait * 0.75) > world.time)
|
||||
continue
|
||||
if (SS.postponed_fires >= 1)
|
||||
SS.postponed_fires--
|
||||
SS.update_nextfire()
|
||||
continue
|
||||
SS.enqueue()
|
||||
. = 1
|
||||
|
||||
@@ -439,12 +464,11 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/tick_precentage
|
||||
var/tick_remaining
|
||||
var/ran = TRUE //this is right
|
||||
var/ran_non_ticker = FALSE
|
||||
var/bg_calc //have we swtiched current_tick_budget to background mode yet?
|
||||
var/tick_usage
|
||||
|
||||
//keep running while we have stuff to run and we haven't gone over a tick
|
||||
// this is so subsystems paused eariler can use tick time that later subsystems never used
|
||||
// this is so subsystems paused eariler can use tick time that later subsystems never used
|
||||
while (ran && queue_head && TICK_USAGE < TICK_LIMIT_MC)
|
||||
ran = FALSE
|
||||
bg_calc = FALSE
|
||||
@@ -459,20 +483,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
if (!(queue_node_flags & SS_TICKER) && skip_ticks)
|
||||
queue_node = queue_node.queue_next
|
||||
continue
|
||||
//super special case, subsystems where we can't make them pause mid way through
|
||||
//if we can't run them this tick (without going over a tick)
|
||||
//we bump up their priority and attempt to run them next tick
|
||||
//(unless we haven't even ran anything this tick, since its unlikely they will ever be able run
|
||||
// in those cases, so we just let them run)
|
||||
if (queue_node_flags & SS_NO_TICK_CHECK)
|
||||
if (queue_node.tick_usage > TICK_LIMIT_RUNNING - TICK_USAGE && ran_non_ticker)
|
||||
if (!(queue_node_flags & SS_BACKGROUND))
|
||||
queue_node.queued_priority += queue_priority_count * 0.1
|
||||
queue_priority_count -= queue_node_priority
|
||||
queue_priority_count += queue_node.queued_priority
|
||||
current_tick_budget -= queue_node_priority
|
||||
queue_node = queue_node.queue_next
|
||||
continue
|
||||
|
||||
if (!bg_calc && (queue_node_flags & SS_BACKGROUND))
|
||||
current_tick_budget = queue_priority_count_bg
|
||||
@@ -481,7 +491,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
tick_remaining = TICK_LIMIT_RUNNING - TICK_USAGE
|
||||
|
||||
if (current_tick_budget > 0 && queue_node_priority > 0)
|
||||
tick_precentage = tick_remaining / (current_tick_budget / queue_node_priority)
|
||||
//Give the subsystem a precentage of the remaining tick based on the remaning priority
|
||||
tick_precentage = tick_remaining * (queue_node_priority / current_tick_budget)
|
||||
else
|
||||
tick_precentage = tick_remaining
|
||||
|
||||
@@ -489,8 +500,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
current_ticklimit = round(TICK_USAGE + tick_precentage)
|
||||
|
||||
if (!(queue_node_flags & SS_TICKER))
|
||||
ran_non_ticker = TRUE
|
||||
ran = TRUE
|
||||
|
||||
queue_node_paused = (queue_node.state == SS_PAUSED || queue_node.state == SS_PAUSING)
|
||||
@@ -535,14 +544,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
queue_node.last_fire = world.time
|
||||
queue_node.times_fired++
|
||||
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
queue_node.next_fire = world.time + (world.tick_lag * queue_node.wait)
|
||||
else if (queue_node_flags & SS_POST_FIRE_TIMING)
|
||||
queue_node.next_fire = world.time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
|
||||
else if (queue_node_flags & SS_KEEP_TIMING)
|
||||
queue_node.next_fire += queue_node.wait
|
||||
else
|
||||
queue_node.next_fire = queue_node.queued_time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
|
||||
queue_node.update_nextfire()
|
||||
|
||||
queue_node.queued_time = 0
|
||||
|
||||
@@ -554,7 +556,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
. = 1
|
||||
|
||||
//resets the queue, and all subsystems, while filtering out the subsystem lists
|
||||
// called if any mc's queue procs runtime or exit improperly.
|
||||
// called if any mc's queue procs runtime or exit improperly.
|
||||
/datum/controller/master/proc/SoftReset(list/ticker_SS, list/runlevel_SS)
|
||||
. = 0
|
||||
log_world("MC: SoftReset called, resetting MC queue state.")
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
var/initialized = FALSE
|
||||
|
||||
/// Set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later
|
||||
/// use the [SS_NO_FIRE] flag instead for systems that never fire to keep it from even being added to list that is checked every tick
|
||||
/// use the [SS_NO_FIRE] flag instead for systems that never fire to keep it from even being added to list that is checked every tick
|
||||
var/can_fire = TRUE
|
||||
|
||||
///Bitmap of what game states can this subsystem fire at. See [RUNLEVELS_DEFAULT] for more details.
|
||||
var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire
|
||||
var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire
|
||||
|
||||
/*
|
||||
* The following variables are managed by the MC and should not be modified directly.
|
||||
@@ -69,6 +69,9 @@
|
||||
/// Tracks the amount of completed runs for the subsystem
|
||||
var/times_fired = 0
|
||||
|
||||
/// How many fires have we been requested to postpone
|
||||
var/postponed_fires = 0
|
||||
|
||||
/// Time the subsystem entered the queue, (for timing and priority reasons)
|
||||
var/queued_time = 0
|
||||
|
||||
@@ -122,12 +125,38 @@
|
||||
dequeue()
|
||||
can_fire = 0
|
||||
flags |= SS_NO_FIRE
|
||||
Master.subsystems -= src
|
||||
if (Master)
|
||||
Master.subsystems -= src
|
||||
return ..()
|
||||
|
||||
|
||||
/** Update next_fire for the next run.
|
||||
* reset_time (bool) - Ignore things that would normally alter the next fire, like tick_overrun, and last_fire. (also resets postpone)
|
||||
*/
|
||||
/datum/controller/subsystem/proc/update_nextfire(reset_time = FALSE)
|
||||
var/queue_node_flags = flags
|
||||
|
||||
if (reset_time)
|
||||
postponed_fires = 0
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
next_fire = world.time + (world.tick_lag * wait)
|
||||
else
|
||||
next_fire = world.time + wait
|
||||
return
|
||||
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
next_fire = world.time + (world.tick_lag * wait)
|
||||
else if (queue_node_flags & SS_POST_FIRE_TIMING)
|
||||
next_fire = world.time + wait + (world.tick_lag * (tick_overrun/100))
|
||||
else if (queue_node_flags & SS_KEEP_TIMING)
|
||||
next_fire += wait
|
||||
else
|
||||
next_fire = queued_time + wait + (world.tick_lag * (tick_overrun/100))
|
||||
|
||||
|
||||
//Queue it to run.
|
||||
// (we loop thru a linked list until we get to the end or find the right point)
|
||||
// (this lets us sort our run order correctly without having to re-sort the entire already sorted list)
|
||||
// (we loop thru a linked list until we get to the end or find the right point)
|
||||
// (this lets us sort our run order correctly without having to re-sort the entire already sorted list)
|
||||
/datum/controller/subsystem/proc/enqueue()
|
||||
var/SS_priority = priority
|
||||
var/SS_flags = flags
|
||||
@@ -191,9 +220,9 @@
|
||||
queue_next.queue_prev = queue_prev
|
||||
if (queue_prev)
|
||||
queue_prev.queue_next = queue_next
|
||||
if (src == Master.queue_tail)
|
||||
if (Master && (src == Master.queue_tail))
|
||||
Master.queue_tail = queue_prev
|
||||
if (src == Master.queue_head)
|
||||
if (Master && (src == Master.queue_head))
|
||||
Master.queue_head = queue_next
|
||||
queued_time = 0
|
||||
if (state == SS_QUEUED)
|
||||
@@ -217,10 +246,11 @@
|
||||
//used to initialize the subsystem AFTER the map has loaded
|
||||
/datum/controller/subsystem/Initialize(start_timeofday)
|
||||
initialized = TRUE
|
||||
// SEND_SIGNAL(src, COMSIG_SUBSYSTEM_POST_INITIALIZE, start_timeofday)
|
||||
var/time = (REALTIMEOFDAY - start_timeofday) / 10
|
||||
var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!"
|
||||
to_chat(world, "<span class='boldannounce'>[msg]</span>")
|
||||
log_subsystem("INIT", msg)
|
||||
to_chat(world, span_boldannounce("[msg]"))
|
||||
log_subsystem(msg)
|
||||
return time
|
||||
|
||||
/datum/controller/subsystem/stat_entry(msg)
|
||||
@@ -243,11 +273,10 @@
|
||||
if (SS_IDLE)
|
||||
. = " "
|
||||
|
||||
//could be used to postpone a costly subsystem for (default one) var/cycles, cycles
|
||||
//for instance, during cpu intensive operations like explosions
|
||||
/// Causes the next "cycle" fires to be missed. Effect is accumulative but can reset by calling update_nextfire(reset_time = TRUE)
|
||||
/datum/controller/subsystem/proc/postpone(cycles = 1)
|
||||
if(next_fire - world.time < wait)
|
||||
next_fire += (wait*cycles)
|
||||
if (can_fire && cycles >= 1)
|
||||
postponed_fires += cycles
|
||||
|
||||
//usually called via datum/controller/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash)
|
||||
//should attempt to salvage what it can from the old instance of subsystem
|
||||
@@ -258,7 +287,7 @@
|
||||
if (NAMEOF(src, can_fire))
|
||||
//this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag
|
||||
if (var_value)
|
||||
next_fire = world.time + wait
|
||||
update_nextfire(reset_time = TRUE)
|
||||
if (NAMEOF(src, queued_priority)) //editing this breaks things.
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
@@ -30,6 +30,7 @@ SUBSYSTEM_DEF(air)
|
||||
var/list/networks = list()
|
||||
var/list/pipenets_needing_rebuilt = list()
|
||||
var/list/deferred_airs = list()
|
||||
var/cur_deferred_airs = 0
|
||||
var/max_deferred_airs = 0
|
||||
var/list/obj/machinery/atmos_machinery = list()
|
||||
var/list/obj/machinery/atmos_air_machinery = list()
|
||||
@@ -37,7 +38,8 @@ SUBSYSTEM_DEF(air)
|
||||
|
||||
//atmos singletons
|
||||
var/list/gas_reactions = list()
|
||||
|
||||
var/list/atmos_gen
|
||||
var/list/planetary = list() //auxmos already caches static planetary mixes but could be convenient to do so here too
|
||||
//Special functions lists
|
||||
var/list/turf/open/high_pressure_delta = list()
|
||||
|
||||
@@ -53,14 +55,24 @@ SUBSYSTEM_DEF(air)
|
||||
var/equalize_turf_limit = 10
|
||||
// Max number of turfs to look for a space turf, and max number of turfs that will be decompressed.
|
||||
var/equalize_hard_turf_limit = 2000
|
||||
// Whether equalization should be enabled at all.
|
||||
// Whether equalization is enabled. Can be disabled for performance reasons.
|
||||
var/equalize_enabled = TRUE
|
||||
// Whether equalization should be enabled.
|
||||
var/should_do_equalization = TRUE
|
||||
// When above 0, won't equalize; performance handling
|
||||
var/eq_cooldown = 0
|
||||
// Whether turf-to-turf heat exchanging should be enabled.
|
||||
var/heat_enabled = FALSE
|
||||
// Max number of times process_turfs will share in a tick.
|
||||
var/share_max_steps = 3
|
||||
// Target for share_max_steps; can go below this, if it determines the thread is taking too long.
|
||||
var/share_max_steps_target = 3
|
||||
// Excited group processing will try to equalize groups with total pressure difference less than this amount.
|
||||
var/excited_group_pressure_goal = 1
|
||||
// Target for excited_group_pressure_goal; can go below this, if it determines the thread is taking too long.
|
||||
var/excited_group_pressure_goal_target = 1
|
||||
// If this is set to 0, monstermos won't process planet atmos
|
||||
var/planet_equalize_enabled = 0
|
||||
|
||||
/datum/controller/subsystem/air/stat_entry(msg)
|
||||
msg += "C:{"
|
||||
@@ -96,6 +108,7 @@ SUBSYSTEM_DEF(air)
|
||||
setup_atmos_machinery()
|
||||
setup_pipenets()
|
||||
gas_reactions = init_gas_reactions()
|
||||
should_do_equalization = CONFIG_GET(flag/atmos_equalize_enabled)
|
||||
auxtools_update_reactions()
|
||||
return ..()
|
||||
|
||||
@@ -218,6 +231,7 @@ SUBSYSTEM_DEF(air)
|
||||
// This also happens to do all the commented out stuff below, all in a single separate thread. This is mostly so that the
|
||||
// waiting is consistent.
|
||||
if(currentpart == SSAIR_ACTIVETURFS)
|
||||
run_delay_heuristics()
|
||||
timer = TICK_USAGE_REAL
|
||||
process_turfs(resumed)
|
||||
cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
@@ -275,7 +289,8 @@ SUBSYSTEM_DEF(air)
|
||||
pipenets_needing_rebuilt += atmos_machine
|
||||
|
||||
/datum/controller/subsystem/air/proc/process_deferred_airs(resumed = 0)
|
||||
max_deferred_airs = max(deferred_airs.len,max_deferred_airs)
|
||||
cur_deferred_airs = deferred_airs.len
|
||||
max_deferred_airs = max(cur_deferred_airs,max_deferred_airs)
|
||||
while(deferred_airs.len)
|
||||
var/list/cur_op = deferred_airs[deferred_airs.len]
|
||||
deferred_airs.len--
|
||||
@@ -375,6 +390,24 @@ SUBSYSTEM_DEF(air)
|
||||
return
|
||||
*/
|
||||
|
||||
/datum/controller/subsystem/air/proc/run_delay_heuristics()
|
||||
if(!equalize_enabled)
|
||||
cost_equalize = 0
|
||||
if(should_do_equalization)
|
||||
eq_cooldown--
|
||||
if(eq_cooldown <= 0)
|
||||
equalize_enabled = TRUE
|
||||
var/total_thread_time = cost_turfs + cost_equalize + cost_groups + cost_post_process
|
||||
if(total_thread_time)
|
||||
var/wait_ms = wait * 100
|
||||
var/delay_threshold = 1-(total_thread_time/wait_ms + cur_deferred_airs / 50)
|
||||
share_max_steps = max(1,round(share_max_steps_target * delay_threshold, 1))
|
||||
eq_cooldown += (1-delay_threshold) * (cost_equalize / total_thread_time) * 2
|
||||
if(eq_cooldown > 0.5)
|
||||
equalize_enabled = FALSE
|
||||
excited_group_pressure_goal = max(0,excited_group_pressure_goal_target * (1 - delay_threshold))
|
||||
|
||||
|
||||
/datum/controller/subsystem/air/proc/process_turfs(resumed = 0)
|
||||
if(process_turfs_auxtools(resumed,TICK_REMAINING_MS))
|
||||
pause()
|
||||
@@ -399,7 +432,7 @@ SUBSYSTEM_DEF(air)
|
||||
pause()
|
||||
|
||||
/datum/controller/subsystem/air/proc/finish_turf_processing(resumed = 0)
|
||||
if(finish_turf_processing_auxtools(TICK_REMAINING_MS))
|
||||
if(finish_turf_processing_auxtools(TICK_REMAINING_MS) || thread_running())
|
||||
pause()
|
||||
|
||||
/datum/controller/subsystem/air/proc/post_process_turfs(resumed = 0)
|
||||
@@ -473,6 +506,20 @@ SUBSYSTEM_DEF(air)
|
||||
|
||||
return pipe_init_dirs_cache[type]["[dir]"]
|
||||
|
||||
/datum/controller/subsystem/air/proc/generate_atmos()
|
||||
atmos_gen = list()
|
||||
for(var/T in subtypesof(/datum/atmosphere))
|
||||
var/datum/atmosphere/atmostype = T
|
||||
atmos_gen[initial(atmostype.id)] = new atmostype
|
||||
|
||||
/datum/controller/subsystem/air/proc/preprocess_gas_string(gas_string)
|
||||
if(!atmos_gen)
|
||||
generate_atmos()
|
||||
if(!atmos_gen[gas_string])
|
||||
return gas_string
|
||||
var/datum/atmosphere/mix = atmos_gen[gas_string]
|
||||
return mix.gas_string
|
||||
|
||||
#undef SSAIR_PIPENETS
|
||||
#undef SSAIR_ATMOSMACHINERY
|
||||
#undef SSAIR_EXCITEDGROUPS
|
||||
|
||||
@@ -29,37 +29,35 @@ SUBSYSTEM_DEF(garbage)
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
|
||||
init_order = INIT_ORDER_GARBAGE
|
||||
|
||||
var/list/collection_timeout = list(2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level
|
||||
var/list/collection_timeout = list(GC_FILTER_QUEUE, GC_DEL_QUEUE) // deciseconds to wait before moving something up in the queue to the next level
|
||||
|
||||
//Stat tracking
|
||||
var/delslasttick = 0 // number of del()'s we've done this tick
|
||||
var/gcedlasttick = 0 // number of things that gc'ed last tick
|
||||
var/delslasttick = 0 // number of del()'s we've done this tick
|
||||
var/gcedlasttick = 0 // number of things that gc'ed last tick
|
||||
var/totaldels = 0
|
||||
var/totalgcs = 0
|
||||
|
||||
var/highest_del_time = 0
|
||||
var/highest_del_tickusage = 0
|
||||
var/highest_del_ms = 0
|
||||
var/highest_del_type_string = ""
|
||||
|
||||
var/list/pass_counts
|
||||
var/list/fail_counts
|
||||
|
||||
var/list/items = list() // Holds our qdel_item statistics datums
|
||||
var/list/items = list() // Holds our qdel_item statistics datums
|
||||
|
||||
//Queue
|
||||
var/list/queues
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
#ifdef REFERENCE_TRACKING
|
||||
var/list/reference_find_on_fail = list()
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
//Should we save found refs. Used for unit testing
|
||||
var/should_save_refs = FALSE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/datum/controller/subsystem/garbage/PreInit()
|
||||
queues = new(GC_QUEUE_COUNT)
|
||||
pass_counts = new(GC_QUEUE_COUNT)
|
||||
fail_counts = new(GC_QUEUE_COUNT)
|
||||
for(var/i in 1 to GC_QUEUE_COUNT)
|
||||
queues[i] = list()
|
||||
pass_counts[i] = 0
|
||||
fail_counts[i] = 0
|
||||
InitQueues()
|
||||
|
||||
/datum/controller/subsystem/garbage/stat_entry(msg)
|
||||
var/list/counts = list()
|
||||
@@ -90,13 +88,18 @@ SUBSYSTEM_DEF(garbage)
|
||||
for(var/path in items)
|
||||
var/datum/qdel_item/I = items[path]
|
||||
dellog += "Path: [path]"
|
||||
if (I.qdel_flags & QDEL_ITEM_SUSPENDED_FOR_LAG)
|
||||
dellog += "\tSUSPENDED FOR LAG"
|
||||
if (I.failures)
|
||||
dellog += "\tFailures: [I.failures]"
|
||||
dellog += "\tqdel() Count: [I.qdels]"
|
||||
dellog += "\tDestroy() Cost: [I.destroy_time]ms"
|
||||
if (I.hard_deletes)
|
||||
dellog += "\tTotal Hard Deletes [I.hard_deletes]"
|
||||
dellog += "\tTotal Hard Deletes: [I.hard_deletes]"
|
||||
dellog += "\tTime Spent Hard Deleting: [I.hard_delete_time]ms"
|
||||
dellog += "\tHighest Time Spent Hard Deleting: [I.hard_delete_max]ms"
|
||||
if (I.hard_deletes_over_threshold)
|
||||
dellog += "\tHard Deletes Over Threshold: [I.hard_deletes_over_threshold]"
|
||||
if (I.slept_destroy)
|
||||
dellog += "\tSleeps: [I.slept_destroy]"
|
||||
if (I.no_respect_force)
|
||||
@@ -122,6 +125,15 @@ SUBSYSTEM_DEF(garbage)
|
||||
|
||||
|
||||
|
||||
/datum/controller/subsystem/garbage/proc/InitQueues()
|
||||
if (isnull(queues)) // Only init the queues if they don't already exist, prevents overriding of recovered lists
|
||||
queues = new(GC_QUEUE_COUNT)
|
||||
pass_counts = new(GC_QUEUE_COUNT)
|
||||
fail_counts = new(GC_QUEUE_COUNT)
|
||||
for(var/i in 1 to GC_QUEUE_COUNT)
|
||||
queues[i] = list()
|
||||
pass_counts[i] = 0
|
||||
fail_counts[i] = 0
|
||||
|
||||
/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK)
|
||||
if (level == GC_QUEUE_CHECK)
|
||||
@@ -153,7 +165,6 @@ SUBSYSTEM_DEF(garbage)
|
||||
if(GCd_at_time > cut_off_time)
|
||||
break // Everything else is newer, skip them
|
||||
count++
|
||||
|
||||
var/refID = L[2]
|
||||
var/datum/D
|
||||
D = locate(refID)
|
||||
@@ -162,8 +173,8 @@ SUBSYSTEM_DEF(garbage)
|
||||
++gcedlasttick
|
||||
++totalgcs
|
||||
pass_counts[level]++
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
reference_find_on_fail -= refID //It's deleted we don't care anymore.
|
||||
#ifdef REFERENCE_TRACKING
|
||||
reference_find_on_fail -= refID //It's deleted we don't care anymore.
|
||||
#endif
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
@@ -171,35 +182,43 @@ SUBSYSTEM_DEF(garbage)
|
||||
|
||||
// Something's still referring to the qdel'd object.
|
||||
fail_counts[level]++
|
||||
|
||||
#ifdef REFERENCE_TRACKING
|
||||
var/ref_searching = FALSE
|
||||
#endif
|
||||
|
||||
switch (level)
|
||||
if (GC_QUEUE_CHECK)
|
||||
#ifdef REFERENCE_TRACKING
|
||||
D.find_references()
|
||||
#elif defined(LEGACY_REFERENCE_TRACKING)
|
||||
if(reference_find_on_fail[refID])
|
||||
D.find_references_legacy()
|
||||
INVOKE_ASYNC(D, /datum/proc/find_references)
|
||||
ref_searching = TRUE
|
||||
#ifdef GC_FAILURE_HARD_LOOKUP
|
||||
else
|
||||
D.find_references_legacy()
|
||||
INVOKE_ASYNC(D, /datum/proc/find_references)
|
||||
ref_searching = TRUE
|
||||
#endif
|
||||
reference_find_on_fail -= refID
|
||||
#endif
|
||||
var/type = D.type
|
||||
var/datum/qdel_item/I = items[type]
|
||||
#ifdef TESTING
|
||||
|
||||
log_world("## TESTING: GC: -- \ref[D] | [type] was unable to be GC'd --")
|
||||
#ifdef TESTING
|
||||
for(var/c in GLOB.admins) //Using testing() here would fill the logs with ADMIN_VV garbage
|
||||
var/client/admin = c
|
||||
if(!check_rights_for(admin, R_ADMIN))
|
||||
continue
|
||||
to_chat(admin, "## TESTING: GC: -- [ADMIN_VV(D)] | [type] was unable to be GC'd --")
|
||||
testing("GC: -- \ref[src] | [type] was unable to be GC'd --")
|
||||
#endif
|
||||
#ifdef REFERENCE_TRACKING
|
||||
GLOB.deletion_failures += D //It should no longer be bothered by the GC, manual deletion only.
|
||||
continue
|
||||
#endif
|
||||
I.failures++
|
||||
|
||||
if (I.qdel_flags & QDEL_ITEM_SUSPENDED_FOR_LAG)
|
||||
#ifdef REFERENCE_TRACKING
|
||||
if(ref_searching)
|
||||
return //ref searching intentionally cancels all further fires while running so things that hold references don't end up getting deleted, so we want to return here instead of continue
|
||||
#endif
|
||||
continue
|
||||
if (GC_QUEUE_HARDDELETE)
|
||||
HardDelete(D)
|
||||
if (MC_TICK_CHECK)
|
||||
@@ -208,27 +227,17 @@ SUBSYSTEM_DEF(garbage)
|
||||
|
||||
Queue(D, level+1)
|
||||
|
||||
#ifdef REFERENCE_TRACKING
|
||||
if(ref_searching)
|
||||
return
|
||||
#endif
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
if (count)
|
||||
queue.Cut(1,count+1)
|
||||
count = 0
|
||||
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
/datum/controller/subsystem/garbage/proc/add_type_to_findref(type)
|
||||
if(!ispath(type))
|
||||
return "NOT A VAILD PATH"
|
||||
reference_find_on_fail_types |= typecacheof(type)
|
||||
|
||||
/datum/controller/subsystem/garbage/proc/remove_type_from_findref(type)
|
||||
if(!ispath(type))
|
||||
return "NOT A VALID PATH"
|
||||
reference_find_on_fail_types -= typesof(type)
|
||||
|
||||
/datum/controller/subsystem/garbage/proc/clear_findref_types()
|
||||
reference_find_on_fail_types = list()
|
||||
#endif
|
||||
|
||||
/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK)
|
||||
if (isnull(D))
|
||||
return
|
||||
@@ -238,63 +247,66 @@ SUBSYSTEM_DEF(garbage)
|
||||
var/gctime = world.time
|
||||
var/refid = "\ref[D]"
|
||||
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
if(reference_find_on_fail_types[D.type])
|
||||
SSgarbage.reference_find_on_fail[REF(D)] = TRUE
|
||||
#endif
|
||||
|
||||
D.gc_destroyed = gctime
|
||||
var/list/queue = queues[level]
|
||||
|
||||
queue[++queue.len] = list(gctime, refid) // not += for byond reasons
|
||||
|
||||
//this is mainly to separate things profile wise.
|
||||
/datum/controller/subsystem/garbage/proc/HardDelete(datum/D)
|
||||
var/time = world.timeofday
|
||||
var/tick = TICK_USAGE
|
||||
var/ticktime = world.time
|
||||
++delslasttick
|
||||
++totaldels
|
||||
var/type = D.type
|
||||
var/refID = "\ref[D]"
|
||||
|
||||
var/tick_usage = TICK_USAGE
|
||||
del(D)
|
||||
|
||||
tick = (TICK_USAGE-tick+((world.time-ticktime)/world.tick_lag*100))
|
||||
tick_usage = TICK_USAGE_TO_MS(tick_usage)
|
||||
|
||||
var/datum/qdel_item/I = items[type]
|
||||
|
||||
I.hard_deletes++
|
||||
I.hard_delete_time += TICK_DELTA_TO_MS(tick)
|
||||
I.hard_delete_time += tick_usage
|
||||
if (tick_usage > I.hard_delete_max)
|
||||
I.hard_delete_max = tick_usage
|
||||
if (tick_usage > highest_del_ms)
|
||||
highest_del_ms = tick_usage
|
||||
highest_del_type_string = "[type]"
|
||||
|
||||
var/time = MS2DS(tick_usage)
|
||||
|
||||
if (tick > highest_del_tickusage)
|
||||
highest_del_tickusage = tick
|
||||
time = world.timeofday - time
|
||||
if (!time && TICK_DELTA_TO_MS(tick) > 1)
|
||||
time = TICK_DELTA_TO_MS(tick)/100
|
||||
if (time > highest_del_time)
|
||||
highest_del_time = time
|
||||
if (time > 10)
|
||||
log_game("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete)")
|
||||
message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete).")
|
||||
if (time > 0.1 SECONDS)
|
||||
postpone(time)
|
||||
var/threshold = CONFIG_GET(number/hard_deletes_overrun_threshold)
|
||||
if (threshold && (time > threshold SECONDS))
|
||||
if (!(I.qdel_flags & QDEL_ITEM_ADMINS_WARNED))
|
||||
log_game("Error: [type]([refID]) took longer than [threshold] seconds to delete (took [round(time/10, 0.1)] seconds to delete)")
|
||||
message_admins("Error: [type]([refID]) took longer than [threshold] seconds to delete (took [round(time/10, 0.1)] seconds to delete).")
|
||||
I.qdel_flags |= QDEL_ITEM_ADMINS_WARNED
|
||||
I.hard_deletes_over_threshold++
|
||||
var/overrun_limit = CONFIG_GET(number/hard_deletes_overrun_limit)
|
||||
if (overrun_limit && I.hard_deletes_over_threshold >= overrun_limit)
|
||||
I.qdel_flags |= QDEL_ITEM_SUSPENDED_FOR_LAG
|
||||
|
||||
/datum/controller/subsystem/garbage/Recover()
|
||||
InitQueues() //We first need to create the queues before recovering data
|
||||
if (istype(SSgarbage.queues))
|
||||
for (var/i in 1 to SSgarbage.queues.len)
|
||||
queues[i] |= SSgarbage.queues[i]
|
||||
|
||||
|
||||
/// Qdel Item: Holds statistics on each type that passes thru qdel
|
||||
/datum/qdel_item
|
||||
var/name = ""
|
||||
var/qdels = 0 //Total number of times it's passed thru qdel.
|
||||
var/destroy_time = 0 //Total amount of milliseconds spent processing this type's Destroy()
|
||||
var/failures = 0 //Times it was queued for soft deletion but failed to soft delete.
|
||||
var/hard_deletes = 0 //Different from failures because it also includes QDEL_HINT_HARDDEL deletions
|
||||
var/hard_delete_time = 0//Total amount of milliseconds spent hard deleting this type.
|
||||
var/no_respect_force = 0//Number of times it's not respected force=TRUE
|
||||
var/no_hint = 0 //Number of times it's not even bother to give a qdel hint
|
||||
var/slept_destroy = 0 //Number of times it's slept in its destroy
|
||||
var/name = "" //!Holds the type as a string for this type
|
||||
var/qdels = 0 //!Total number of times it's passed thru qdel.
|
||||
var/destroy_time = 0 //!Total amount of milliseconds spent processing this type's Destroy()
|
||||
var/failures = 0 //!Times it was queued for soft deletion but failed to soft delete.
|
||||
var/hard_deletes = 0 //!Different from failures because it also includes QDEL_HINT_HARDDEL deletions
|
||||
var/hard_delete_time = 0 //!Total amount of milliseconds spent hard deleting this type.
|
||||
var/hard_delete_max = 0 //!Highest time spent hard_deleting this in ms.
|
||||
var/hard_deletes_over_threshold = 0 //!Number of times hard deletes took longer than the configured threshold
|
||||
var/no_respect_force = 0 //!Number of times it's not respected force=TRUE
|
||||
var/no_hint = 0 //!Number of times it's not even bother to give a qdel hint
|
||||
var/slept_destroy = 0 //!Number of times it's slept in its destroy
|
||||
var/qdel_flags = 0 //!Flags related to this type's trip thru qdel.
|
||||
|
||||
/datum/qdel_item/New(mytype)
|
||||
name = "[mytype]"
|
||||
@@ -307,12 +319,12 @@ SUBSYSTEM_DEF(garbage)
|
||||
if(!istype(D))
|
||||
del(D)
|
||||
return
|
||||
|
||||
var/datum/qdel_item/I = SSgarbage.items[D.type]
|
||||
if (!I)
|
||||
I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type)
|
||||
I.qdels++
|
||||
|
||||
|
||||
if(isnull(D.gc_destroyed))
|
||||
if (SEND_SIGNAL(D, COMSIG_PARENT_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted
|
||||
return
|
||||
@@ -328,12 +340,12 @@ SUBSYSTEM_DEF(garbage)
|
||||
if(!D)
|
||||
return
|
||||
switch(hint)
|
||||
if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion.
|
||||
if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion.
|
||||
SSgarbage.Queue(D)
|
||||
if (QDEL_HINT_IWILLGC)
|
||||
D.gc_destroyed = world.time
|
||||
return
|
||||
if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory.
|
||||
if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory.
|
||||
if(!force)
|
||||
D.gc_destroyed = null //clear the gc variable (important!)
|
||||
return
|
||||
@@ -350,17 +362,17 @@ SUBSYSTEM_DEF(garbage)
|
||||
I.no_respect_force++
|
||||
|
||||
SSgarbage.Queue(D)
|
||||
if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete
|
||||
if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete
|
||||
SSgarbage.Queue(D, GC_QUEUE_HARDDELETE)
|
||||
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
|
||||
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
|
||||
SSgarbage.HardDelete(D)
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
if (QDEL_HINT_FINDREFERENCE) //qdel will, if LEGACY_REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion.
|
||||
#ifdef REFERENCE_TRACKING
|
||||
if (QDEL_HINT_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion.
|
||||
SSgarbage.Queue(D)
|
||||
D.find_references_legacy()
|
||||
if (QDEL_HINT_IFFAIL_FINDREFERENCE)
|
||||
D.find_references()
|
||||
if (QDEL_HINT_IFFAIL_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled and the object fails to collect, display all references to this object.
|
||||
SSgarbage.Queue(D)
|
||||
SSgarbage.reference_find_on_fail[REF(D)] = TRUE
|
||||
SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE
|
||||
#endif
|
||||
else
|
||||
#ifdef TESTING
|
||||
@@ -371,18 +383,3 @@ SUBSYSTEM_DEF(garbage)
|
||||
SSgarbage.Queue(D)
|
||||
else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")
|
||||
|
||||
#ifdef TESTING
|
||||
/proc/writeDatumCount()
|
||||
var/list/datums = list()
|
||||
for(var/datum/D in world)
|
||||
datums[D.type] += 1
|
||||
for(var/datum/D)
|
||||
datums[D.type] += 1
|
||||
datums = sortTim(datums, /proc/cmp_numeric_dsc, associative = TRUE)
|
||||
if(fexists("data/DATUMCOUNT.txt"))
|
||||
fdel("data/DATUMCOUNT.txt")
|
||||
var/outfile = file("data/DATUMCOUNT.txt")
|
||||
for(var/path in datums)
|
||||
outfile << "[datums[path]]\t\t\t\t\t[path]"
|
||||
#endif
|
||||
|
||||
@@ -366,10 +366,16 @@ SUBSYSTEM_DEF(research)
|
||||
techweb_categories[I.category] = list(I.id = TRUE)
|
||||
|
||||
/datum/controller/subsystem/research/proc/techweb_node_by_id(id)
|
||||
return techweb_nodes[id] || error_node
|
||||
if(techweb_nodes[id])
|
||||
return techweb_nodes[id]
|
||||
stack_trace("Attempted to access node ID [id] which didn't exist")
|
||||
return error_node
|
||||
|
||||
/datum/controller/subsystem/research/proc/techweb_design_by_id(id)
|
||||
return techweb_designs[id] || error_design
|
||||
if(techweb_designs[id])
|
||||
return techweb_designs[id]
|
||||
stack_trace("Attempted to access design ID [id] which didn't exist")
|
||||
return error_design
|
||||
|
||||
/datum/controller/subsystem/research/proc/on_design_deletion(datum/design/D)
|
||||
for(var/i in techweb_nodes)
|
||||
|
||||
@@ -68,7 +68,7 @@ SUBSYSTEM_DEF(vote)
|
||||
//get the highest number of votes
|
||||
var/greatest_votes = 0
|
||||
var/total_votes = 0
|
||||
if(mode == "gamemode" && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
|
||||
if((mode == "gamemode" || mode == "roundtype") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
|
||||
for(var/mob/dead/new_player/P in GLOB.player_list)
|
||||
if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey])
|
||||
choices[choices[voted[P.ckey]]]--
|
||||
@@ -105,7 +105,7 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
/datum/controller/subsystem/vote/proc/calculate_condorcet_votes(var/blackbox_text)
|
||||
// https://en.wikipedia.org/wiki/Schulze_method#Implementation
|
||||
if((mode == "gamemode" || mode == "dynamic") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
|
||||
if((mode == "gamemode" || mode == "dynamic" || mode == "roundtype") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
|
||||
for(var/mob/dead/new_player/P in GLOB.player_list)
|
||||
if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey])
|
||||
voted -= P.ckey
|
||||
@@ -155,7 +155,7 @@ SUBSYSTEM_DEF(vote)
|
||||
for(var/choice in choices)
|
||||
scores_by_choice += "[choice]"
|
||||
scores_by_choice["[choice]"] = list()
|
||||
if((mode == "gamemode" || mode == "dynamic") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
|
||||
if((mode == "gamemode" || mode == "dynamic" || mode == "roundtype") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
|
||||
for(var/mob/dead/new_player/P in GLOB.player_list)
|
||||
if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey])
|
||||
voted -= P.ckey
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/datum/atmosphere
|
||||
var/gas_string
|
||||
var/id
|
||||
|
||||
var/list/base_gases // A list of gases to always have
|
||||
var/list/normal_gases // A list of allowed gases:base_amount
|
||||
var/list/restricted_gases // A list of allowed gases like normal_gases but each can only be selected a maximum of one time
|
||||
var/restricted_chance = 10 // Chance per iteration to take from restricted gases
|
||||
|
||||
var/minimum_pressure
|
||||
var/maximum_pressure
|
||||
|
||||
var/minimum_temp
|
||||
var/maximum_temp
|
||||
|
||||
/datum/atmosphere/New()
|
||||
generate_gas_string()
|
||||
|
||||
/datum/atmosphere/proc/generate_gas_string()
|
||||
var/list/spicy_gas = restricted_gases.Copy()
|
||||
var/target_pressure = rand(minimum_pressure, maximum_pressure)
|
||||
var/pressure_scale = target_pressure / maximum_pressure
|
||||
|
||||
// First let's set up the gasmix and base gases for this template
|
||||
// We make the string from a gasmix in this proc because gases need to calculate their pressure
|
||||
var/datum/gas_mixture/gasmix = new
|
||||
gasmix.set_temperature(rand(minimum_temp, maximum_temp))
|
||||
for(var/i in base_gases)
|
||||
gasmix.set_moles(i, base_gases[i])
|
||||
|
||||
// Now let the random choices begin
|
||||
var/gastype
|
||||
var/amount
|
||||
while(gasmix.return_pressure() < target_pressure)
|
||||
if(!prob(restricted_chance) || !length(spicy_gas))
|
||||
gastype = pick(normal_gases)
|
||||
amount = normal_gases[gastype]
|
||||
else
|
||||
gastype = pick(spicy_gas)
|
||||
amount = spicy_gas[gastype]
|
||||
spicy_gas -= gastype //You can only pick each restricted gas once
|
||||
|
||||
amount *= rand(50, 200) / 100 // Randomly modifes the amount from half to double the base for some variety
|
||||
amount *= pressure_scale // If we pick a really small target pressure we want roughly the same mix but less of it all
|
||||
amount = CEILING(amount, 0.1)
|
||||
|
||||
gasmix.adjust_moles(gastype, amount)
|
||||
|
||||
// That last one put us over the limit, remove some of it
|
||||
if(gasmix.return_pressure() > target_pressure)
|
||||
var/moles_to_remove = (1 - target_pressure / gasmix.return_pressure()) * gasmix.total_moles()
|
||||
gasmix.adjust_moles(gastype, -moles_to_remove)
|
||||
gasmix.set_moles(gastype, FLOOR(gasmix.get_moles(gastype), 0.1))
|
||||
|
||||
// Now finally lets make that string
|
||||
var/list/gas_string_builder = list()
|
||||
for(var/id in gasmix.get_gases())
|
||||
gas_string_builder += "[id]=[gasmix.get_moles(id)]"
|
||||
gas_string_builder += "TEMP=[gasmix.return_temperature()]"
|
||||
gas_string = gas_string_builder.Join(";")
|
||||
@@ -0,0 +1,48 @@
|
||||
// Atmos types used for planetary airs
|
||||
/datum/atmosphere/lavaland
|
||||
id = LAVALAND_DEFAULT_ATMOS
|
||||
|
||||
base_gases = list(
|
||||
GAS_O2=5,
|
||||
GAS_N2=10,
|
||||
)
|
||||
normal_gases = list(
|
||||
GAS_O2=10,
|
||||
GAS_N2=10,
|
||||
GAS_CO2=10,
|
||||
)
|
||||
restricted_gases = list(
|
||||
GAS_BZ=0.1,
|
||||
GAS_METHYL_BROMIDE=0.1,
|
||||
)
|
||||
restricted_chance = 30
|
||||
|
||||
minimum_pressure = HAZARD_LOW_PRESSURE + 10
|
||||
maximum_pressure = LAVALAND_EQUIPMENT_EFFECT_PRESSURE - 1
|
||||
|
||||
minimum_temp = BODYTEMP_COLD_DAMAGE_LIMIT + 1
|
||||
maximum_temp = 320
|
||||
|
||||
/datum/atmosphere/icemoon
|
||||
id = ICEMOON_DEFAULT_ATMOS
|
||||
|
||||
base_gases = list(
|
||||
GAS_O2=5,
|
||||
GAS_N2=10,
|
||||
)
|
||||
normal_gases = list(
|
||||
GAS_O2=10,
|
||||
GAS_N2=10,
|
||||
GAS_CO2=10,
|
||||
)
|
||||
restricted_gases = list(
|
||||
GAS_METHYL_BROMIDE=0.1,
|
||||
)
|
||||
restricted_chance = 10
|
||||
|
||||
minimum_pressure = HAZARD_LOW_PRESSURE + 10
|
||||
maximum_pressure = LAVALAND_EQUIPMENT_EFFECT_PRESSURE - 1
|
||||
|
||||
minimum_temp = 180
|
||||
maximum_temp = 180
|
||||
|
||||
@@ -264,3 +264,36 @@
|
||||
speak_dejavu += speech_args[SPEECH_MESSAGE]
|
||||
else
|
||||
speak_dejavu += speech_args[SPEECH_MESSAGE]
|
||||
|
||||
/datum/brain_trauma/mild/redacted
|
||||
name = "Confidentiality Trauma"
|
||||
desc = "Patient's language neurons seem to be warped in a strange manner, resulting in them being unable to speak properly."
|
||||
scan_desc = "<b>\[REDACTED]</b>"
|
||||
gain_text = "<span class='warning'>You feel the need to <b>\[REDACTED]</b></span>"
|
||||
lose_text = "<span class='notice'>You no longer feel the need to <b>\[REDACTED]</b>.</span>"
|
||||
|
||||
/datum/brain_trauma/mild/redacted/handle_speech(datum/source, list/speech_args)
|
||||
var/message = speech_args[SPEECH_MESSAGE]
|
||||
if(message)
|
||||
var/list/message_split = splittext(message, " ")
|
||||
var/list/new_message = list()
|
||||
|
||||
for(var/word in message_split)
|
||||
var/suffix = ""
|
||||
var/suffix_foundon = 0
|
||||
for(var/potential_suffix in list("." , "," , ";" , "!" , ":" , "?"))
|
||||
suffix_foundon = findtext(word, potential_suffix, -length(potential_suffix))
|
||||
if(suffix_foundon)
|
||||
suffix = potential_suffix
|
||||
break
|
||||
|
||||
if(suffix_foundon)
|
||||
word = copytext(word, 1, suffix_foundon)
|
||||
|
||||
word = html_decode(word)
|
||||
|
||||
if(prob(25))
|
||||
word = pick(list("<b>\[REDACTED]</b>", "<b>\[CLASSIFIED]</b>", "<b>\[EXPUNGED]</b>"))
|
||||
new_message += word + suffix
|
||||
message = jointext(new_message, " ")
|
||||
speech_args[SPEECH_MESSAGE] = trim(message)
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
R.update_icon()
|
||||
to_chat(user, "<span class='info'>You strengthen [R], improving its resistance against melee, bullet and laser damage.</span>")
|
||||
else
|
||||
SEND_SIGNAL(O, COMSIG_ARMOR_PLATED, amount, maxamount)
|
||||
to_chat(user, "<span class='info'>You strengthen [O], improving its resistance against melee attacks.</span>")
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//This file is for glass working types of things!
|
||||
|
||||
/obj/item/glasswork
|
||||
name = "This is a bug report it!"
|
||||
desc = "Failer to code. Contact your local bug remover..."
|
||||
name = "this is a bug!"
|
||||
desc = "Uh oh, the coders did a fucky wucky! Contact your local code monkey and tell them about this!"
|
||||
icon = 'icons/obj/glassworks.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
force = 1
|
||||
@@ -11,45 +11,45 @@
|
||||
tool_behaviour = null
|
||||
|
||||
/obj/item/glasswork/glasskit
|
||||
name = "Glass working tools"
|
||||
desc = "A lovely belt of most the tools you will need to shape, mold, and refine glass into more advanced shapes."
|
||||
name = "glasswork tools"
|
||||
desc = "A set of most the tools you will need to shape, mold, and refine glass into more advanced shapes."
|
||||
icon_state = "glass_tools"
|
||||
tool_behaviour = TOOL_GLASS_CUT //Cutting takes 20 ticks
|
||||
|
||||
/obj/item/glasswork/blowing_rod
|
||||
name = "Glass working blow rod"
|
||||
desc = "A hollow metal stick made for glass blowing."
|
||||
name = "glassblowing rod"
|
||||
desc = "A hollow metal rod made for blowing glass."
|
||||
icon_state = "blowing_rods_unused"
|
||||
tool_behaviour = TOOL_BLOW //Rods take 5 ticks
|
||||
|
||||
/obj/item/glasswork/glass_base //Welding takes 30 ticks
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A sheet of glass set aside for glass working"
|
||||
name = "glass fodder sheet"
|
||||
desc = "A sheet of glass set aside for glass working."
|
||||
icon_state = "glass_base"
|
||||
var/next_step = null
|
||||
var/rod = /obj/item/glasswork/blowing_rod
|
||||
|
||||
/obj/item/tea_plate
|
||||
name = "Tea Plate"
|
||||
name = "tea saucer"
|
||||
desc = "A polished plate for a tea cup. How fancy!"
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "tea_plate"
|
||||
|
||||
/obj/item/tea_cup
|
||||
name = "Tea Cup"
|
||||
desc = "A glass cup made for fake tea!"
|
||||
name = "tea cup"
|
||||
desc = "A glass cup made for sipping tea!"
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "tea_plate"
|
||||
|
||||
//////////////////////Chem Disk/////////////////////
|
||||
//Two Steps //
|
||||
//Sells for 300 cr, takes 10 glass shets //
|
||||
//Usefull for chem spliting //
|
||||
//Useful for chem spliting //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/dish
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a small glass dish. Needs to be cut with some tools."
|
||||
name = "glass fodder sheet (dish)"
|
||||
desc = "A set of glass sheets set aside for glass working. This one is ideal for a small glass dish. It needs to be cut with some glassworking tools."
|
||||
next_step = /obj/item/glasswork/glass_base/dish_part1
|
||||
|
||||
/obj/item/glasswork/glass_base/dish/attackby(obj/item/I, mob/user, params)
|
||||
@@ -60,8 +60,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/dish_part1
|
||||
name = "Half chem dish sheet"
|
||||
desc = "A sheet of glass cut in half, looks like it still needs some more cutting down"
|
||||
name = "half glass fodder sheet (dish)"
|
||||
desc = "A sheet of glass cut in half. It looks like it still needs some more cutting down."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/reagent_containers/glass/beaker/glass_dish
|
||||
|
||||
@@ -75,12 +75,12 @@
|
||||
//////////////////////Lens//////////////////////////
|
||||
//Six Steps //
|
||||
//Sells for 1600 cr, takes 15 glass shets //
|
||||
//Usefull for selling and later crafting //
|
||||
//Useful for selling and later crafting //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a small glass lens. Needs to be cut with some tools."
|
||||
name = "glass fodder sheet (lens)"
|
||||
desc = "A set of glass sheets set aside for glass working. This one is ideal for a glass lens. It needs to be cut with some glassworking tools."
|
||||
next_step = /obj/item/glasswork/glass_base/glass_lens_part1
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens/attackby(obj/item/I, mob/user, params)
|
||||
@@ -91,8 +91,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part1
|
||||
name = "Glass fodder sheet"
|
||||
desc = "Cut glass ready to be heated. Needs to be heated with some tools."
|
||||
name = "half glass fodder sheet (lens)"
|
||||
desc = "Cut glass ready to be heated with something very hot."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/glasswork/glass_base/glass_lens_part2
|
||||
|
||||
@@ -104,8 +104,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part2
|
||||
name = "Glass fodder sheet"
|
||||
desc = "Cut glass that has been heated. Needs to be heated more with some tools."
|
||||
name = "heated half glass fodder sheet (lens)"
|
||||
desc = "Cut glass that has been heated once already and is ready to be heated again."
|
||||
icon_state = "glass_base_heat"
|
||||
next_step = /obj/item/glasswork/glass_base/glass_lens_part3
|
||||
|
||||
@@ -117,8 +117,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part3
|
||||
name = "Glass fodder sheet"
|
||||
desc = "Cut glass that has been heated into a blob of hot glass. Needs to be placed onto a blow tube."
|
||||
name = "heated glass blob (lens)"
|
||||
desc = "Cut glass that has been heated into a blob. It needs to be attached to a glassblowing rod."
|
||||
icon_state = "glass_base_molding"
|
||||
next_step = /obj/item/glasswork/glass_base/glass_lens_part4
|
||||
|
||||
@@ -131,8 +131,8 @@
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part4
|
||||
name = "Glass fodder sheet"
|
||||
desc = "Cut glass that has been heated into a blob of hot glass. Needs to be cut off onto a blow tube."
|
||||
name = "glassblowing rod (lens)"
|
||||
desc = "A hollow metal rod made for blowing glass. There is a blob of shapen glass at the end of it that needs to be cut off with some glassworking tools."
|
||||
icon_state = "blowing_rods_inuse"
|
||||
next_step = /obj/item/glasswork/glass_base/glass_lens_part5
|
||||
|
||||
@@ -145,8 +145,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part5
|
||||
name = "Unpolished glass lens"
|
||||
desc = "A small unpolished glass lens. Could be polished with some cloth."
|
||||
name = "unpolished glass lens"
|
||||
desc = "An unpolished glass lens. It needs to be polished with some dry cloth."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "glass_optics"
|
||||
next_step = /obj/item/glasswork/glass_base/glass_lens_part6
|
||||
@@ -159,8 +159,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part6
|
||||
name = "Unrefined glass lens"
|
||||
desc = "A small polished glass lens. Just needs to be refined with some sandstone."
|
||||
name = "unrefined glass lens"
|
||||
desc = "A polished glass lens. It needs to be refined with some sandstone."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "glass_optics"
|
||||
next_step = /obj/item/glasswork/glass_base/lens
|
||||
@@ -174,12 +174,12 @@
|
||||
//////////////////////Spouty Flask//////////////////
|
||||
//Four Steps //
|
||||
//Sells for 1200 cr, takes 20 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
//Useful for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/spouty
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a spout beaker. Needs to be cut with some tools."
|
||||
name = "Glass fodder sheet (spout)"
|
||||
desc = "A set of glass sheets set aside for glass working. This one is ideal for a spouty flask. It needs to heated with something very hot."
|
||||
next_step = /obj/item/glasswork/glass_base/spouty_part2
|
||||
|
||||
/obj/item/glasswork/glass_base/spouty/attackby(obj/item/I, mob/user, params)
|
||||
@@ -190,8 +190,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/spouty_part2
|
||||
name = "Glass fodder sheet"
|
||||
desc = "Cut glass that has been heated. Needs to be heated with some tools."
|
||||
name = "glass fodder sheet (spout)"
|
||||
desc = "Cut glass ready to be heated with something very hot."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/glasswork/glass_base/spouty_part3
|
||||
|
||||
@@ -203,8 +203,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/spouty_part3
|
||||
name = "Glass fodder sheet"
|
||||
desc = "Cut glass that has been heated into a blob of hot glass. Needs to be placed onto a blow tube."
|
||||
name = "heated glass blob (spout)"
|
||||
desc = "Cut glass that has been heated into a blob. It needs to be attached to a glassblowing rod."
|
||||
icon_state = "glass_base_molding"
|
||||
next_step = /obj/item/glasswork/glass_base/spouty_part4
|
||||
|
||||
@@ -217,8 +217,8 @@
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/spouty_part4
|
||||
name = "Glass fodder sheet"
|
||||
desc = "Cut glass that has been heated into a blob of hot glass. Needs to be cut off onto a blow tube."
|
||||
name = "glassblowing rod (spout)"
|
||||
desc = "A hollow metal rod made for blowing glass. There is a blob of shapen glass at the end of it that needs to be cut off with some glassworking tools."
|
||||
icon_state = "blowing_rods_inuse"
|
||||
next_step = /obj/item/reagent_containers/glass/beaker/flask/spouty
|
||||
|
||||
@@ -233,12 +233,12 @@
|
||||
//////////////////////Small Bulb Flask//////////////
|
||||
//Two Steps //
|
||||
//Sells for 600 cr, takes 5 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
//Useful for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_small
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a small flask. Needs to be heated with some tools."
|
||||
name = "glass fodder sheet (small flask)"
|
||||
desc = "A set of glass sheets set aside for glass working. This one is ideal for a small flask. It needs to heated with something very hot."
|
||||
next_step = /obj/item/glasswork/glass_base/flask_small_part1
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_small/attackby(obj/item/I, mob/user, params)
|
||||
@@ -249,8 +249,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_small_part1
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass, this one is ideal for a small flask. Needs to be blown with some tools."
|
||||
name = "heated glass blob (small flask)"
|
||||
desc = "Glass that has been heated into a blob. It needs to be attached to a glassblowing rod."
|
||||
icon_state = "glass_base_molding"
|
||||
next_step = /obj/item/glasswork/glass_base/flask_small_part2
|
||||
|
||||
@@ -263,8 +263,8 @@
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_small_part2
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass on the end of a blowing rod. Needs to be cut off with some tools."
|
||||
name = "glassblowing rod (small flask)"
|
||||
desc = "A hollow metal rod made for blowing glass. There is a blob of shapen glass at the end of it that needs to be cut off with some glassworking tools."
|
||||
icon_state = "blowing_rods_inuse"
|
||||
next_step = /obj/item/reagent_containers/glass/beaker/flask
|
||||
|
||||
@@ -279,12 +279,12 @@
|
||||
//////////////////////Large Bulb Flask//////////////
|
||||
//Two Steps //
|
||||
//Sells for 1000 cr, takes 15 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
//Useful for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_large
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a large flask. Needs to be heated with some tools."
|
||||
name = "glass fodder sheet (large flask)"
|
||||
desc = "A set of glass sheets set aside for glass working. This one is ideal for a large flask. It needs to heated with something very hot."
|
||||
next_step = /obj/item/glasswork/glass_base/flask_large_part1
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_large/attackby(obj/item/I, mob/user, params)
|
||||
@@ -295,8 +295,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_large_part1
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass, this one is ideal for a large flask. Needs to be blown with some tools."
|
||||
name = "heated glass blob (large flask)"
|
||||
desc = "Glass that has been heated into a blob. It needs to be attached to a glassblowing rod."
|
||||
icon_state = "glass_base_molding"
|
||||
next_step = /obj/item/glasswork/glass_base/flask_large_part2
|
||||
|
||||
@@ -309,8 +309,8 @@
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_large_part2
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass on the end of a blowing rod. Needs to be cut off with some tools."
|
||||
name = "glassblowing rod (small flask)"
|
||||
desc = "A hollow metal rod made for blowing glass. There is a blob of shapen glass at the end of it that needs to be cut off with some glassworking tools."
|
||||
icon_state = "blowing_rods_inuse"
|
||||
next_step = /obj/item/reagent_containers/glass/beaker/flask/large
|
||||
|
||||
@@ -325,12 +325,12 @@
|
||||
//////////////////////Tea Plates////////////////////
|
||||
//Three Steps //
|
||||
//Sells for 1000 cr, takes 5 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
//Useful for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a tea plate, how fancy! Needs to be heated with some tools."
|
||||
name = "glass fodder sheet (tea saucer)"
|
||||
desc = "A set of glass sheets set aside for glass working. This one is ideal for a tea saucer. It needs to heated with something very hot."
|
||||
next_step = /obj/item/glasswork/glass_base/tea_plate1
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate/attackby(obj/item/I, mob/user, params)
|
||||
@@ -341,8 +341,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate1
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass, this one is ideal for a tea plate. Needs to be blown with some tools."
|
||||
name = "heated glass blob (tea saucer)"
|
||||
desc = "Glass that has been heated into a blob. It needs to be attached to a glassblowing rod."
|
||||
icon_state = "glass_base_molding"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_plate2
|
||||
|
||||
@@ -355,8 +355,8 @@
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate2
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass on the end of a blowing rod. Needs to be cut off with some tools."
|
||||
name = "glassblowing rod (tea saucer)"
|
||||
desc = "A hollow metal rod made for blowing glass. There is a blob of shapen glass at the end of it that needs to be cut off with some glassworking tools."
|
||||
icon_state = "blowing_rods_inuse"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_plate3
|
||||
|
||||
@@ -369,8 +369,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate3
|
||||
name = "Disk of glass"
|
||||
desc = "A disk of glass that can be cant be used for much. Needs to be polished with some cloth."
|
||||
name = "unpolished glass saucer (tea saucer)"
|
||||
desc = "An unpolished glass saucer. It needs to be polished with some dry cloth."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/tea_plate
|
||||
|
||||
@@ -384,12 +384,12 @@
|
||||
//////////////////////Tea Cup///////////////////////
|
||||
//Four Steps //
|
||||
//Sells for 1600 cr, takes 6 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
//Useful for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a tea cup, how fancy! Needs to be heated with some tools."
|
||||
name = "glass fodder sheet (tea cup)"
|
||||
desc = "A set of glass sheets set aside for glass working. This one is ideal for a tea cup. It needs to heated with something very hot."
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup1
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup/attackby(obj/item/I, mob/user, params)
|
||||
@@ -400,8 +400,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup1
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass, this one is ideal for a tea cup. Needs to be blown with some tools."
|
||||
name = "heated glass blob (tea cup)"
|
||||
desc = "Glass that has been heated into a blob. It needs to be attached to a glassblowing rod."
|
||||
icon_state = "glass_base_molding"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup2
|
||||
|
||||
@@ -414,8 +414,8 @@
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cupe2
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass on the end of a blowing rod. Needs to be cut off with some tools."
|
||||
name = "glassblowing rod (tea cup)"
|
||||
desc = "A hollow metal rod made for blowing glass. There is a blob of shapen glass at the end of it that needs to be cut off with some glassworking tools."
|
||||
icon_state = "blowing_rods_inuse"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup3
|
||||
|
||||
@@ -428,8 +428,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup3
|
||||
name = "Disk of glass"
|
||||
desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some cloth."
|
||||
name = "unpolished glass cup (tea cup)"
|
||||
desc = "An unpolished glass cup. It needs to be polished with some dry cloth."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup4
|
||||
|
||||
@@ -441,8 +441,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup4
|
||||
name = "Disk of glass"
|
||||
desc = "A bowl of polished glass that can be cant be used for much. Needs some more glass to make a handle."
|
||||
name = "polished glass cup (tea cup)"
|
||||
desc = "A polished glass cup. It needs some extra glass to form a handle."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/tea_cup
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
//This file is for crafting using a lens!
|
||||
|
||||
/obj/item/glasswork/glass_base/lens
|
||||
name = "Optical lens"
|
||||
desc = "Good for selling or crafting, by itself its useless"
|
||||
name = "optical lens"
|
||||
desc = "A glass lens. Useless by itself, but may prove useful in making something with a focus."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "glass_optics"
|
||||
|
||||
//Laser pointers - 2600
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell
|
||||
name = "Laser pointer assembly"
|
||||
desc = "Good for selling or crafting, by itself its useless. Needs a power capactor."
|
||||
name = "laser pointer assembly"
|
||||
desc = "An empty hull of a laser pointer. It's missing a capacitor."
|
||||
icon_state = "laser_case"
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
next_step = /obj/item/glasswork/glass_base/laserpointer_shell_1
|
||||
@@ -21,8 +21,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell_1
|
||||
name = "Laser pointer assembly"
|
||||
desc = "Good for selling or crafting, by itself its useless. Needs a glass lens."
|
||||
name = "powered laser pointer assembly"
|
||||
desc = "A laser pointer hull with a capacitor inside of it. It's missing a lens."
|
||||
icon_state = "laser_wire"
|
||||
icon_state = "laser_case"
|
||||
next_step = /obj/item/glasswork/glass_base/laserpointer_shell_2
|
||||
@@ -34,8 +34,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell_2
|
||||
name = "Laser pointer assembly"
|
||||
desc = "Good for selling or crafting, by itself its useless. Needs to be screwed together."
|
||||
name = "near-complete laser pointer assembly"
|
||||
desc = "A laser pointer hull with a capacitor and a lens inside of it. It needs to be screwed together."
|
||||
icon_state = "laser_wire"
|
||||
icon_state = "laser_case"
|
||||
next_step = /obj/item/laser_pointer/blue/handmade
|
||||
@@ -50,8 +50,8 @@
|
||||
//NERD SHIT - 5000
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame
|
||||
name = "Glasses Frame"
|
||||
desc = "Good for crafting a pare of glasses, by itself its useless. Just add a pare of lens."
|
||||
name = "glasses frame"
|
||||
desc = "A pair of glasses without the lenses. You could probably add them yourself, though."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames"
|
||||
next_step = /obj/item/glasswork/glass_base/glasses_frame_1
|
||||
@@ -64,8 +64,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame_1
|
||||
name = "Glasses Frame"
|
||||
desc = "Good for crafting a pare of glasses, by itself its useless. Just add a the other lens."
|
||||
name = "glasses frame"
|
||||
desc = "A pair of shoddily-assembled glasses with only one lens. You could probably add the second one yourself, though."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames_1"
|
||||
next_step = /obj/item/glasswork/glass_base/glasses_frame_2
|
||||
@@ -78,8 +78,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame_2
|
||||
name = "Glasses Frame"
|
||||
desc = "Good for crafting a pare of glasses, by itself its useless. Just adjust the pices into the frame with a screwdriver."
|
||||
name = "glasses frame"
|
||||
desc = "A pair of hastily-assembled unfitted glasses with both lenses intact. Use a screwdriver to fit them."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames_2"
|
||||
next_step = /obj/item/glasswork/glasses
|
||||
@@ -92,7 +92,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glasses
|
||||
name = "Handmade Glasses"
|
||||
desc = "Handmade glasses that have not been polished at all making them useless. Selling them could still be worth a few credits."
|
||||
name = "handmade glasses"
|
||||
desc = "A pair of poorly-assembled glasses clearly produced by someone with no qualifications in making glasses. They're smudged, ugly, and don't even fit you. They might be worth some money, though."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames_2"
|
||||
|
||||
@@ -135,6 +135,8 @@
|
||||
var/obj/item/I = AM
|
||||
var/mob/M = parent.loc
|
||||
I.dropped(M)
|
||||
I.item_flags &= ~IN_STORAGE
|
||||
I.remove_outline()
|
||||
if(new_location)
|
||||
AM.forceMove(new_location) // exited comsig will handle removal reset.
|
||||
//We don't want to call this if the item is being destroyed
|
||||
@@ -180,6 +182,7 @@
|
||||
I.forceMove(parent.drop_location())
|
||||
return FALSE
|
||||
I.on_enter_storage(master)
|
||||
I.item_flags |= IN_STORAGE
|
||||
refresh_mob_views()
|
||||
I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
|
||||
if(M)
|
||||
|
||||
@@ -423,6 +423,9 @@
|
||||
var/atom/A = parent
|
||||
if(ismob(M)) //all the check for item manipulation are in other places, you can safely open any storages as anything and its not buggy, i checked
|
||||
A.add_fingerprint(M)
|
||||
if(istype(A, /obj/item))
|
||||
var/obj/item/I = A
|
||||
I.remove_outline() //Removes the outline when we drag
|
||||
if(!over_object)
|
||||
return FALSE
|
||||
if(ismecha(M.loc)) // stops inventory actions in a mech
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
var/mob/living/L = parent
|
||||
if(L.incapacitated() || L.lying)
|
||||
return
|
||||
var/matrix/otransform = matrix(L.transform) //make a copy of the current transform
|
||||
animate(L, pixel_z = 4, time = 0)
|
||||
animate(pixel_z = 0, transform = turn(matrix(), pick(-12, 0, 12)), time=2)
|
||||
animate(pixel_z = 0, transform = matrix(), time = 0)
|
||||
animate(pixel_z = 0, transform = turn(L.transform, pick(-12, 0, 12)), time=2) //waddle.
|
||||
animate(pixel_z = 0, transform = otransform, time = 0) //return to previous transform.
|
||||
|
||||
@@ -57,9 +57,13 @@
|
||||
*/
|
||||
var/list/cooldowns
|
||||
|
||||
#ifdef TESTING
|
||||
#ifdef REFERENCE_TRACKING
|
||||
var/running_find_references
|
||||
var/last_find_references = 0
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
///Stores info about where refs are found, used for sanity checks and testing
|
||||
var/list/found_refs
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DATUMVAR_DEBUGGING_MODE
|
||||
|
||||
@@ -386,6 +386,14 @@
|
||||
qdel(language_holder)
|
||||
var/species_holder = initial(mrace.species_language_holder)
|
||||
language_holder = new species_holder(src)
|
||||
|
||||
var/mob/living/carbon/human/H = src
|
||||
//provide the user's additional language to the new language holder even if they change species
|
||||
if(H.additional_language && H.additional_language != "None")
|
||||
var/language_entry = GLOB.roundstart_languages[H.additional_language]
|
||||
if(language_entry)
|
||||
grant_language(language_entry, TRUE, TRUE)
|
||||
|
||||
update_atom_languages()
|
||||
|
||||
/mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
Stack End Detector.
|
||||
Can detect if a given code stack has exited, used by the mc for stack overflow detection.
|
||||
|
||||
**/
|
||||
/datum/stack_end_detector
|
||||
var/datum/weakref/_WF
|
||||
var/datum/stack_canary/_canary
|
||||
|
||||
/datum/stack_end_detector/New()
|
||||
_canary = new()
|
||||
_WF = WEAKREF(_canary)
|
||||
|
||||
/** Prime the stack overflow detector.
|
||||
Store the return value of this proc call in a proc level var.
|
||||
Can only be called once.
|
||||
**/
|
||||
/datum/stack_end_detector/proc/prime_canary()
|
||||
if (!_canary)
|
||||
CRASH("Prime_canary called twice")
|
||||
. = _canary
|
||||
_canary = null
|
||||
|
||||
/// Returns true if the stack is still going. Calling before the canary has been primed also returns true
|
||||
/datum/stack_end_detector/proc/check()
|
||||
return !!_WF.resolve()
|
||||
|
||||
/// Stack canary. Will go away if the stack it was primed by is ended by byond for return or stack overflow reasons.
|
||||
/datum/stack_canary
|
||||
|
||||
/// empty proc to avoid warnings about unused variables. Call this proc on your canary in the stack it's watching.
|
||||
/datum/stack_canary/proc/use_variable()
|
||||
+11
-3
@@ -6,10 +6,12 @@
|
||||
var/body
|
||||
var/headers
|
||||
var/url
|
||||
/// If present response body will be saved to this file.
|
||||
var/output_file
|
||||
|
||||
var/_raw_response
|
||||
|
||||
/datum/http_request/proc/prepare(method, url, body = "", list/headers)
|
||||
/datum/http_request/proc/prepare(method, url, body = "", list/headers, output_file)
|
||||
if (!length(headers))
|
||||
headers = ""
|
||||
else
|
||||
@@ -19,15 +21,16 @@
|
||||
src.url = url
|
||||
src.body = body
|
||||
src.headers = headers
|
||||
src.output_file = output_file
|
||||
|
||||
/datum/http_request/proc/execute_blocking()
|
||||
_raw_response = rustg_http_request_blocking(method, url, body, headers)
|
||||
_raw_response = rustg_http_request_blocking(method, url, body, headers, build_options())
|
||||
|
||||
/datum/http_request/proc/begin_async()
|
||||
if (in_progress)
|
||||
CRASH("Attempted to re-use a request object.")
|
||||
|
||||
id = rustg_http_request_async(method, url, body, headers)
|
||||
id = rustg_http_request_async(method, url, body, headers, build_options())
|
||||
|
||||
if (isnull(text2num(id)))
|
||||
stack_trace("Proc error: [id]")
|
||||
@@ -35,6 +38,11 @@
|
||||
else
|
||||
in_progress = TRUE
|
||||
|
||||
/datum/http_request/proc/build_options()
|
||||
if(output_file)
|
||||
return json_encode(list("output_filename"=output_file,"body_filename"=null))
|
||||
return null
|
||||
|
||||
/datum/http_request/proc/is_complete()
|
||||
if (isnull(id))
|
||||
return TRUE
|
||||
|
||||
@@ -162,3 +162,20 @@
|
||||
gain_text = "<span class='notice'>You feel like munching on a can of soda.</span>"
|
||||
lose_text = "<span class='notice'>You no longer feel like you should be eating trash.</span>"
|
||||
mob_trait = TRAIT_TRASHCAN
|
||||
|
||||
/datum/quirk/colorist
|
||||
name = "Colorist"
|
||||
desc = "You like carrying around a hair dye spray to quickly apply color patterns to your hair."
|
||||
value = 0
|
||||
medical_record_text = "Patient enjoys dyeing their hair with pretty colors."
|
||||
|
||||
/datum/quirk/colorist/on_spawn()
|
||||
var/mob/living/carbon/human/H = quirk_holder
|
||||
var/obj/item/dyespray/spraycan = new(get_turf(quirk_holder))
|
||||
H.equip_to_slot(spraycan, SLOT_IN_BACKPACK)
|
||||
H.regenerate_icons()
|
||||
|
||||
/datum/quirk/colorist/post_add()
|
||||
var/mob/living/carbon/human/H = quirk_holder
|
||||
SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_SHOW, H)
|
||||
to_chat(quirk_holder, "<span class='boldnotice'>You brought some extra dye with you! It's in your bag if you forgot.</span>")
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
area_type = /area
|
||||
protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer,
|
||||
/area/ai_monitored/turret_protected/ai, /area/commons/storage/emergency/starboard, /area/commons/storage/emergency/port, /area/shuttle, /area/security/prison/safe, /area/security/prison/toilet)
|
||||
/area/ai_monitored/turret_protected/ai, /area/commons/storage/emergency/starboard, /area/commons/storage/emergency/port, /area/shuttle)
|
||||
target_trait = ZTRAIT_STATION
|
||||
|
||||
immunity_type = "rad"
|
||||
|
||||
@@ -329,3 +329,15 @@
|
||||
to_chat(L, "<span class='warning'>You need an attachable assembly!</span>")
|
||||
|
||||
#undef MAXIMUM_EMP_WIRES
|
||||
|
||||
//gremlins
|
||||
/datum/wires/proc/npc_tamper(mob/living/L)
|
||||
if(!wires.len)
|
||||
return
|
||||
|
||||
var/wire_to_screw = pick(wires)
|
||||
|
||||
if(is_color_cut(wire_to_screw) || prob(50)) //CutWireColour() proc handles both cutting and mending wires. If the wire is already cut, always mend it back. Otherwise, 50% to cut it and 50% to pulse it
|
||||
cut(wire_to_screw)
|
||||
else
|
||||
pulse(wire_to_screw, L)
|
||||
|
||||
@@ -37,7 +37,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
/area/ai_monitored/turret_protected/AIsatextAP
|
||||
name = "AI Sat Ext"
|
||||
icon_state = "storage"
|
||||
|
||||
|
||||
/area/arrival
|
||||
requires_power = FALSE
|
||||
|
||||
@@ -296,6 +296,28 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
icon_state = "xenomaint"
|
||||
area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | XENOBIOLOGY_COMPATIBLE | CULT_PERMITTED
|
||||
|
||||
//Maintenance - Prison
|
||||
|
||||
/area/maintenance/prison
|
||||
name = "Prison Maintenance"
|
||||
icon_state = "prison_maintenance"
|
||||
|
||||
/area/maintenance/prison/fore
|
||||
name = "Prison Fore Maintenance"
|
||||
icon_state = "prison_maintenance"
|
||||
|
||||
/area/maintenance/prison/starboard
|
||||
name = "Prison Starboard Maintenance"
|
||||
icon_state = "prison_maintenance"
|
||||
|
||||
/area/maintenance/prison/aft
|
||||
name = "Prison Aft Maintenance"
|
||||
icon_state = "prison_maintenance"
|
||||
|
||||
/area/maintenance/prison/port
|
||||
name = "Prison Port Maintenance"
|
||||
icon_state = "prison_maintenance"
|
||||
|
||||
//Maintenance - Generic
|
||||
|
||||
/area/maintenance/arrivals/north
|
||||
@@ -1393,13 +1415,9 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
name = "Prison Wing"
|
||||
icon_state = "sec_prison"
|
||||
|
||||
/area/security/prison/toilet //radproof
|
||||
name = "Prison Toilet"
|
||||
icon_state = "sec_prison_safe"
|
||||
|
||||
/area/security/prison/safe //radproof
|
||||
/area/security/prison/cells
|
||||
name = "Prison Wing Cells"
|
||||
icon_state = "sec_prison_safe"
|
||||
icon_state = "prison_cells"
|
||||
|
||||
/area/security/prison/upper
|
||||
name = "Upper Prison Wing"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
antag_flag = ROLE_BLOODSUCKER
|
||||
false_report_weight = 1
|
||||
chaos = 4
|
||||
restricted_jobs = list("AI","Cyborg")
|
||||
restricted_jobs = list("Prisoner", "AI","Cyborg")
|
||||
protected_jobs = list("Chaplain", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_players = 20
|
||||
required_enemies = 2
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
config_tag = "traitorbro"
|
||||
required_players = 25
|
||||
chaos = 5
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
restricted_jobs = list("Prisoner", "AI", "Cyborg")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
|
||||
announce_span = "danger"
|
||||
|
||||
@@ -11,7 +11,7 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
|
||||
antag_flag = ROLE_CHANGELING
|
||||
false_report_weight = 10
|
||||
chaos = 5
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
restricted_jobs = list("Prisoner", "AI", "Cyborg")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to ling role blacklist
|
||||
required_players = 15
|
||||
required_enemies = 1
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
false_report_weight = 10
|
||||
chaos = 6
|
||||
traitors_possible = 3 //hard limit on traitors if scaling is turned off
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
restricted_jobs = list("Prisoner", "AI", "Cyborg")
|
||||
required_players = 25
|
||||
required_enemies = 1 // how many of each type are required
|
||||
recommended_enemies = 3
|
||||
|
||||
@@ -139,7 +139,7 @@ Credit where due:
|
||||
required_enemies = 3
|
||||
recommended_enemies = 5
|
||||
enemy_minimum_age = 7
|
||||
protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //Silicons can eventually be converted
|
||||
protected_jobs = list("Prisoner", "AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //Silicons can eventually be converted
|
||||
restricted_jobs = list("Chaplain", "Captain")
|
||||
announce_span = "brass"
|
||||
announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\
|
||||
@@ -151,14 +151,14 @@ Credit where due:
|
||||
var/datum/team/clockcult/main_clockcult
|
||||
|
||||
/datum/game_mode/clockwork_cult/pre_setup() //Gamemode and job code is pain. Have fun codediving all of that stuff, whoever works on this next - Delta
|
||||
/*var/list/errorList = list()
|
||||
var/list/errorList = list()
|
||||
var/list/reebes = SSmapping.LoadGroup(errorList, "Reebe", "map_files/generic", "City_of_Cogs.dmm", default_traits = ZTRAITS_REEBE, silent = TRUE)
|
||||
if(errorList.len) // reebe failed to load
|
||||
message_admins("Reebe failed to load!")
|
||||
log_game("Reebe failed to load!")
|
||||
return FALSE
|
||||
for(var/datum/parsed_map/PM in reebes) //Temporarily commented because of z-level loading reliably segfaulting the server.
|
||||
PM.initTemplateBounds()*/
|
||||
PM.initTemplateBounds()
|
||||
if(CONFIG_GET(flag/protect_roles_from_antagonist))
|
||||
restricted_jobs += protected_jobs
|
||||
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
|
||||
@@ -275,7 +275,7 @@ Credit where due:
|
||||
ears = /obj/item/radio/headset
|
||||
gloves = /obj/item/clothing/gloves/color/yellow
|
||||
belt = /obj/item/storage/belt/utility/servant
|
||||
backpack_contents = list(/obj/item/storage/box/engineer = 1, \
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/reagent_containers/food/drinks/bottle/holyoil = 1)
|
||||
id = /obj/item/pda
|
||||
var/plasmaman //We use this to determine if we should activate internals in post_equip()
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
l_pocket = /obj/item/pinpointer/nuke/syndicate
|
||||
r_pocket = /obj/item/bikehorn
|
||||
id = /obj/item/card/id/syndicate
|
||||
backpack_contents = list(/obj/item/storage/box/syndie=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/syndie=1,\
|
||||
/obj/item/kitchen/knife/combat/survival,
|
||||
/obj/item/reagent_containers/spray/waterflower/lube)
|
||||
implants = list(/obj/item/implant/sad_trombone)
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
antag_flag = ROLE_CULTIST
|
||||
false_report_weight = 10
|
||||
chaos = 8
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
restricted_jobs = list("Prisoner", "AI", "Cyborg")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_players = 30
|
||||
required_enemies = 3
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
antag_flag = ROLE_DEVIL
|
||||
false_report_weight = 1
|
||||
chaos = 3
|
||||
protected_jobs = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI")
|
||||
protected_jobs = list("Prisoner", "Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI")
|
||||
required_players = 0
|
||||
required_enemies = 1
|
||||
recommended_enemies = 4
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
antag_flag = ROLE_HERETIC
|
||||
false_report_weight = 5
|
||||
chaos = 5
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
restricted_jobs = list("Prisoner", "AI", "Cyborg")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to heretic role blacklist
|
||||
required_players = 15
|
||||
required_enemies = 1
|
||||
|
||||
@@ -7,7 +7,7 @@ GLOBAL_LIST_EMPTY(gangs)
|
||||
config_tag = "gang"
|
||||
antag_flag = ROLE_GANG
|
||||
chaos = 9
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
restricted_jobs = list("Prisoner", "AI", "Cyborg")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_players = 15
|
||||
required_enemies = 0
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
l_pocket = /obj/item/pinpointer/nuke/syndicate
|
||||
id = /obj/item/card/id/syndicate
|
||||
belt = /obj/item/gun/ballistic/automatic/pistol
|
||||
backpack_contents = list(/obj/item/storage/box/syndie=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/syndie=1,\
|
||||
/obj/item/kitchen/knife/combat/survival)
|
||||
|
||||
var/tc = 25
|
||||
@@ -173,7 +173,7 @@
|
||||
internals_slot = SLOT_R_STORE
|
||||
belt = /obj/item/storage/belt/military
|
||||
r_hand = /obj/item/gun/ballistic/automatic/shotgun/bulldog
|
||||
backpack_contents = list(/obj/item/storage/box/syndie=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/syndie=1,\
|
||||
/obj/item/tank/jetpack/oxygen/harness=1,\
|
||||
/obj/item/gun/ballistic/automatic/pistol=1,\
|
||||
/obj/item/kitchen/knife/combat/survival)
|
||||
@@ -188,7 +188,7 @@
|
||||
r_pocket = /obj/item/tank/internals/emergency_oxygen/engi
|
||||
internals_slot = SLOT_R_STORE
|
||||
belt = /obj/item/storage/belt/military
|
||||
backpack_contents = list(/obj/item/storage/box/syndie=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/syndie=1,\
|
||||
/obj/item/tank/jetpack/oxygen/harness=1,\
|
||||
/obj/item/gun/ballistic/automatic/pistol=1,\
|
||||
/obj/item/kitchen/knife/combat/survival)
|
||||
|
||||
@@ -160,12 +160,14 @@ If not set, defaults to check_completion instead. Set it. It's used by cryo.
|
||||
|
||||
/datum/objective/proc/give_special_equipment(special_equipment)
|
||||
var/datum/mind/receiver = pick(get_owners())
|
||||
. = list()
|
||||
if(receiver && receiver.current)
|
||||
if(ishuman(receiver.current))
|
||||
var/mob/living/carbon/human/H = receiver.current
|
||||
var/list/slots = list("backpack" = SLOT_IN_BACKPACK)
|
||||
for(var/eq_path in special_equipment)
|
||||
var/obj/O = new eq_path
|
||||
. += O
|
||||
H.equip_in_one_of_slots(O, slots, critical = TRUE)
|
||||
|
||||
/datum/objective/assassinate
|
||||
@@ -560,6 +562,7 @@ GLOBAL_LIST_EMPTY(possible_items)
|
||||
name = "steal"
|
||||
var/datum/objective_item/targetinfo = null //Save the chosen item datum so we can access it later.
|
||||
var/obj/item/steal_target = null //Needed for custom objectives (they're just items, not datums).
|
||||
var/list/special_items_given = list()
|
||||
martyr_compatible = 0
|
||||
|
||||
/datum/objective/steal/get_target()
|
||||
@@ -571,6 +574,11 @@ GLOBAL_LIST_EMPTY(possible_items)
|
||||
for(var/I in subtypesof(/datum/objective_item/steal))
|
||||
new I
|
||||
|
||||
/datum/objective/steal/Destroy(force, ...)
|
||||
if(length(special_items_given))
|
||||
QDEL_LIST(special_items_given)
|
||||
. = ..()
|
||||
|
||||
/datum/objective/steal/find_target(dupe_search_range, blacklist)
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
var/approved_targets = list()
|
||||
@@ -589,7 +597,7 @@ GLOBAL_LIST_EMPTY(possible_items)
|
||||
targetinfo = item
|
||||
steal_target = targetinfo.targetitem
|
||||
explanation_text = "Steal [targetinfo.name]"
|
||||
give_special_equipment(targetinfo.special_equipment)
|
||||
special_items_given = give_special_equipment(targetinfo.special_equipment)
|
||||
return steal_target
|
||||
else
|
||||
explanation_text = "Free objective"
|
||||
@@ -1180,6 +1188,7 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
|
||||
/datum/objective/sabotage
|
||||
name = "sabotage"
|
||||
var/datum/sabotage_objective/targetinfo = null //composition > inheritance.
|
||||
var/list/special_items_given = list()
|
||||
|
||||
/datum/objective/sabotage/get_target()
|
||||
return targetinfo.sabotage_type
|
||||
@@ -1190,6 +1199,11 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
|
||||
for(var/I in subtypesof(/datum/sabotage_objective))
|
||||
new I
|
||||
|
||||
/datum/objective/sabotage/Destroy()
|
||||
if(length(special_items_given))
|
||||
QDEL_LIST(special_items_given)
|
||||
. = ..()
|
||||
|
||||
/datum/objective/sabotage/find_target(dupe_search_range, blacklist)
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
var/approved_targets = list()
|
||||
@@ -1207,7 +1221,7 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
|
||||
if(sabo)
|
||||
targetinfo = sabo
|
||||
explanation_text = "[targetinfo.name]"
|
||||
give_special_equipment(targetinfo.special_equipment)
|
||||
special_items_given = give_special_equipment(targetinfo.special_equipment)
|
||||
return sabo
|
||||
else
|
||||
explanation_text = "Free objective"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
antag_flag = ROLE_REV
|
||||
false_report_weight = 10
|
||||
chaos = 8
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
restricted_jobs = list("Prisoner", "AI", "Cyborg")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_players = 20
|
||||
required_enemies = 1
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
config_tag = "traitor"
|
||||
antag_flag = ROLE_TRAITOR
|
||||
false_report_weight = 20 //Reports of traitors are pretty common.
|
||||
restricted_jobs = list("Cyborg")//They are part of the AI if he is traitor so are they, they use to get double chances
|
||||
restricted_jobs = list("Prisoner", "Cyborg")//They are part of the AI if he is traitor so are they, they use to get double chances
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to ling role blacklist
|
||||
required_players = 0
|
||||
required_enemies = 1
|
||||
|
||||
@@ -191,6 +191,7 @@
|
||||
var/x2 = x1
|
||||
work_squares(y2, x2) //Work squares while in this loop so there's less load
|
||||
reset_board = FALSE
|
||||
CHECK_TICK
|
||||
|
||||
web += "<table>" //Start setting up the html table
|
||||
web += "<tbody>"
|
||||
@@ -235,6 +236,7 @@
|
||||
web += "<td>[MINESWEEPERIMG(7)]</td>"
|
||||
if(19)
|
||||
web += "<td>[MINESWEEPERIMG(8)]</td>"
|
||||
CHECK_TICK
|
||||
web += "</tr>"
|
||||
web += "</table>"
|
||||
web += "</tbody>"
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
var/static/list/airlock_overlays = list()
|
||||
|
||||
/// sigh
|
||||
var/unelectrify_timerid
|
||||
|
||||
/obj/machinery/door/airlock/Initialize()
|
||||
. = ..()
|
||||
@@ -791,21 +794,6 @@
|
||||
return WIRE_INTERACTION_FAIL
|
||||
return ..()
|
||||
|
||||
/obj/machinery/door/airlock/proc/electrified_loop()
|
||||
while (secondsElectrified > NOT_ELECTRIFIED)
|
||||
sleep(10)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
secondsElectrified--
|
||||
updateDialog()
|
||||
// This is to protect against changing to permanent, mid loop.
|
||||
if(secondsElectrified == NOT_ELECTRIFIED)
|
||||
set_electrified(NOT_ELECTRIFIED)
|
||||
else
|
||||
set_electrified(ELECTRIFIED_PERMANENT)
|
||||
updateDialog()
|
||||
|
||||
/obj/machinery/door/airlock/Topic(href, href_list, var/nowindow = 0)
|
||||
// If you add an if(..()) check you must first remove the var/nowindow parameter.
|
||||
// Otherwise it will runtime with this kind of error: null.Topic()
|
||||
@@ -1365,11 +1353,18 @@
|
||||
wires.cut_all()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/door/airlock/proc/remove_electrify()
|
||||
secondsElectrified = NOT_ELECTRIFIED
|
||||
unelectrify_timerid = null
|
||||
|
||||
/obj/machinery/door/airlock/proc/set_electrified(seconds, mob/user)
|
||||
secondsElectrified = seconds
|
||||
if(unelectrify_timerid)
|
||||
deltimer(unelectrify_timerid)
|
||||
unelectrify_timerid = null
|
||||
if(secondsElectrified != ELECTRIFIED_PERMANENT)
|
||||
unelectrify_timerid = addtimer(CALLBACK(src, .proc/remove_electrify), secondsElectrified SECONDS, TIMER_STOPPABLE)
|
||||
diag_hud_set_electrified()
|
||||
if(secondsElectrified > NOT_ELECTRIFIED)
|
||||
INVOKE_ASYNC(src, .proc/electrified_loop)
|
||||
|
||||
if(user)
|
||||
var/message
|
||||
|
||||
@@ -197,10 +197,8 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
|
||||
if(orig_light < 10)
|
||||
say("Explosion not large enough for research calculations.")
|
||||
return
|
||||
else if(orig_light < 4500)
|
||||
point_gain = (83300 * orig_light) / (orig_light + 3000)
|
||||
else
|
||||
point_gain = TECHWEB_BOMB_POINTCAP
|
||||
point_gain = (100000 * orig_light) / (orig_light + 5000)
|
||||
|
||||
/*****The Point Capper*****/
|
||||
if(point_gain > linked_techweb.largest_bomb_value)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/obj/machinery/plate_press
|
||||
name = "license plate press"
|
||||
desc = "You know, we're making a lot of license plates for a station with literaly no cars in it."
|
||||
icon = 'icons/obj/machines/prison.dmi'
|
||||
icon_state = "offline"
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 2
|
||||
active_power_usage = 50
|
||||
var/obj/item/stack/license_plates/empty/current_plate
|
||||
var/pressing = FALSE
|
||||
|
||||
/obj/machinery/plate_press/update_icon()
|
||||
. = ..()
|
||||
if(!is_operational())
|
||||
icon_state = "offline"
|
||||
else if(pressing)
|
||||
icon_state = "loop"
|
||||
else if(current_plate)
|
||||
icon_state = "online_loaded"
|
||||
else
|
||||
icon_state = "online"
|
||||
|
||||
/obj/machinery/plate_press/Destroy()
|
||||
QDEL_NULL(current_plate)
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/plate_press/attackby(obj/item/I, mob/living/user, params)
|
||||
if(!is_operational())
|
||||
to_chat(user, "<span class='warning'>[src] has to be on to do this!</span>")
|
||||
return FALSE
|
||||
if(pressing)
|
||||
to_chat(user, "<span class='warning'>[src] already has a plate in it!</span>")
|
||||
return FALSE
|
||||
if(istype(I, /obj/item/stack/license_plates/empty))
|
||||
var/obj/item/stack/license_plates/empty/plate = I
|
||||
plate.use(1)
|
||||
current_plate = new plate.type(src, 1) //Spawn a new single sheet in the machine
|
||||
update_icon()
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/plate_press/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(!pressing && current_plate)
|
||||
work_press(user)
|
||||
|
||||
///This proc attempts to create a plate. User cannot move during this process.
|
||||
/obj/machinery/plate_press/proc/work_press(mob/living/user)
|
||||
|
||||
pressing = TRUE
|
||||
update_icon()
|
||||
to_chat(user, "<span class='notice'>You start pressing a new license plate!</span>")
|
||||
|
||||
if(!do_after(user, 40, target = src))
|
||||
pressing = FALSE
|
||||
update_icon()
|
||||
return FALSE
|
||||
|
||||
use_power(100)
|
||||
to_chat(user, "<span class='notice'>You finish pressing a new license plate!</span>")
|
||||
|
||||
pressing = FALSE
|
||||
QDEL_NULL(current_plate)
|
||||
update_icon()
|
||||
|
||||
new /obj/item/stack/license_plates/filled(drop_location(), 1)
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/machinery/recharger
|
||||
name = "recharger"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "recharger0"
|
||||
icon_state = "recharger"
|
||||
base_icon_state = "recharger"
|
||||
desc = "A charging dock for energy based weaponry."
|
||||
use_power = IDLE_POWER_USE
|
||||
@@ -12,6 +12,8 @@
|
||||
var/obj/item/charging = null
|
||||
var/recharge_coeff = 1
|
||||
var/using_power = FALSE //Did we put power into "charging" last process()?
|
||||
///Did we finish recharging the currently inserted item?
|
||||
var/finished_recharging = FALSE
|
||||
|
||||
var/static/list/allowed_devices = typecacheof(list(
|
||||
/obj/item/gun/energy,
|
||||
@@ -48,13 +50,14 @@
|
||||
charging = new_charging
|
||||
if (new_charging)
|
||||
START_PROCESSING(SSmachines, src)
|
||||
finished_recharging = FALSE
|
||||
use_power = ACTIVE_POWER_USE
|
||||
using_power = TRUE
|
||||
update_icon()
|
||||
update_appearance()
|
||||
else
|
||||
use_power = IDLE_POWER_USE
|
||||
using_power = FALSE
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/recharger/Exited(atom/movable/M, atom/newloc)
|
||||
. = ..()
|
||||
@@ -100,7 +103,8 @@
|
||||
return 1
|
||||
|
||||
if(anchored && !charging)
|
||||
if(default_deconstruction_screwdriver(user, "rechargeropen", "recharger0", G))
|
||||
if(default_deconstruction_screwdriver(user, "recharger", "recharger", G))
|
||||
update_appearance()
|
||||
return
|
||||
|
||||
if(panel_open && G.tool_behaviour == TOOL_CROWBAR)
|
||||
@@ -133,7 +137,7 @@
|
||||
C.give(C.chargerate * recharge_coeff)
|
||||
use_power(250 * recharge_coeff)
|
||||
using_power = TRUE
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
if(istype(charging, /obj/item/ammo_box/magazine/recharge))
|
||||
var/obj/item/ammo_box/magazine/recharge/R = charging
|
||||
@@ -141,7 +145,7 @@
|
||||
R.stored_ammo += new R.ammo_type(R)
|
||||
use_power(200 * recharge_coeff)
|
||||
using_power = TRUE
|
||||
update_icon()
|
||||
update_appearance()
|
||||
return
|
||||
|
||||
if(istype(charging, /obj/item/ammo_casing/mws_batt))
|
||||
@@ -152,7 +156,7 @@
|
||||
using_power = 1
|
||||
if(R.BB == null)
|
||||
R.chargeshot()
|
||||
update_icon(using_power)
|
||||
update_appearance()
|
||||
|
||||
if(istype(charging, /obj/item/ammo_box/magazine/mws_mag))
|
||||
var/obj/item/ammo_box/magazine/mws_mag/R = charging
|
||||
@@ -164,14 +168,19 @@
|
||||
using_power = 1
|
||||
if(batt.BB == null)
|
||||
batt.chargeshot()
|
||||
update_icon(using_power)
|
||||
update_appearance()
|
||||
|
||||
if(!using_power && !finished_recharging) //Inserted thing is at max charge/ammo, notify those around us
|
||||
finished_recharging = TRUE
|
||||
playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
|
||||
say("[charging] has finished recharging!")
|
||||
|
||||
else
|
||||
return PROCESS_KILL
|
||||
|
||||
/obj/machinery/recharger/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/recharger/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
var/list/to_eat = AM0.GetAllContents()
|
||||
|
||||
var/living_detected = FALSE //technically includes silicons as well but eh
|
||||
var/mob/living/living_detected //technically includes silicons as well but eh
|
||||
var/list/nom = list()
|
||||
var/list/crunchy_nom = list() //Mobs have to be handled differently so they get a different list instead of checking them multiple times.
|
||||
|
||||
@@ -120,10 +120,10 @@
|
||||
var/obj/item/bodypart/head/as_head = AM
|
||||
var/obj/item/mmi/as_mmi = AM
|
||||
if(istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /obj/item/dullahan_relay))
|
||||
living_detected = TRUE
|
||||
living_detected = living_detected || AM
|
||||
nom += AM
|
||||
else if(isliving(AM))
|
||||
living_detected = TRUE
|
||||
living_detected = living_detected || TRUE
|
||||
crunchy_nom += AM
|
||||
var/not_eaten = to_eat.len - nom.len - crunchy_nom.len
|
||||
if(living_detected) // First, check if we have any living beings detected.
|
||||
@@ -132,7 +132,7 @@
|
||||
if(isliving(CRUNCH)) // MMIs and brains will get eaten like normal items
|
||||
crush_living(CRUNCH)
|
||||
else // Stop processing right now without eating anything.
|
||||
emergency_stop()
|
||||
emergency_stop(living_detected)
|
||||
return
|
||||
for(var/nommed in nom)
|
||||
recycle_item(nommed)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
anchored = FALSE
|
||||
density = TRUE
|
||||
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN
|
||||
use_power = NO_POWER_USE
|
||||
icon = 'icons/obj/atmos.dmi'
|
||||
icon_state = "sheater-off"
|
||||
name = "space heater"
|
||||
@@ -72,7 +73,7 @@
|
||||
on = FALSE
|
||||
return PROCESS_KILL
|
||||
|
||||
if(cell && cell.charge > 0)
|
||||
if(cell && cell.charge > 1 / efficiency)
|
||||
var/turf/L = loc
|
||||
PerformHeating(L)
|
||||
|
||||
@@ -112,7 +113,9 @@
|
||||
var/requiredPower = abs(env.return_temperature() - targetTemperature) * heat_capacity
|
||||
requiredPower = min(requiredPower, heatingPower)
|
||||
|
||||
if(requiredPower < 1)
|
||||
if(requiredPower < 1 || !cell.use(requiredPower / efficiency))
|
||||
on = FALSE
|
||||
update_icon()
|
||||
return
|
||||
|
||||
var/deltaTemperature = requiredPower / heat_capacity
|
||||
@@ -121,7 +124,6 @@
|
||||
if(deltaTemperature)
|
||||
env.set_temperature(env.return_temperature() + deltaTemperature)
|
||||
air_update_turf()
|
||||
cell.use(requiredPower / efficiency)
|
||||
|
||||
/obj/machinery/space_heater/RefreshParts()
|
||||
var/laser = 2
|
||||
|
||||
@@ -64,6 +64,10 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
|
||||
name = "Assistant"
|
||||
icon_state = "Assistant"
|
||||
|
||||
/obj/effect/landmark/start/prisoner
|
||||
name = "Prisoner"
|
||||
icon_state = "Prisoner"
|
||||
|
||||
/obj/effect/landmark/start/assistant/override
|
||||
jobspawn_override = TRUE
|
||||
delete_after_roundstart = FALSE
|
||||
|
||||
@@ -60,6 +60,48 @@
|
||||
/obj/item/gun/ballistic/automatic/pistol/deagle,
|
||||
/obj/item/storage/box/syndie_kit/throwing_weapons = 3)
|
||||
|
||||
/obj/effect/spawner/lootdrop/prison_contraband
|
||||
name = "prison contraband loot spawner"
|
||||
loot = list(/obj/item/clothing/mask/cigarette/space_cigarette = 4,
|
||||
/obj/item/clothing/mask/cigarette/robust = 2,
|
||||
/obj/item/clothing/mask/cigarette/carp = 3,
|
||||
/obj/item/clothing/mask/cigarette/uplift = 2,
|
||||
/obj/item/clothing/mask/cigarette/dromedary = 3,
|
||||
/obj/item/clothing/mask/cigarette/robustgold = 1,
|
||||
/obj/item/storage/fancy/cigarettes/cigpack_uplift = 3,
|
||||
/obj/item/storage/fancy/cigarettes = 3,
|
||||
/obj/item/clothing/mask/cigarette/rollie/cannabis = 4,
|
||||
/obj/item/toy/crayon/spraycan = 2,
|
||||
/obj/item/crowbar = 1,
|
||||
/obj/item/assembly/flash/handheld = 1,
|
||||
/obj/item/restraints/handcuffs/cable/zipties = 1,
|
||||
/obj/item/restraints/handcuffs = 1,
|
||||
/obj/item/radio/off = 1,
|
||||
/obj/item/lighter = 3,
|
||||
/obj/item/storage/box/matches = 3,
|
||||
/obj/item/reagent_containers/syringe/contraband/space_drugs = 1,
|
||||
/obj/item/reagent_containers/syringe/contraband/krokodil = 1,
|
||||
/obj/item/reagent_containers/syringe/contraband/crank = 1,
|
||||
/obj/item/reagent_containers/syringe/contraband/methamphetamine = 1,
|
||||
/obj/item/reagent_containers/syringe/contraband/bath_salts = 1,
|
||||
/obj/item/reagent_containers/syringe/contraband/fentanyl = 1,
|
||||
/obj/item/reagent_containers/syringe/contraband/morphine = 1,
|
||||
/obj/item/storage/pill_bottle/happy = 1,
|
||||
/obj/item/storage/pill_bottle/lsd = 1,
|
||||
/obj/item/storage/pill_bottle/psicodine = 1,
|
||||
/obj/item/reagent_containers/food/drinks/beer = 4,
|
||||
/obj/item/reagent_containers/food/drinks/bottle/whiskey = 1,
|
||||
/obj/item/paper/fluff/jobs/prisoner/letter = 1,
|
||||
/obj/item/grenade/smokebomb = 1,
|
||||
/obj/item/flashlight/seclite = 1,
|
||||
/obj/item/tailclub = 1, //want to buy makeshift wooden club sprite
|
||||
/obj/item/kitchen/knife/shiv = 4,
|
||||
/obj/item/kitchen/knife/shiv/carrot = 1,
|
||||
/obj/item/kitchen/knife = 1,
|
||||
/obj/item/storage/wallet/random = 1,
|
||||
/obj/item/pda = 1
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/gambling
|
||||
name = "gambling valuables spawner"
|
||||
loot = list(
|
||||
|
||||
@@ -146,6 +146,9 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
|
||||
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
|
||||
|
||||
//the outline filter on hover
|
||||
var/outline_filter
|
||||
|
||||
/* Our block parry data. Should be set in init, or something if you are using it.
|
||||
* This won't be accessed without ITEM_CAN_BLOCK or ITEM_CAN_PARRY so do not set it unless you have to to save memory.
|
||||
* If you decide it's a good idea to leave this unset while turning the flags on, you will runtime. Enjoy.
|
||||
@@ -175,6 +178,12 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
if(force_string)
|
||||
item_flags |= FORCE_STRING_OVERRIDE
|
||||
|
||||
if(istype(loc, /obj/item/storage))
|
||||
item_flags |= IN_STORAGE
|
||||
|
||||
if(istype(loc, /obj/item/robot_module))
|
||||
item_flags |= IN_INVENTORY
|
||||
|
||||
if(!hitsound)
|
||||
if(damtype == "fire")
|
||||
hitsound = 'sound/items/welder.ogg'
|
||||
@@ -373,6 +382,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(src))
|
||||
return
|
||||
|
||||
remove_outline()
|
||||
pickup(user)
|
||||
add_fingerprint(user)
|
||||
if(!user.put_in_active_hand(src, FALSE, FALSE))
|
||||
@@ -443,6 +453,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
qdel(src)
|
||||
item_flags &= ~IN_INVENTORY
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_DROPPED,user)
|
||||
remove_outline()
|
||||
// if(!silent)
|
||||
// playsound(src, drop_sound, DROP_SOUND_VOLUME, ignore_walls = FALSE)
|
||||
user?.update_equipment_speed_mods()
|
||||
@@ -557,6 +568,12 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
if(usr.incapacitated() || !Adjacent(usr) || usr.lying)
|
||||
return
|
||||
|
||||
if(iscyborg(usr))
|
||||
var/obj/item/gripper/gripper = usr.get_active_held_item(TRUE)
|
||||
if(istype(gripper))
|
||||
gripper.pre_attack(src, usr, get_dist(src, usr))
|
||||
return
|
||||
|
||||
if(usr.get_active_held_item() == null) // Let me know if this has any problems -Yota
|
||||
usr.UnarmedAttack(src)
|
||||
|
||||
@@ -867,18 +884,49 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
openToolTip(user,src,params,title = name,content = "[desc]<br><b>Force:</b> [force_string]",theme = "")
|
||||
|
||||
/obj/item/MouseEntered(location, control, params)
|
||||
if((item_flags & IN_INVENTORY) && usr.client.prefs.enable_tips && !QDELETED(src))
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_ENTER, location, control, params)
|
||||
if((item_flags & IN_INVENTORY || item_flags & IN_STORAGE) && usr.client.prefs.enable_tips && !QDELETED(src))
|
||||
var/timedelay = usr.client.prefs.tip_delay/100
|
||||
var/user = usr
|
||||
tip_timer = addtimer(CALLBACK(src, .proc/openTip, location, control, params, user), timedelay, TIMER_STOPPABLE)//timer takes delay in deciseconds, but the pref is in milliseconds. dividing by 100 converts it.
|
||||
var/mob/living/L = usr
|
||||
if(istype(L) && (L.incapacitated() || (current_equipped_slot in L.check_obscured_slots()) || !L.canUnEquip(src)))
|
||||
apply_outline(_size = 3)
|
||||
else
|
||||
apply_outline()
|
||||
|
||||
/obj/item/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params)
|
||||
. = ..()
|
||||
remove_outline()
|
||||
|
||||
/obj/item/MouseExited(location,control,params)
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_EXIT, location, control, params)
|
||||
deltimer(tip_timer)//delete any in-progress timer if the mouse is moved off the item before it finishes
|
||||
closeToolTip(usr)
|
||||
remove_outline()
|
||||
|
||||
/obj/item/MouseEntered(location,control,params)
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_ENTER, location, control, params)
|
||||
/obj/item/proc/apply_outline(colour = null, _size=1)
|
||||
if(!(item_flags & IN_INVENTORY || item_flags & IN_STORAGE) || QDELETED(src) || isobserver(usr))
|
||||
return
|
||||
if(usr.client)
|
||||
if(!usr.client.prefs.outline_enabled)
|
||||
return
|
||||
if(!colour)
|
||||
if(usr.client)
|
||||
colour = usr.client.prefs.outline_color
|
||||
if(!colour)
|
||||
colour = COLOR_BLUE_GRAY
|
||||
else
|
||||
colour = COLOR_BLUE_GRAY
|
||||
if(outline_filter)
|
||||
filters -= outline_filter
|
||||
outline_filter = filter(type="outline", size=_size, color=colour)
|
||||
filters += outline_filter
|
||||
|
||||
/obj/item/proc/remove_outline()
|
||||
if(outline_filter)
|
||||
filters -= outline_filter
|
||||
outline_filter = null
|
||||
|
||||
// Called when a mob tries to use the item as a tool.
|
||||
// Handles most checks.
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
/obj/item/dogborg/sleeper/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "dogborg_sleeper", name, 375, 550) //UI DOES NOT EXIST
|
||||
ui = new(user, src, "Sleeper", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/dogborg/sleeper/ui_data()
|
||||
|
||||
@@ -105,6 +105,12 @@ GLOBAL_LIST_INIT(channel_tokens, list(
|
||||
keyslot = new /obj/item/encryptionkey/binary
|
||||
recalculateChannels()
|
||||
|
||||
/obj/item/radio/headset/headset_prisoner
|
||||
name = "prison radio headset"
|
||||
desc = "An updated, modular intercom that fits over the head. Takes encryption keys. It looks like it has been modified to not broadcast."
|
||||
icon_state = "prisoner_headset"
|
||||
prison_radio = TRUE
|
||||
|
||||
/obj/item/radio/headset/headset_sec
|
||||
name = "security radio headset"
|
||||
desc = "This is used by your elite security force."
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/obj/item/dyespray
|
||||
name = "hair dye spray"
|
||||
desc = "A spray to dye your hair any gradients you'd like."
|
||||
icon = 'icons/obj/dyespray.dmi'
|
||||
icon_state = "dyespray"
|
||||
|
||||
/obj/item/dyespray/attack_self(mob/user)
|
||||
dye(user)
|
||||
|
||||
/obj/item/dyespray/pre_attack(atom/target, mob/living/user, params)
|
||||
dye(target)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Applies a gradient and a gradient color to a mob.
|
||||
*
|
||||
* Arguments:
|
||||
* * target - The mob who we will apply the gradient and gradient color to.
|
||||
*/
|
||||
|
||||
/obj/item/dyespray/proc/dye(mob/target)
|
||||
if(!ishuman(target))
|
||||
return
|
||||
var/mob/living/carbon/human/human_target = target
|
||||
|
||||
var/new_grad_style = input(usr, "Choose a color pattern:", "Character Preference") as null|anything in GLOB.hair_gradients_list
|
||||
if(!new_grad_style)
|
||||
return
|
||||
|
||||
var/new_grad_color = input(usr, "Choose a secondary hair color:", "Character Preference","#"+human_target.grad_color) as color|null
|
||||
if(!new_grad_color)
|
||||
return
|
||||
|
||||
human_target.grad_style = new_grad_style
|
||||
human_target.grad_color = sanitize_hexcolor(new_grad_color)
|
||||
to_chat(human_target, "<span class='notice'>You start applying the hair dye...</span>")
|
||||
if(!do_after(usr, 30, target = human_target))
|
||||
return
|
||||
playsound(src, 'sound/effects/spray.ogg', 5, TRUE, 5)
|
||||
human_target.update_hair()
|
||||
@@ -255,18 +255,31 @@
|
||||
icon_state = "knife"
|
||||
desc = "A cyborg-mounted plasteel knife. Extremely sharp and durable."
|
||||
|
||||
/obj/item/kitchen/knife/carrotshiv
|
||||
/obj/item/kitchen/knife/shiv
|
||||
name = "glass shiv"
|
||||
icon = 'icons/obj/shards.dmi'
|
||||
icon_state = "shiv"
|
||||
item_state = "shiv"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
desc = "A makeshift glass shiv."
|
||||
force = 8
|
||||
throwforce = 12//fuck git
|
||||
attack_verb = list("shanked", "shivved")
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
custom_materials = list(/datum/material/glass=400)
|
||||
|
||||
/obj/item/kitchen/knife/shiv/carrot
|
||||
name = "carrot shiv"
|
||||
icon_state = "carrotshiv"
|
||||
item_state = "carrotshiv"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
icon = 'icons/obj/kitchen.dmi'
|
||||
desc = "Unlike other carrots, you should probably keep this far away from your eyes."
|
||||
force = 8
|
||||
throwforce = 12//fuck git
|
||||
custom_materials = null
|
||||
attack_verb = list("shanked", "shivved")
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
|
||||
/obj/item/kitchen/knife/shiv/carrot/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] forcefully drives \the [src] into [user.p_their()] eye! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/kitchen/rollingpin
|
||||
name = "rolling pin"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user