Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into prisoners
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
|
||||
|
||||
@@ -54557,8 +54557,8 @@
|
||||
id = "xenoigniter";
|
||||
luminosity = 2
|
||||
},
|
||||
/obj/machinery/atmospherics/components/unary/vent_pump/on{
|
||||
dir = 8
|
||||
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/engine,
|
||||
/area/science/xenobiology)
|
||||
@@ -55493,7 +55493,7 @@
|
||||
/obj/structure/cable{
|
||||
icon_state = "1-2"
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
|
||||
/obj/machinery/atmospherics/pipe/manifold4w/supply/hidden,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/science/xenobiology)
|
||||
"hVx" = (
|
||||
@@ -55915,6 +55915,7 @@
|
||||
id = "xenoigniter";
|
||||
luminosity = 2
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
|
||||
/turf/open/floor/engine,
|
||||
/area/science/xenobiology)
|
||||
"iPz" = (
|
||||
@@ -59469,6 +59470,7 @@
|
||||
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
|
||||
dir = 8
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
|
||||
/turf/open/floor/engine,
|
||||
/area/science/xenobiology)
|
||||
"qAx" = (
|
||||
@@ -60673,6 +60675,7 @@
|
||||
/area/maintenance/department/science)
|
||||
"tfP" = (
|
||||
/obj/item/beacon,
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
|
||||
/turf/open/floor/engine,
|
||||
/area/science/xenobiology)
|
||||
"tfZ" = (
|
||||
@@ -114727,13 +114730,13 @@ abI
|
||||
aby
|
||||
aaa
|
||||
xKc
|
||||
blX
|
||||
lCN
|
||||
qAk
|
||||
iPj
|
||||
tfP
|
||||
geN
|
||||
qAk
|
||||
blX
|
||||
uzB
|
||||
xKc
|
||||
aaa
|
||||
aby
|
||||
|
||||
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)
|
||||
))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,7 @@
|
||||
#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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
inv_item.apply_outline(COLOR_RED_GRAY)
|
||||
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,12 @@
|
||||
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
|
||||
|
||||
@@ -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:{"
|
||||
@@ -218,6 +230,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 +288,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 +389,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 +431,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 +505,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
|
||||
|
||||
@@ -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>")
|
||||
|
||||
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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())
|
||||
apply_outline(COLOR_RED_GRAY)
|
||||
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)
|
||||
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=1, 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.
|
||||
|
||||
@@ -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()
|
||||
@@ -184,7 +184,7 @@
|
||||
hitcost = 75 //Costs more than a standard cyborg esword
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
sharpness = SHARP_EDGED
|
||||
light_color = "#40ceff"
|
||||
light_color = LIGHT_COLOR_RED
|
||||
tool_behaviour = TOOL_SAW
|
||||
toolspeed = 0.7
|
||||
|
||||
|
||||
@@ -745,9 +745,9 @@
|
||||
Grippers oh god oh fuck
|
||||
***********************************************************************/
|
||||
|
||||
/obj/item/weapon/gripper
|
||||
/obj/item/gripper
|
||||
name = "engineering gripper"
|
||||
desc = "A simple grasping tool for interacting with various engineering related items, such as circuits, gas tanks, conveyer belts and more. Alt click to drop instead of use."
|
||||
desc = "A simple grasping tool for interacting with various engineering related items, such as circuits, gas tanks, conveyer belts and more."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "gripper"
|
||||
|
||||
@@ -776,18 +776,29 @@
|
||||
|
||||
var/obj/item/wrapped = null // Item currently being held.
|
||||
|
||||
//Used to interact with UI's of held items, such as gas tanks and airlock electronics.
|
||||
/obj/item/weapon/gripper/AltClick(mob/user)
|
||||
// Used to drop whatever's in the gripper.
|
||||
/obj/item/gripper/proc/drop_held(silent = FALSE)
|
||||
if(wrapped)
|
||||
wrapped.forceMove(get_turf(wrapped))
|
||||
to_chat(user, "<span class='notice'>You drop the [wrapped].</span>")
|
||||
if(!silent)
|
||||
to_chat(usr, "<span class='notice'>You drop the [wrapped].</span>")
|
||||
modify_appearance(wrapped, FALSE)
|
||||
wrapped = null
|
||||
return ..()
|
||||
update_appearance()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/gripper/pre_attack(var/atom/target, var/mob/living/silicon/robot/user, proximity, params)
|
||||
/obj/item/gripper/proc/takeitem(obj/item/item, silent = FALSE)
|
||||
if(!silent)
|
||||
to_chat(usr, "<span class='notice'>You collect \the [item].</span>")
|
||||
item.loc = src
|
||||
wrapped = item
|
||||
update_appearance()
|
||||
|
||||
if(!proximity)
|
||||
return
|
||||
/obj/item/gripper/pre_attack(atom/target, mob/living/silicon/robot/user, params)
|
||||
var/proximity = get_dist(user, target)
|
||||
if(proximity > 1)
|
||||
return STOP_ATTACK_PROC_CHAIN
|
||||
|
||||
if(!wrapped)
|
||||
for(var/obj/item/thing in src.contents)
|
||||
@@ -795,21 +806,24 @@
|
||||
break
|
||||
|
||||
if(wrapped) //Already have an item.
|
||||
var/obj/item/item = wrapped
|
||||
drop_held(TRUE)
|
||||
//Temporary put wrapped into user so target's attackby() checks pass.
|
||||
wrapped.loc = user
|
||||
item.loc = user
|
||||
|
||||
//Pass the attack on to the target. This might delete/relocate wrapped.
|
||||
var/resolved = target.attackby(wrapped,user)
|
||||
if(!resolved && wrapped && target)
|
||||
wrapped.afterattack(target,user,1)
|
||||
var/resolved = target.attackby(item, user, params)
|
||||
if(!resolved && item && target)
|
||||
item.afterattack(target, user, proximity, params)
|
||||
//If wrapped was neither deleted nor put into target, put it back into the gripper.
|
||||
if(wrapped && user && (wrapped.loc == user))
|
||||
wrapped.loc = src
|
||||
else
|
||||
wrapped = null
|
||||
if(item && user && (item.loc == user))
|
||||
takeitem(item, TRUE)
|
||||
return
|
||||
else
|
||||
item = null
|
||||
return STOP_ATTACK_PROC_CHAIN
|
||||
|
||||
else if(istype(target,/obj/item))
|
||||
else if(isitem(target))
|
||||
var/obj/item/I = target
|
||||
var/grab = 0
|
||||
|
||||
@@ -824,24 +838,94 @@
|
||||
|
||||
//We can grab the item, finally.
|
||||
if(grab)
|
||||
to_chat(user, "<span class='notice'>You collect \the [I].</span>")
|
||||
I.loc = src
|
||||
wrapped = I
|
||||
takeitem(I)
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='danger'>Your gripper cannot hold \the [target].</span>")
|
||||
|
||||
/obj/item/weapon/gripper/mining
|
||||
// Rare cases - meant to be handled by code\modules\mob\living\silicon\robot\robot.dm:584 and the weirdness of get_active_held_item() of borgs.
|
||||
/obj/item/gripper/attack_self(mob/user)
|
||||
if(wrapped)
|
||||
wrapped.attack_self(user)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
// Splitable items
|
||||
/obj/item/gripper/AltClick(mob/user)
|
||||
if(wrapped)
|
||||
wrapped.AltClick(user)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
// Even rarer cases
|
||||
/obj/item/gripper/CtrlClick(mob/user)
|
||||
if(wrapped)
|
||||
wrapped.CtrlClick(user)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
// At this point you're just kidding me, but have this one as well.
|
||||
/obj/item/gripper/CtrlShiftClick(mob/user)
|
||||
if(wrapped)
|
||||
wrapped.CtrlShiftClick(user)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
// Make it clear what we can do with it.
|
||||
/obj/item/gripper/examine(mob/user)
|
||||
. = ..()
|
||||
if(wrapped)
|
||||
. += "<span class='notice'>It is holding [icon2html(wrapped, user)] [wrapped].</span>"
|
||||
. += "<span class='notice'>Examine the little preview to examine it.</span>"
|
||||
. += "<span class='notice'>Attempting to drop the gripper will only drop [wrapped].</span>"
|
||||
|
||||
// Resets vis_contents and if holding something, add it to vis_contents.
|
||||
/obj/item/gripper/update_appearance(updates)
|
||||
. = ..()
|
||||
vis_contents = list()
|
||||
if(wrapped)
|
||||
modify_appearance(wrapped, TRUE)
|
||||
vis_contents += wrapped
|
||||
|
||||
// Generates the "minified" version of the item being held and adjust it's position.
|
||||
/obj/item/gripper/proc/modify_appearance(obj/item, minify = FALSE)
|
||||
if(minify)
|
||||
var/matrix/new_transform = new
|
||||
new_transform.Scale(0.5, 0.5)
|
||||
item.transform = new_transform
|
||||
item.pixel_x = 8
|
||||
item.pixel_y = -8
|
||||
else
|
||||
item.pixel_x = initial(pixel_x)
|
||||
item.pixel_y = initial(pixel_y)
|
||||
item.transform = new
|
||||
|
||||
// I kind of wanted the item to be held in the gripper when stored as well, but i realized "store" is just drop as well, so i'll do this for now.
|
||||
// This will handle cases where the borg runs out of power or is damaged enough so the module is forcefully stored.
|
||||
/obj/item/gripper/cyborg_unequip(mob/user)
|
||||
. = ..()
|
||||
if(wrapped)
|
||||
drop_held()
|
||||
|
||||
// Clear references on being destroyed
|
||||
/obj/item/Destroy()
|
||||
for(var/obj/item/gripper/gripper in vis_locs)
|
||||
if(gripper.wrapped == src)
|
||||
gripper.wrapped = null
|
||||
gripper.update_appearance()
|
||||
. = ..()
|
||||
|
||||
/obj/item/gripper/mining
|
||||
name = "shelter capsule deployer"
|
||||
desc = "A simple grasping tool for carrying and deploying shelter capsules. Alt click to drop instead of use."
|
||||
desc = "A simple grasping tool for carrying and deploying shelter capsules."
|
||||
icon_state = "gripper_mining"
|
||||
can_hold = list(
|
||||
/obj/item/survivalcapsule
|
||||
)
|
||||
|
||||
/obj/item/weapon/gripper/medical
|
||||
/obj/item/gripper/medical
|
||||
name = "medical gripper"
|
||||
desc = "A simple grasping tool for interacting with medical equipment, such as beakers, blood bags, chem bags and more. Alt click to drop instead of use."
|
||||
desc = "A simple grasping tool for interacting with medical equipment, such as beakers, blood bags, chem bags and more."
|
||||
icon_state = "gripper_medical"
|
||||
can_hold = list(
|
||||
/obj/item/storage/bag/bio,
|
||||
|
||||
@@ -3,6 +3,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
|
||||
new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 25, one_per_turf = 0), \
|
||||
new/datum/stack_recipe("railing", /obj/structure/railing, 3, time = 18, window_checks = TRUE), \
|
||||
new/datum/stack_recipe("catwalk tile", /obj/item/stack/tile/catwalk, 1, 4, 20), \
|
||||
))
|
||||
|
||||
/obj/item/stack/rods
|
||||
|
||||
@@ -502,6 +502,8 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \
|
||||
new /datum/stack_recipe("sterile masks box", /obj/item/storage/box/masks), \
|
||||
new /datum/stack_recipe("body bag box", /obj/item/storage/box/bodybags), \
|
||||
new /datum/stack_recipe("prescription glasses box", /obj/item/storage/box/rxglasses), \
|
||||
new /datum/stack_recipe("oxygen tank box", /obj/item/storage/box/emergencytank), \
|
||||
new /datum/stack_recipe("extended oxygen tank box", /obj/item/storage/box/engitank), \
|
||||
null, \
|
||||
new /datum/stack_recipe("disk box", /obj/item/storage/box/disks), \
|
||||
new /datum/stack_recipe("light tubes box", /obj/item/storage/box/lights/tubes), \
|
||||
|
||||
@@ -555,3 +555,10 @@
|
||||
color = "#92661A"
|
||||
turf_type = /turf/open/floor/bronze
|
||||
custom_materials = list(/datum/material/bronze = 250)
|
||||
|
||||
/obj/item/stack/tile/catwalk
|
||||
name = "catwalk tile"
|
||||
singular_name = "catwalk floor tile"
|
||||
desc = "Flooring that shows its contents underneath. Engineers love it!"
|
||||
icon_state = "catwalk_tile"
|
||||
turf_type = /turf/open/floor/plating/catwalk_floor
|
||||
|
||||
@@ -102,12 +102,22 @@
|
||||
new /obj/item/disk/nanite_program(src)
|
||||
|
||||
// Ordinary survival box
|
||||
/obj/item/storage/box/survival
|
||||
name = "survival box"
|
||||
desc = "A box with the bare essentials of ensuring the survival of you and others."
|
||||
icon_state = "internals"
|
||||
illustration = "emergencytank"
|
||||
var/mask_type = /obj/item/clothing/mask/breath
|
||||
var/internal_type = /obj/item/tank/internals/emergency_oxygen
|
||||
var/medipen_type = /obj/item/reagent_containers/hypospray/medipen
|
||||
|
||||
/obj/item/storage/box/survival/PopulateContents()
|
||||
new /obj/item/clothing/mask/breath(src)
|
||||
new /obj/item/reagent_containers/hypospray/medipen(src)
|
||||
new mask_type(src)
|
||||
if(!isnull(medipen_type))
|
||||
new medipen_type(src)
|
||||
|
||||
if(!isplasmaman(loc))
|
||||
new /obj/item/tank/internals/emergency_oxygen(src)
|
||||
new internal_type(src)
|
||||
else
|
||||
new /obj/item/tank/internals/plasmaman/belt(src)
|
||||
|
||||
@@ -115,10 +125,13 @@
|
||||
..() // we want the survival stuff too.
|
||||
new /obj/item/radio/off(src)
|
||||
|
||||
/obj/item/storage/box/survival_mining/PopulateContents()
|
||||
new /obj/item/clothing/mask/gas/explorer(src)
|
||||
// Mining survival box
|
||||
/obj/item/storage/box/survival/mining
|
||||
mask_type = /obj/item/clothing/mask/gas/explorer
|
||||
|
||||
/obj/item/storage/box/survival/mining/PopulateContents()
|
||||
..()
|
||||
new /obj/item/crowbar/red(src)
|
||||
new /obj/item/reagent_containers/hypospray/medipen(src)
|
||||
|
||||
if(!isplasmaman(loc))
|
||||
new /obj/item/tank/internals/emergency_oxygen(src)
|
||||
@@ -126,39 +139,30 @@
|
||||
new /obj/item/tank/internals/plasmaman/belt(src)
|
||||
|
||||
// Engineer survival box
|
||||
/obj/item/storage/box/engineer/PopulateContents()
|
||||
new /obj/item/clothing/mask/breath(src)
|
||||
new /obj/item/reagent_containers/hypospray/medipen(src)
|
||||
/obj/item/storage/box/survival/engineer
|
||||
name = "extended-capacity survival box"
|
||||
desc = "A box with the bare essentials of ensuring the survival of you and others. This one is labelled to contain an extended-capacity tank."
|
||||
illustration = "extendedtank"
|
||||
internal_type = /obj/item/tank/internals/emergency_oxygen/engi
|
||||
|
||||
if(!isplasmaman(loc))
|
||||
new /obj/item/tank/internals/emergency_oxygen/engi(src)
|
||||
else
|
||||
new /obj/item/tank/internals/plasmaman/belt(src)
|
||||
|
||||
/obj/item/storage/box/engineer/radio/PopulateContents()
|
||||
/obj/item/storage/box/survival/engineer/radio/PopulateContents()
|
||||
..() // we want the regular items too.
|
||||
new /obj/item/radio/off(src)
|
||||
|
||||
// Syndie survival box
|
||||
/obj/item/storage/box/syndie/PopulateContents()
|
||||
new /obj/item/clothing/mask/gas/syndicate(src)
|
||||
|
||||
if(!isplasmaman(loc))
|
||||
new /obj/item/tank/internals/emergency_oxygen/engi(src)
|
||||
else
|
||||
new /obj/item/tank/internals/plasmaman/belt(src)
|
||||
/obj/item/storage/box/survival/syndie //why is this its own thing if it's just the engi box with a syndie mask and medipen?
|
||||
name = "extended-capacity survival box"
|
||||
desc = "A box with the bare essentials of ensuring the survival of you and others. This one is labelled to contain an extended-capacity tank."
|
||||
illustration = "extendedtank"
|
||||
mask_type = /obj/item/clothing/mask/gas/syndicate
|
||||
internal_type = /obj/item/tank/internals/emergency_oxygen/engi
|
||||
medipen_type = null
|
||||
|
||||
// Security survival box
|
||||
/obj/item/storage/box/security/PopulateContents()
|
||||
new /obj/item/clothing/mask/gas/sechailer(src)
|
||||
new /obj/item/reagent_containers/hypospray/medipen(src)
|
||||
/obj/item/storage/box/survival/security
|
||||
mask_type = /obj/item/clothing/mask/gas/sechailer
|
||||
|
||||
if(!isplasmaman(loc))
|
||||
new /obj/item/tank/internals/emergency_oxygen(src)
|
||||
else
|
||||
new /obj/item/tank/internals/plasmaman/belt(src)
|
||||
|
||||
/obj/item/storage/box/security/radio/PopulateContents()
|
||||
/obj/item/storage/box/survival/security/radio/PopulateContents()
|
||||
..() // we want the regular stuff too
|
||||
new /obj/item/radio/off(src)
|
||||
|
||||
@@ -1244,6 +1248,26 @@
|
||||
icon_state = "box_pink"
|
||||
illustration = null
|
||||
|
||||
/obj/item/storage/box/emergencytank
|
||||
name = "emergency oxygen tank box"
|
||||
desc = "A box of emergency oxygen tanks."
|
||||
illustration = "emergencytank"
|
||||
|
||||
/obj/item/storage/box/emergencytank/PopulateContents()
|
||||
..()
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/tank/internals/emergency_oxygen(src) //in case anyone ever wants to do anything with spawning them, apart from crafting the box
|
||||
|
||||
/obj/item/storage/box/engitank
|
||||
name = "extended-capacity emergency oxygen tank box"
|
||||
desc = "A box of extended-capacity emergency oxygen tanks."
|
||||
illustration = "extendedtank"
|
||||
|
||||
/obj/item/storage/box/engitank/PopulateContents()
|
||||
..()
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/tank/internals/emergency_oxygen/engi(src) //in case anyone ever wants to do anything with spawning them, apart from crafting the box
|
||||
|
||||
/obj/item/storage/box/mre //base MRE type.
|
||||
name = "Nanotrasen MRE Ration Kit Menu 0"
|
||||
desc = "A package containing food suspended in an outdated bluespace pocket which lasts for centuries. If you're lucky you may even be able to enjoy the meal without getting food poisoning."
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
new /obj/item/clothing/neck/petcollar(src) //I considered removing the pet stuff too but eh, who knows. We might get Renault back. Plus I guess you could use that collar for... other means. Aren't you supposed to be guarding the disk?
|
||||
new /obj/item/pet_carrier(src)
|
||||
new /obj/item/clothing/suit/armor/vest/capcarapace(src)
|
||||
new /obj/item/clothing/suit/armor/vest/capcarapace/alt(src)
|
||||
new /obj/item/clothing/suit/toggle/captains_parade(src)
|
||||
new /obj/item/clothing/head/crown/fancy(src)
|
||||
new /obj/item/cartridge/captain(src)
|
||||
new /obj/item/storage/box/silver_ids(src)
|
||||
@@ -56,6 +56,7 @@
|
||||
/obj/structure/closet/secure_closet/hos/PopulateContents()
|
||||
..()
|
||||
new /obj/item/clothing/neck/cloak/hos(src)
|
||||
new /obj/item/clothing/suit/toggle/armor/hos/hos_formal(src)
|
||||
new /obj/item/cartridge/hos(src)
|
||||
new /obj/item/radio/headset/heads/hos(src)
|
||||
new /obj/item/clothing/under/rank/security/head_of_security/parade/female(src)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* ## catwalk flooring
|
||||
*
|
||||
* They show what's underneath their catwalk flooring (pipes and the like)
|
||||
* you can crowbar it to interact with the underneath stuff without destroying the tile...
|
||||
* unless you want to!
|
||||
*/
|
||||
/turf/open/floor/plating/catwalk_floor
|
||||
icon = 'icons/turf/floors/catwalk_plating.dmi'
|
||||
icon_state = "catwalk_below"
|
||||
floor_tile = /obj/item/stack/tile/catwalk
|
||||
name = "catwalk floor"
|
||||
desc = "Flooring that shows its contents underneath. Engineers love it!"
|
||||
baseturfs = /turf/open/floor/plating
|
||||
footstep = FOOTSTEP_CATWALK
|
||||
barefootstep = FOOTSTEP_CATWALK
|
||||
clawfootstep = FOOTSTEP_CATWALK
|
||||
heavyfootstep = FOOTSTEP_CATWALK
|
||||
var/covered = TRUE
|
||||
|
||||
/turf/open/floor/plating/catwalk_floor/Initialize()
|
||||
. = ..()
|
||||
layer = CATWALK_LAYER
|
||||
update_icon(UPDATE_OVERLAYS)
|
||||
|
||||
/turf/open/floor/plating/catwalk_floor/update_overlays()
|
||||
. = ..()
|
||||
var/static/catwalk_overlay
|
||||
if(isnull(catwalk_overlay))
|
||||
catwalk_overlay = iconstate2appearance(icon, "catwalk_above")
|
||||
if(covered)
|
||||
. += catwalk_overlay
|
||||
|
||||
/turf/open/floor/plating/catwalk_floor/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
covered = !covered
|
||||
to_chat(user, span_notice("[!covered ? "You removed the cover!" : "You added the cover!"]"))
|
||||
update_icon(UPDATE_OVERLAYS)
|
||||
|
||||
/turf/open/floor/plating/catwalk_floor/pry_tile(obj/item/crowbar, mob/user, silent)
|
||||
if(covered)
|
||||
to_chat(user, span_notice("You need to remove the cover first!"))
|
||||
return FALSE
|
||||
. = ..()
|
||||
+1
-1
@@ -16,7 +16,7 @@ GLOBAL_LIST(topic_status_cache)
|
||||
call(debug_server, "auxtools_init")()
|
||||
enable_debugging()
|
||||
AUXTOOLS_CHECK(AUXMOS)
|
||||
#ifdef REFERENCE_TRACKING
|
||||
#ifdef EXTOOLS_REFERENCE_TRACKING
|
||||
enable_reference_tracking()
|
||||
#endif
|
||||
world.Profile(PROFILE_START)
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
/obj/machinery/vr_sleeper/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.lying || !iscarbon(target) || !Adjacent(target) || !user.canUseTopic(src, BE_CLOSE, TRUE, NO_TK))
|
||||
return
|
||||
if(occupant)
|
||||
to_chat(user, "<span class='boldnotice'>The VR Sleeper is already occupied!</span>")
|
||||
return
|
||||
close_machine(target)
|
||||
ui_interact(user)
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ GLOBAL_PROTECT(admin_verbs_debug)
|
||||
// #endif
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
/datum/admins/proc/fixcorruption,
|
||||
#ifdef REFERENCE_TRACKING
|
||||
#ifdef EXTOOLS_REFERENCE_TRACKING
|
||||
/datum/admins/proc/view_refs,
|
||||
/datum/admins/proc/view_del_failures,
|
||||
#endif
|
||||
|
||||
@@ -2862,7 +2862,7 @@
|
||||
return
|
||||
|
||||
if(!CONFIG_GET(string/centcom_ban_db))
|
||||
to_chat(usr, "<span class='warning'>Centcom Galactic Ban DB is disabled!</span>")
|
||||
to_chat(usr, span_warning("Centcom Galactic Ban DB is disabled!"))
|
||||
return
|
||||
|
||||
var/ckey = href_list["centcomlookup"]
|
||||
@@ -2889,8 +2889,19 @@
|
||||
dat += "<center><b>0 bans detected for [ckey]</b></center>"
|
||||
else
|
||||
bans = json_decode(response["body"])
|
||||
dat += "<center><b>[bans.len] ban\s detected for [ckey]</b></center>"
|
||||
|
||||
//Ignore bans from non-whitelisted sources, if a whitelist exists
|
||||
var/list/valid_sources
|
||||
if(CONFIG_GET(string/centcom_source_whitelist))
|
||||
valid_sources = splittext(CONFIG_GET(string/centcom_source_whitelist), ",")
|
||||
dat += "<center><b>Bans detected for [ckey]</b></center>"
|
||||
else
|
||||
//Ban count is potentially inaccurate if they're using a whitelist
|
||||
dat += "<center><b>[bans.len] ban\s detected for [ckey]</b></center>"
|
||||
|
||||
for(var/list/ban in bans)
|
||||
if(valid_sources && !(ban["sourceName"] in valid_sources))
|
||||
continue
|
||||
dat += "<b>Server: </b> [sanitize(ban["sourceName"])]<br>"
|
||||
dat += "<b>RP Level: </b> [sanitize(ban["sourceRoleplayLevel"])]<br>"
|
||||
dat += "<b>Type: </b> [sanitize(ban["type"])]<br>"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifdef REFERENCE_TRACKING
|
||||
#ifdef EXTOOLS_REFERENCE_TRACKING
|
||||
|
||||
GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
|
||||
@@ -102,29 +102,21 @@ GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
#ifdef REFERENCE_TRACKING
|
||||
|
||||
/datum/verb/legacy_find_refs()
|
||||
set category = "Debug"
|
||||
set name = "Find References"
|
||||
set src in world
|
||||
|
||||
find_references_legacy(FALSE)
|
||||
|
||||
|
||||
/datum/proc/find_references_legacy(skip_alert)
|
||||
/datum/proc/find_references(skip_alert)
|
||||
running_find_references = type
|
||||
if(usr?.client)
|
||||
if(usr.client.running_find_references)
|
||||
testing("CANCELLED search for references to a [usr.client.running_find_references].")
|
||||
log_reftracker("CANCELLED search for references to a [usr.client.running_find_references].")
|
||||
usr.client.running_find_references = null
|
||||
running_find_references = null
|
||||
//restart the garbage collector
|
||||
SSgarbage.can_fire = TRUE
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
SSgarbage.update_nextfire(reset_time = TRUE)
|
||||
return
|
||||
|
||||
if(!skip_alert && alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") != "Yes")
|
||||
if(!skip_alert && tgui_alert(usr,"Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", list("Yes", "No")) != "Yes")
|
||||
running_find_references = null
|
||||
return
|
||||
|
||||
@@ -134,92 +126,122 @@ GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
if(usr?.client)
|
||||
usr.client.running_find_references = type
|
||||
|
||||
testing("Beginning search for references to a [type].")
|
||||
last_find_references = world.time
|
||||
log_reftracker("Beginning search for references to a [type].")
|
||||
|
||||
var/starting_time = world.time
|
||||
|
||||
//Time to search the whole game for our ref
|
||||
DoSearchVar(GLOB, "GLOB") //globals
|
||||
log_reftracker("Finished searching globals")
|
||||
|
||||
DoSearchVar(GLOB) //globals
|
||||
for(var/datum/thing in world) //atoms (don't beleive its lies)
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
DoSearchVar(thing, "World -> [thing.type]", search_time = starting_time)
|
||||
log_reftracker("Finished searching atoms")
|
||||
|
||||
for(var/datum/thing) //datums
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
DoSearchVar(thing, "Datums -> [thing.type]", search_time = starting_time)
|
||||
log_reftracker("Finished searching datums")
|
||||
|
||||
//Warning, attempting to search clients like this will cause crashes if done on live. Watch yourself
|
||||
for(var/client/thing) //clients
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
DoSearchVar(thing, "Clients -> [thing.type]", search_time = starting_time)
|
||||
log_reftracker("Finished searching clients")
|
||||
|
||||
log_reftracker("Completed search for references to a [type].")
|
||||
|
||||
testing("Completed search for references to a [type].")
|
||||
if(usr?.client)
|
||||
usr.client.running_find_references = null
|
||||
running_find_references = null
|
||||
|
||||
//restart the garbage collector
|
||||
SSgarbage.can_fire = TRUE
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
SSgarbage.update_nextfire(reset_time = TRUE)
|
||||
|
||||
/datum/proc/DoSearchVar(potential_container, container_name, recursive_limit = 64, search_time = world.time)
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
if(!found_refs && SSgarbage.should_save_refs)
|
||||
found_refs = list()
|
||||
#endif
|
||||
|
||||
/datum/verb/qdel_then_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References"
|
||||
set src in world
|
||||
|
||||
qdel(src, TRUE) //force a qdel
|
||||
if(!running_find_references)
|
||||
find_references_legacy(TRUE)
|
||||
|
||||
|
||||
/datum/verb/qdel_then_if_fail_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References if GC failure"
|
||||
set src in world
|
||||
|
||||
qdel_and_find_ref_if_fail(src, TRUE)
|
||||
|
||||
|
||||
/datum/proc/DoSearchVar(potential_container, container_name, recursive_limit = 64)
|
||||
if(usr?.client && !usr.client.running_find_references)
|
||||
return
|
||||
|
||||
if(!recursive_limit)
|
||||
log_reftracker("Recursion limit reached. [container_name]")
|
||||
return
|
||||
|
||||
if(istype(potential_container, /datum))
|
||||
var/datum/datum_container = potential_container
|
||||
if(datum_container.last_find_references == last_find_references)
|
||||
return
|
||||
|
||||
datum_container.last_find_references = last_find_references
|
||||
var/list/vars_list = datum_container.vars
|
||||
|
||||
for(var/varname in vars_list)
|
||||
if (varname == "vars")
|
||||
continue
|
||||
var/variable = vars_list[varname]
|
||||
|
||||
if(variable == src)
|
||||
testing("Found [type] \ref[src] in [datum_container.type]'s [varname] var. [container_name]")
|
||||
|
||||
else if(islist(variable))
|
||||
DoSearchVar(variable, "[container_name] -> list", recursive_limit - 1)
|
||||
|
||||
else if(islist(potential_container))
|
||||
var/normal = IS_NORMAL_LIST(potential_container)
|
||||
for(var/element_in_list in potential_container)
|
||||
if(element_in_list == src)
|
||||
testing("Found [type] \ref[src] in list [container_name].")
|
||||
|
||||
else if(element_in_list && !isnum(element_in_list) && normal && potential_container[element_in_list] == src)
|
||||
testing("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]")
|
||||
|
||||
else if(islist(element_in_list))
|
||||
DoSearchVar(element_in_list, "[container_name] -> list", recursive_limit - 1)
|
||||
|
||||
//Check each time you go down a layer. This makes it a bit slow, but it won't effect the rest of the game at all
|
||||
#ifndef FIND_REF_NO_CHECK_TICK
|
||||
CHECK_TICK
|
||||
#endif
|
||||
|
||||
if(istype(potential_container, /datum))
|
||||
var/datum/datum_container = potential_container
|
||||
if(datum_container.last_find_references == search_time)
|
||||
return
|
||||
|
||||
datum_container.last_find_references = search_time
|
||||
var/list/vars_list = datum_container.vars
|
||||
|
||||
for(var/varname in vars_list)
|
||||
#ifndef FIND_REF_NO_CHECK_TICK
|
||||
CHECK_TICK
|
||||
#endif
|
||||
if (varname == "vars" || varname == "vis_locs") //Fun fact, vis_locs don't count for references
|
||||
continue
|
||||
var/variable = vars_list[varname]
|
||||
|
||||
if(variable == src)
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
if(SSgarbage.should_save_refs)
|
||||
found_refs[varname] = TRUE
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in [datum_container.type]'s \ref[datum_container] [varname] var. [container_name]")
|
||||
continue
|
||||
|
||||
if(islist(variable))
|
||||
DoSearchVar(variable, "[container_name] \ref[datum_container] -> [varname] (list)", recursive_limit - 1, search_time)
|
||||
|
||||
else if(islist(potential_container))
|
||||
var/normal = IS_NORMAL_LIST(potential_container)
|
||||
var/list/potential_cache = potential_container
|
||||
for(var/element_in_list in potential_cache)
|
||||
#ifndef FIND_REF_NO_CHECK_TICK
|
||||
CHECK_TICK
|
||||
#endif
|
||||
//Check normal entrys
|
||||
if(element_in_list == src)
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
if(SSgarbage.should_save_refs)
|
||||
found_refs[potential_cache] = TRUE
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in list [container_name].")
|
||||
continue
|
||||
|
||||
var/assoc_val = null
|
||||
if(!isnum(element_in_list) && normal)
|
||||
assoc_val = potential_cache[element_in_list]
|
||||
//Check assoc entrys
|
||||
if(assoc_val == src)
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
if(SSgarbage.should_save_refs)
|
||||
found_refs[potential_cache] = TRUE
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]")
|
||||
continue
|
||||
//We need to run both of these checks, since our object could be hiding in either of them
|
||||
//Check normal sublists
|
||||
if(islist(element_in_list))
|
||||
DoSearchVar(element_in_list, "[container_name] -> [element_in_list] (list)", recursive_limit - 1, search_time)
|
||||
//Check assoc sublists
|
||||
if(islist(assoc_val))
|
||||
DoSearchVar(potential_container[element_in_list], "[container_name]\[[element_in_list]\] -> [assoc_val] (list)", recursive_limit - 1, search_time)
|
||||
|
||||
/proc/qdel_and_find_ref_if_fail(datum/thing_to_del, force = FALSE)
|
||||
SSgarbage.reference_find_on_fail[REF(thing_to_del)] = TRUE
|
||||
qdel(thing_to_del, force)
|
||||
thing_to_del.qdel_and_find_ref_if_fail(force)
|
||||
|
||||
/datum/proc/qdel_and_find_ref_if_fail(force = FALSE)
|
||||
SSgarbage.reference_find_on_fail["\ref[src]"] = TRUE
|
||||
qdel(src, force)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
usr.client.debug_variables(src)
|
||||
return
|
||||
|
||||
#ifdef REFERENCE_TRACKING
|
||||
#ifdef EXTOOLS_REFERENCE_TRACKING
|
||||
if(href_list[VV_HK_VIEW_REFERENCES])
|
||||
var/datum/D = locate(href_list[VV_HK_TARGET])
|
||||
if(!D)
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
if((IS_HERETIC(local_user) || IS_HERETIC_MONSTER(local_user)) && HAS_TRAIT(src,TRAIT_NODROP))
|
||||
REMOVE_TRAIT(src, TRAIT_NODROP, CLOTHING_TRAIT)
|
||||
|
||||
for(var/mob/living/carbon/human/human_in_range in spiral_range(9,local_user))
|
||||
for(var/mob/living/carbon/human/human_in_range in viewers(9,local_user))
|
||||
if(IS_HERETIC(human_in_range) || IS_HERETIC_MONSTER(human_in_range))
|
||||
continue
|
||||
|
||||
|
||||
@@ -129,13 +129,12 @@
|
||||
/mob/living/simple_animal/slaughter/proc/release_victims()
|
||||
if(!consumed_mobs)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
T = find_safe_turf()
|
||||
for(var/mob/living/M in consumed_mobs)
|
||||
if(!M)
|
||||
continue
|
||||
var/turf/T = find_safe_turf()
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
M.forceMove(T)
|
||||
|
||||
/mob/living/simple_animal/slaughter/proc/refresh_consumed_buff()
|
||||
@@ -263,12 +262,12 @@
|
||||
if(!consumed_mobs)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
T = find_safe_turf()
|
||||
for(var/mob/living/M in consumed_mobs)
|
||||
if(!M)
|
||||
continue
|
||||
var/turf/T = find_safe_turf()
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
continue
|
||||
M.forceMove(T)
|
||||
if(M.revive(full_heal = TRUE, admin_revive = TRUE))
|
||||
M.grab_ghost(force = TRUE)
|
||||
|
||||
@@ -45,5 +45,5 @@ GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
/datum/traitor_class/proc/clean_up_traitor(datum/antagonist/traitor/T)
|
||||
// Any effects that need to be cleaned up if traitor class is being swapped.
|
||||
|
||||
/datum/traitor_class/proc/on_process(/datum/antagonist/traitor/T)
|
||||
/datum/traitor_class/proc/on_process(datum/antagonist/traitor/T)
|
||||
// only for processing traitor classes; runs once an SSprocessing tick
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
/datum/asset/simple/tgui_common
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui-common.bundle.js" = 'tgui/public/tgui-common.bundle.js',
|
||||
"tgui-common.bundle.js" = file("tgui/public/tgui-common.bundle.js"),
|
||||
)
|
||||
|
||||
/datum/asset/simple/tgui
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui.bundle.js" = 'tgui/public/tgui.bundle.js',
|
||||
"tgui.bundle.css" = 'tgui/public/tgui.bundle.css',
|
||||
"tgui.bundle.js" = file("tgui/public/tgui.bundle.js"),
|
||||
"tgui.bundle.css" = file("tgui/public/tgui.bundle.css"),
|
||||
)
|
||||
|
||||
/datum/asset/simple/tgui_panel
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui-panel.bundle.js" = 'tgui/public/tgui-panel.bundle.js',
|
||||
"tgui-panel.bundle.css" = 'tgui/public/tgui-panel.bundle.css',
|
||||
"tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"),
|
||||
"tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"),
|
||||
)
|
||||
|
||||
/datum/asset/simple/headers
|
||||
@@ -168,10 +168,12 @@
|
||||
|
||||
/datum/asset/simple/namespaced/tgfont
|
||||
assets = list(
|
||||
"tgfont.eot" = 'tgui/packages/tgfont/dist/tgfont.eot',
|
||||
"tgfont.woff2" = 'tgui/packages/tgfont/dist/tgfont.woff2',
|
||||
"tgfont.eot" = file("tgui/packages/tgfont/dist/tgfont.eot"),
|
||||
"tgfont.woff2" = file("tgui/packages/tgfont/dist/tgfont.woff2"),
|
||||
)
|
||||
parents = list(
|
||||
"tgfont.css" = file("tgui/packages/tgfont/dist/tgfont.css"),
|
||||
)
|
||||
parents = list("tgfont.css" = 'tgui/packages/tgfont/dist/tgfont.css')
|
||||
|
||||
/datum/asset/spritesheet/chat
|
||||
name = "chat"
|
||||
|
||||
@@ -157,6 +157,8 @@
|
||||
id = GAS_METHANE
|
||||
specific_heat = 30
|
||||
name = "Methane"
|
||||
powerloss_inhibition = 1
|
||||
heat_resistance = 3
|
||||
breath_results = GAS_METHYL_BROMIDE
|
||||
fire_products = list(GAS_CO2 = 1, GAS_H2O = 2)
|
||||
fire_burn_rate = 0.5
|
||||
@@ -177,6 +179,8 @@
|
||||
id = GAS_METHYL_BROMIDE
|
||||
specific_heat = 42
|
||||
name = "Methyl Bromide"
|
||||
powermix = 1
|
||||
heat_penalty = -1
|
||||
flags = GAS_FLAG_DANGEROUS
|
||||
breath_alert_info = list(
|
||||
not_enough_alert = list(
|
||||
|
||||
@@ -32,6 +32,11 @@
|
||||
if(!blocks_air)
|
||||
air = new(2500,src)
|
||||
air.copy_from_turf(src)
|
||||
if(planetary_atmos && !(initial_gas_mix in SSair.planetary))
|
||||
var/datum/gas_mixture/mix = new
|
||||
mix.parse_gas_string(initial_gas_mix)
|
||||
mix.mark_immutable()
|
||||
SSair.planetary[initial_gas_mix] = mix
|
||||
update_air_ref(planetary_atmos ? 1 : 2)
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -261,6 +261,8 @@ we use a hook instead
|
||||
return 1
|
||||
|
||||
/datum/gas_mixture/parse_gas_string(gas_string)
|
||||
gas_string = SSair.preprocess_gas_string(gas_string)
|
||||
|
||||
var/list/gas = params2list(gas_string)
|
||||
if(gas["TEMP"])
|
||||
var/temp = text2num(gas["TEMP"])
|
||||
|
||||
@@ -648,7 +648,7 @@
|
||||
//Replace miasma with oxygen
|
||||
var/cleaned_air = min(air.get_moles(GAS_MIASMA), 20 + (air.return_temperature() - FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 70) / 20)
|
||||
air.adjust_moles(GAS_MIASMA, -cleaned_air)
|
||||
air.adjust_moles(GAS_O2, cleaned_air)
|
||||
air.adjust_moles(GAS_METHANE, cleaned_air)
|
||||
|
||||
//Possibly burning a bit of organic matter through maillard reaction, so a *tiny* bit more heat would be understandable
|
||||
air.set_temperature(air.return_temperature() + cleaned_air * 0.002)
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
/obj/machinery/atmospherics/pipe/setPipenet(datum/pipeline/P)
|
||||
parent = P
|
||||
|
||||
/obj/machinery/atmospherics/pipe/zap_act(power, zap_flags)
|
||||
return 0 // they're not really machines in the normal sense, probably shouldn't explode
|
||||
|
||||
/obj/machinery/atmospherics/pipe/Destroy()
|
||||
QDEL_NULL(parent)
|
||||
|
||||
|
||||
@@ -70,6 +70,12 @@
|
||||
cost = 1500
|
||||
contains = list(/obj/item/toy/plush/beeplushie)
|
||||
|
||||
/datum/supply_pack/goody/dyespray
|
||||
name = "Hair Dye Spray"
|
||||
desc = "A cool spray to dye your hair with awesome colors!"
|
||||
cost = PAYCHECK_EASY * 2
|
||||
contains = list(/obj/item/dyespray)
|
||||
|
||||
/datum/supply_pack/goody/beach_ball
|
||||
name = "Beach Ball"
|
||||
desc = "The simple beach ball is one of Nanotrasen's most popular products. 'Why do we make beach balls? Because we can! (TM)' - Nanotrasen"
|
||||
|
||||
@@ -60,6 +60,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
//autocorrected this round, not that you'd need to check that.
|
||||
|
||||
var/UI_style = null
|
||||
var/outline_enabled = TRUE
|
||||
var/outline_color = COLOR_BLUE_GRAY
|
||||
var/buttons_locked = FALSE
|
||||
var/hotkeys = FALSE
|
||||
|
||||
@@ -117,6 +119,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/hair_color = "000000" //Hair color
|
||||
var/facial_hair_style = "Shaved" //Face hair type
|
||||
var/facial_hair_color = "000000" //Facial hair color
|
||||
var/grad_style //Hair gradient style
|
||||
var/grad_color = "FFFFFF" //Hair gradient color
|
||||
var/skin_tone = "caucasian1" //Skin color
|
||||
var/use_custom_skin_tone = FALSE
|
||||
var/left_eye_color = "000000" //Eye color
|
||||
@@ -503,6 +507,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<a href='?_src_=prefs;preference=previous_facehair_style;task=input'><</a> <a href='?_src_=prefs;preference=next_facehair_style;task=input'>></a><BR>"
|
||||
dat += "<span style='border: 1px solid #161616; background-color: #[facial_hair_color];'> </span> <a href='?_src_=prefs;preference=facial;task=input'>Change</a><BR>"
|
||||
|
||||
dat += "<h3>Hair Gradient</h3>"
|
||||
|
||||
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=grad_style;task=input'>[grad_style]</a>"
|
||||
dat += "<a href='?_src_=prefs;preference=previous_grad_style;task=input'><</a> <a href='?_src_=prefs;preference=next_grad_style;task=input'>></a><BR>"
|
||||
dat += "<span style='border: 1px solid #161616; background-color: #[grad_color];'> </span> <a href='?_src_=prefs;preference=grad_color;task=input'>Change</a><BR>"
|
||||
|
||||
dat += "</td>"
|
||||
//Mutant stuff
|
||||
var/mutant_category = 0
|
||||
@@ -774,6 +784,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<table><tr><td width='340px' height='300px' valign='top'>"
|
||||
dat += "<h2>General Settings</h2>"
|
||||
dat += "<b>UI Style:</b> <a href='?_src_=prefs;task=input;preference=ui'>[UI_style]</a><br>"
|
||||
dat += "<b>Outline:</b> <a href='?_src_=prefs;preference=outline_enabled'>[outline_enabled ? "Enabled" : "Disabled"]</a><br>"
|
||||
dat += "<b>Outline Color:</b> <span style='border:1px solid #161616; background-color: [outline_color];'> </span> <a href='?_src_=prefs;preference=outline_color'>Change</a><BR>"
|
||||
dat += "<b>tgui Monitors:</b> <a href='?_src_=prefs;preference=tgui_lock'>[(tgui_lock) ? "Primary" : "All"]</a><br>"
|
||||
dat += "<b>tgui Style:</b> <a href='?_src_=prefs;preference=tgui_fancy'>[(tgui_fancy) ? "Fancy" : "No Frills"]</a><br>"
|
||||
dat += "<b>Show Runechat Chat Bubbles:</b> <a href='?_src_=prefs;preference=chat_on_map'>[chat_on_map ? "Enabled" : "Disabled"]</a><br>"
|
||||
@@ -1707,6 +1719,23 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if("previous_facehair_style")
|
||||
facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_list)
|
||||
|
||||
if("grad_color")
|
||||
var/new_grad_color = input(user, "Choose your character's gradient colour:", "Character Preference","#"+grad_color) as color|null
|
||||
if(new_grad_color)
|
||||
grad_color = sanitize_hexcolor(new_grad_color, 6)
|
||||
|
||||
if("grad_style")
|
||||
var/new_grad_style
|
||||
new_grad_style = input(user, "Choose your character's hair gradient style:", "Character Preference") as null|anything in GLOB.hair_gradients_list
|
||||
if(new_grad_style)
|
||||
grad_style = new_grad_style
|
||||
|
||||
if("next_grad_style")
|
||||
grad_style = next_list_item(grad_style, GLOB.hair_gradients_list)
|
||||
|
||||
if("previous_grad_style")
|
||||
grad_style = previous_list_item(grad_style, GLOB.hair_gradients_list)
|
||||
|
||||
if("cycle_bg")
|
||||
bgstate = next_list_item(bgstate, bgstate_options)
|
||||
|
||||
@@ -2706,6 +2735,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
buttons_locked = !buttons_locked
|
||||
if("tgui_fancy")
|
||||
tgui_fancy = !tgui_fancy
|
||||
if("outline_enabled")
|
||||
outline_enabled = !outline_enabled
|
||||
if("outline_color")
|
||||
var/pickedOutlineColor = input(user, "Choose your outline color.", "General Preference", outline_color) as color|null
|
||||
if(pickedOutlineColor)
|
||||
outline_color = pickedOutlineColor
|
||||
if("tgui_lock")
|
||||
tgui_lock = !tgui_lock
|
||||
if("winflash")
|
||||
@@ -3006,6 +3041,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
character.dna.skin_tone_override = use_custom_skin_tone ? skin_tone : null
|
||||
character.hair_style = hair_style
|
||||
character.facial_hair_style = facial_hair_style
|
||||
character.grad_style = grad_style
|
||||
character.grad_color = grad_color
|
||||
character.underwear = underwear
|
||||
|
||||
character.saved_underwear = underwear
|
||||
@@ -3070,6 +3107,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(additional_language && additional_language != "None")
|
||||
var/language_entry = GLOB.roundstart_languages[additional_language]
|
||||
if(language_entry)
|
||||
character.additional_language = language_entry
|
||||
character.grant_language(language_entry, TRUE, TRUE)
|
||||
|
||||
//limb stuff, only done when initially spawning in
|
||||
|
||||
@@ -45,6 +45,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
if(current_version < 46) //If you remove this, remove force_reset_keybindings() too.
|
||||
force_reset_keybindings_direct(TRUE)
|
||||
addtimer(CALLBACK(src, .proc/force_reset_keybindings), 30) //No mob available when this is run, timer allows user choice.
|
||||
if(current_version < 30)
|
||||
outline_enabled = TRUE
|
||||
outline_color = COLOR_BLUE_GRAY
|
||||
|
||||
/datum/preferences/proc/update_character(current_version, savefile/S)
|
||||
if(current_version < 19)
|
||||
@@ -377,6 +380,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["ooccolor"] >> ooccolor
|
||||
S["lastchangelog"] >> lastchangelog
|
||||
S["UI_style"] >> UI_style
|
||||
S["outline_color"] >> outline_color
|
||||
S["outline_enabled"] >> outline_enabled
|
||||
S["hotkeys"] >> hotkeys
|
||||
S["chat_on_map"] >> chat_on_map
|
||||
S["max_chat_length"] >> max_chat_length
|
||||
@@ -555,6 +560,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["ooccolor"], ooccolor)
|
||||
WRITE_FILE(S["lastchangelog"], lastchangelog)
|
||||
WRITE_FILE(S["UI_style"], UI_style)
|
||||
WRITE_FILE(S["outline_enabled"], outline_enabled)
|
||||
WRITE_FILE(S["outline_color"], outline_color)
|
||||
WRITE_FILE(S["hotkeys"], hotkeys)
|
||||
WRITE_FILE(S["chat_on_map"], chat_on_map)
|
||||
WRITE_FILE(S["max_chat_length"], max_chat_length)
|
||||
@@ -676,6 +683,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["skin_tone"] >> skin_tone
|
||||
S["hair_style_name"] >> hair_style
|
||||
S["facial_style_name"] >> facial_hair_style
|
||||
S["grad_style"] >> grad_style
|
||||
S["grad_color"] >> grad_color
|
||||
S["underwear"] >> underwear
|
||||
S["undie_color"] >> undie_color
|
||||
S["undershirt"] >> undershirt
|
||||
@@ -868,6 +877,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
|
||||
hair_color = sanitize_hexcolor(hair_color, 6, FALSE)
|
||||
facial_hair_color = sanitize_hexcolor(facial_hair_color, 6, FALSE)
|
||||
grad_style = sanitize_inlist(grad_style, GLOB.hair_gradients_list, "None")
|
||||
grad_color = sanitize_hexcolor(grad_color, 6, FALSE)
|
||||
eye_type = sanitize_inlist(eye_type, GLOB.eye_types, DEFAULT_EYES_TYPE)
|
||||
left_eye_color = sanitize_hexcolor(left_eye_color, 6, FALSE)
|
||||
right_eye_color = sanitize_hexcolor(right_eye_color, 6, FALSE)
|
||||
@@ -1037,6 +1048,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["skin_tone"] , skin_tone)
|
||||
WRITE_FILE(S["hair_style_name"] , hair_style)
|
||||
WRITE_FILE(S["facial_style_name"] , facial_hair_style)
|
||||
WRITE_FILE(S["grad_style"] , grad_style)
|
||||
WRITE_FILE(S["grad_color"] , grad_color)
|
||||
WRITE_FILE(S["underwear"] , underwear)
|
||||
WRITE_FILE(S["undie_color"] , undie_color)
|
||||
WRITE_FILE(S["undershirt"] , undershirt)
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
icon_state = "clown"
|
||||
item_state = "clown_hat"
|
||||
dye_color = "clown"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
flags_cover = MASKCOVERSEYES
|
||||
resistance_flags = FLAMMABLE
|
||||
actions_types = list(/datum/action/item_action/adjust)
|
||||
@@ -131,6 +132,7 @@
|
||||
clothing_flags = ALLOWINTERNALS
|
||||
icon_state = "mime"
|
||||
item_state = "mime"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
flags_cover = MASKCOVERSEYES
|
||||
resistance_flags = FLAMMABLE
|
||||
actions_types = list(/datum/action/item_action/adjust)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
glasses = /obj/item/clothing/glasses/hud/security/sunglasses
|
||||
back = /obj/item/storage/backpack/captain
|
||||
belt = /obj/item/storage/belt/security/full
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer=1,\
|
||||
/obj/item/gun/energy/e_gun=1)
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/ert/alert
|
||||
glasses = /obj/item/clothing/glasses/thermal/eyepatch
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer/swat=1,\
|
||||
/obj/item/gun/energy/e_gun=1)
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
/datum/outfit/ert/commander/alert/red
|
||||
name = "ERT Commander - Red Alert"
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer/swat=1,\
|
||||
/obj/item/gun/energy/pulse/pistol/loyalpin=1)
|
||||
@@ -71,7 +71,7 @@
|
||||
glasses = /obj/item/clothing/glasses/hud/security/sunglasses
|
||||
belt = /obj/item/storage/belt/security/full
|
||||
back = /obj/item/storage/backpack/security
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/storage/box/handcuffs=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer=1,\
|
||||
/obj/item/gun/energy/e_gun/stun=1,\
|
||||
@@ -91,7 +91,7 @@
|
||||
name = "ERT Security - Amber Alert"
|
||||
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/ert/alert/sec
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/storage/box/handcuffs=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer/swat=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
@@ -99,7 +99,7 @@
|
||||
|
||||
/datum/outfit/ert/security/alert/red
|
||||
name = "ERT Security - Red Alert"
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/storage/box/handcuffs=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer/swat=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
@@ -114,7 +114,7 @@
|
||||
back = /obj/item/storage/backpack/satchel/med
|
||||
belt = /obj/item/storage/belt/medical
|
||||
r_hand = /obj/item/storage/firstaid/regular
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer=1,\
|
||||
/obj/item/gun/energy/e_gun=1,\
|
||||
@@ -135,7 +135,7 @@
|
||||
name = "ERT Medic - Amber Alert"
|
||||
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/ert/alert/med
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer/swat=1,\
|
||||
/obj/item/gun/energy/e_gun=1,\
|
||||
@@ -144,7 +144,7 @@
|
||||
|
||||
/datum/outfit/ert/medic/alert/red
|
||||
name = "ERT Medic - Red Alert"
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer/swat=1,\
|
||||
/obj/item/gun/energy/pulse/pistol/loyalpin=1,\
|
||||
@@ -161,7 +161,7 @@
|
||||
belt = /obj/item/storage/belt/utility/full
|
||||
l_pocket = /obj/item/rcd_ammo/large
|
||||
r_hand = /obj/item/storage/firstaid/regular
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer=1,\
|
||||
/obj/item/gun/energy/e_gun=1,\
|
||||
@@ -181,7 +181,7 @@
|
||||
name = "ERT Engineer - Amber Alert"
|
||||
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/ert/alert/engi
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer/swat=1,\
|
||||
/obj/item/gun/energy/e_gun=1,\
|
||||
@@ -189,7 +189,7 @@
|
||||
|
||||
/datum/outfit/ert/engineer/alert/red
|
||||
name = "ERT Engineer - Red Alert"
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,\
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,\
|
||||
/obj/item/melee/baton/loaded=1,\
|
||||
/obj/item/clothing/mask/gas/sechailer/swat=1,\
|
||||
/obj/item/gun/energy/pulse/pistol/loyalpin=1,\
|
||||
@@ -260,7 +260,7 @@
|
||||
name = "Inquisition Commander"
|
||||
r_hand = /obj/item/nullrod/scythe/talking/chainsword
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,
|
||||
/obj/item/clothing/mask/gas/sechailer=1,
|
||||
/obj/item/gun/energy/e_gun=1)
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor
|
||||
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,
|
||||
/obj/item/storage/box/handcuffs=1,
|
||||
/obj/item/clothing/mask/gas/sechailer=1,
|
||||
/obj/item/gun/energy/e_gun/stun=1,
|
||||
@@ -281,7 +281,7 @@
|
||||
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor
|
||||
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,
|
||||
/obj/item/melee/baton/loaded=1,
|
||||
/obj/item/clothing/mask/gas/sechailer=1,
|
||||
/obj/item/gun/energy/e_gun=1,
|
||||
@@ -307,7 +307,7 @@
|
||||
glasses = /obj/item/clothing/glasses/hud/health
|
||||
back = /obj/item/storage/backpack/cultpack
|
||||
belt = /obj/item/storage/belt/soulstone
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,
|
||||
/obj/item/nullrod=1,
|
||||
/obj/item/clothing/mask/gas/sechailer=1,
|
||||
/obj/item/gun/energy/e_gun=1,
|
||||
@@ -319,7 +319,7 @@
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor
|
||||
|
||||
belt = /obj/item/storage/belt/soulstone/full/chappy
|
||||
backpack_contents = list(/obj/item/storage/box/engineer=1,
|
||||
backpack_contents = list(/obj/item/storage/box/survival/engineer=1,
|
||||
/obj/item/grenade/chem_grenade/holy=1,
|
||||
/obj/item/nullrod=1,
|
||||
/obj/item/clothing/mask/gas/sechailer=1,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
id = /obj/item/card/id/syndicate/locked_banking
|
||||
belt = /obj/item/gun/ballistic/automatic/pistol
|
||||
l_pocket = /obj/item/paper/fluff/vr/fluke_ops
|
||||
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)
|
||||
starting_funds = 0 //Should be operating, not shopping.
|
||||
|
||||
|
||||
@@ -237,12 +237,28 @@
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/mining/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/armor_plate)
|
||||
RegisterSignal(src, COMSIG_ARMOR_PLATED, .proc/upgrade_icon)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/mining/proc/upgrade_icon(datum/source, amount, maxamount)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(amount)
|
||||
name = "reinforced [initial(name)]"
|
||||
hardsuit_type = "mining_goliath"
|
||||
if(amount == maxamount)
|
||||
hardsuit_type = "mining_goliath_full"
|
||||
icon_state = "hardsuit[on]-[hardsuit_type]"
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/wearer = loc
|
||||
if(wearer.head == src)
|
||||
wearer.update_inv_head()
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/mining
|
||||
icon_state = "hardsuit-mining"
|
||||
name = "mining hardsuit"
|
||||
desc = "A special suit that protects against hazardous, low pressure environments. Has reinforced plating for wildlife encounters."
|
||||
item_state = "mining_hardsuit"
|
||||
hardsuit_type = "mining"
|
||||
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
|
||||
resistance_flags = FIRE_PROOF
|
||||
armor = list("melee" = 30, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 75, "wound" = 15)
|
||||
@@ -254,6 +270,21 @@
|
||||
/obj/item/clothing/suit/space/hardsuit/mining/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/armor_plate)
|
||||
RegisterSignal(src, COMSIG_ARMOR_PLATED, .proc/upgrade_icon)
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/mining/proc/upgrade_icon(datum/source, amount, maxamount)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(amount)
|
||||
name = "reinforced [initial(name)]"
|
||||
hardsuit_type = "mining_goliath"
|
||||
if(amount == maxamount)
|
||||
hardsuit_type = "mining_goliath_full"
|
||||
icon_state = "hardsuit-[hardsuit_type]"
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/wearer = loc
|
||||
if(wearer.wear_suit == src)
|
||||
wearer.update_inv_wear_suit()
|
||||
|
||||
//Syndicate hardsuit
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/syndi
|
||||
|
||||
@@ -136,17 +136,24 @@
|
||||
icon_state = "syndievest"
|
||||
mutantrace_variation = STYLE_DIGITIGRADE
|
||||
|
||||
/obj/item/clothing/suit/armor/vest/capcarapace/alt
|
||||
/obj/item/clothing/suit/toggle/captains_parade
|
||||
name = "captain's parade jacket"
|
||||
desc = "For when an armoured vest isn't fashionable enough."
|
||||
icon_state = "capformal"
|
||||
item_state = "capspacesuit"
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
armor = list("melee" = 50, "bullet" = 40, "laser" = 50, "energy" = 50, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 90, "wound" = 10)
|
||||
togglename = "buttons"
|
||||
|
||||
/obj/item/clothing/suit/toggle/captains_parade/Initialize()
|
||||
. = ..()
|
||||
allowed = GLOB.security_wintercoat_allowed
|
||||
|
||||
/obj/item/clothing/suit/armor/riot
|
||||
name = "riot suit"
|
||||
desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks. Helps the wearer resist shoving in close quarters."
|
||||
icon_state = "swat"
|
||||
item_state = "swat_suit"
|
||||
icon_state = "riot"
|
||||
item_state = "riot"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
@@ -319,3 +326,29 @@
|
||||
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
|
||||
armor = list("melee" = 25, "bullet" = 20, "laser" = 20, "energy" = 10, "bomb" = 20, "bio" = 50, "rad" = 20, "fire" = -10, "acid" = 50, "wound" = 10)
|
||||
|
||||
/obj/item/clothing/suit/toggle/armor/vest/centcom_formal
|
||||
name = "\improper CentCom formal coat"
|
||||
desc = "A stylish coat given to CentCom Commanders. Perfect for sending ERTs to suicide missions with style!"
|
||||
icon_state = "centcom_formal"
|
||||
item_state = "centcom"
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
armor = list("melee" = 35, "bullet" = 40, "laser" = 40, "energy" = 50, "bomb" = 35, "bio" = 10, "rad" = 10, "fire" = 10, "acid" = 60)
|
||||
togglename = "buttons"
|
||||
|
||||
/obj/item/clothing/suit/toggle/armor/vest/centcom_formal/Initialize()
|
||||
. = ..()
|
||||
allowed = GLOB.security_wintercoat_allowed
|
||||
|
||||
/obj/item/clothing/suit/toggle/armor/hos/hos_formal
|
||||
name = "\improper Head of Security's parade jacket"
|
||||
desc = "For when an armoured vest isn't fashionable enough."
|
||||
icon_state = "hosformal"
|
||||
item_state = "hostrench"
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 40, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 90, "wound" = 10)
|
||||
togglename = "buttons"
|
||||
|
||||
/obj/item/clothing/suit/toggle/armor/hos/hos_formal/Initialize()
|
||||
. = ..()
|
||||
allowed = GLOB.security_wintercoat_allowed
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
var/hoodtype = /obj/item/clothing/head/hooded/winterhood //so the chaplain hoodie or other hoodies can override this
|
||||
///Alternative mode for hiding the hood, instead of storing the hood in the suit it qdels it, useful for when you deal with hooded suit with storage.
|
||||
var/alternative_mode = FALSE
|
||||
var/no_t //do not update sprites when pulling up hood so we can avoid oddities with certain mechanics
|
||||
|
||||
/obj/item/clothing/suit/hooded/Initialize()
|
||||
. = ..()
|
||||
@@ -51,6 +52,8 @@
|
||||
update_icon()
|
||||
|
||||
/obj/item/clothing/suit/hooded/update_icon_state()
|
||||
if(no_t)
|
||||
return
|
||||
icon_state = "[initial(icon_state)]"
|
||||
if(ishuman(hood?.loc))
|
||||
var/mob/living/carbon/human/H = hood.loc
|
||||
|
||||
@@ -27,13 +27,27 @@
|
||||
if(prob(low_threat_perc))
|
||||
severity = "low; the supermatter should return to normal operation shortly."
|
||||
else
|
||||
severity = "medium; the supermatter should return to normal operation, but check NT CIMS to ensure this."
|
||||
severity = "medium; the supermatter should return to normal operation, but regardless, check if the emitters may need to be turned off temporarily."
|
||||
else
|
||||
severity = "high; if the supermatter's cooling is not fortified, coolant may need to be added."
|
||||
severity = "high; the emitters likely need to be turned off, and if the supermatter's cooling loop is not fortified, pre-cooled gas may need to be added."
|
||||
if(100000 to INFINITY)
|
||||
severity = "extreme; emergency action is likely to be required even if coolant loop is fine."
|
||||
severity = "extreme; emergency action is likely to be required even if coolant loop is fine. Turn off the emitters and make sure the loop is properly cooling gases."
|
||||
if(power > 20000 || prob(round(power/200)))
|
||||
priority_announce("Supermatter surge detected. Estimated severity is [severity]", "Anomaly Alert")
|
||||
|
||||
/datum/round_event/supermatter_surge/start()
|
||||
GLOB.main_supermatter_engine.matter_power += power
|
||||
var/obj/machinery/power/supermatter_crystal/supermatter = GLOB.main_supermatter_engine
|
||||
var/power_proportion = supermatter.powerloss_inhibitor/2 // what % of the power goes into matter power, at most 50%
|
||||
// we reduce the proportion that goes into actual matter power based on powerloss inhibitor
|
||||
// primarily so the supermatter doesn't tesla the instant these happen
|
||||
supermatter.matter_power += power * power_proportion
|
||||
var/datum/gas_mixture/methane_puff = new
|
||||
var/selected_gas = pick(4;GAS_CO2, 10;GAS_METHANE, 4;GAS_H2O, 1;GAS_BZ, 1;GAS_METHYL_BROMIDE)
|
||||
methane_puff.set_moles(selected_gas, 500)
|
||||
methane_puff.set_temperature(500)
|
||||
var/energy_ratio = (power * 500 * (1-power_proportion)) / methane_puff.thermal_energy()
|
||||
if(energy_ratio < 1) // energy output we want is lower than current energy, reduce the amount of gas we puff out
|
||||
methane_puff.set_moles(GAS_METHANE, energy_ratio * 500)
|
||||
else // energy output we want is higher than current energy, increase its actual heat
|
||||
methane_puff.set_temperature(energy_ratio * 500)
|
||||
supermatter.assume_air(methane_puff)
|
||||
|
||||
@@ -641,6 +641,18 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and
|
||||
/datum/holiday/easter/getStationPrefix()
|
||||
return pick("Fluffy","Bunny","Easter","Egg")
|
||||
|
||||
/datum/holiday/ianbirthday
|
||||
name = "Ian's Birthday" //github.com/tgstation/tgstation/commit/de7e4f0de0d568cd6e1f0d7bcc3fd34700598acb
|
||||
begin_month = SEPTEMBER
|
||||
begin_day = 9
|
||||
end_day = 10
|
||||
|
||||
/datum/holiday/ianbirthday/greet()
|
||||
return "Happy birthday, Ian!"
|
||||
|
||||
/datum/holiday/ianbirthday/getStationPrefix()
|
||||
return pick("Ian", "Corgi", "Erro")
|
||||
|
||||
//Random citadel thing for halloween species
|
||||
/proc/force_enable_halloween_species()
|
||||
var/list/oldlist = SSevents.holidays
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
backpack = /obj/item/storage/backpack/industrial
|
||||
satchel = /obj/item/storage/backpack/satchel/eng
|
||||
duffelbag = /obj/item/storage/backpack/duffelbag/engineering
|
||||
box = /obj/item/storage/box/engineer
|
||||
box = /obj/item/storage/box/survival/engineer
|
||||
pda_slot = SLOT_L_STORE
|
||||
backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
backpack = /obj/item/storage/backpack/industrial
|
||||
satchel = /obj/item/storage/backpack/satchel/eng
|
||||
duffelbag = /obj/item/storage/backpack/duffelbag/engineering
|
||||
box = /obj/item/storage/box/engineer
|
||||
box = /obj/item/storage/box/survival/engineer
|
||||
pda_slot = SLOT_L_STORE
|
||||
chameleon_extras = /obj/item/stamp/ce
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user