Merge branch 'master' into Dispencer-UI-change

This commit is contained in:
Fermi
2021-02-06 02:40:27 +00:00
836 changed files with 9220 additions and 5737 deletions

View File

@@ -1,6 +1,5 @@
.dockerignore
.editorconfig
.travis.yml
GPLv3.txt
LICENSE
README.md
@@ -26,5 +25,4 @@ tgstation.dyn.rsc
libmariadb.dll
rust_g.dll
BSQL.dll
appveyor.yml
Dockerfile

3
.gitattributes vendored
View File

@@ -38,5 +38,8 @@
*.dmm text eol=lf merge=dmm
*.dmi binary merge=dmi
##Force tab indents on dm files
*.dm whitespace=indent-with-non-tab
## Force changelog merging to use union
html/changelog.html text eol=lf merge=union

114
.github/workflows/ci_suite.yml vendored Normal file
View File

@@ -0,0 +1,114 @@
name: CI Suite
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
run_linters:
if: "!contains(github.event.head_commit.message, '[ci skip]')"
name: Run Linters
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup cache
uses: actions/cache@v2
with:
path: $HOME/SpacemanDMM
key: ${{ runner.os }}-spacemandmm
- name: Install Tools
run: |
pip3 install setuptools
bash tools/ci/install_build_tools.sh
bash tools/ci/install_spaceman_dmm.sh dreamchecker
pip3 install -r tools/mapmerge2/requirements.txt
- name: Run Linters
run: |
bash tools/ci/check_filedirs.sh tgstation.dme
bash tools/ci/check_changelogs.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
bash tools/ci/build_tgui.sh
bash tools/ci/check_grep.sh
python3 tools/mapmerge2/dmi.py --test
~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1
- name: Annotate Lints
uses: yogstation13/DreamAnnotate@v1
if: always()
with:
outputFile: output-annotations.txt
compile_all_maps:
if: "!contains(github.event.head_commit.message, '[ci skip]')"
name: Compile Maps
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup cache
uses: actions/cache@v2
with:
path: $HOME/BYOND
key: ${{ runner.os }}-byond
- name: Compile All Maps
run: |
bash tools/ci/install_byond.sh
source $HOME/BYOND/byond/bin/byondsetup
python3 tools/ci/template_dm_generator.py
bash tools/ci/dm.sh -DCIBUILDING -DCITESTING -DALL_MAPS tgstation.dme
run_all_tests:
if: "!contains(github.event.head_commit.message, '[ci skip]')"
name: Integration Tests
runs-on: ubuntu-latest
services:
mysql:
image: mysql:latest
env:
MYSQL_ROOT_PASSWORD: root
ports:
- 3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v2
- name: Setup cache
uses: actions/cache@v2
with:
path: $HOME/BYOND
key: ${{ runner.os }}-byond
- name: Setup database
run: |
sudo systemctl start mysql
mysql -u root -proot -e 'CREATE DATABASE tg_ci;'
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-g
run: |
sudo dpkg --add-architecture i386
sudo apt update || true
sudo apt install libssl1.1:i386
bash tools/ci/install_rust_g.sh
# - name: Compile and run tests
# run: |
# bash tools/ci/install_byond.sh
# source $HOME/BYOND/byond/bin/byondsetup
# bash tools/ci/dm.sh -DCIBUILDING tgstation.dme
# bash tools/ci/run_server.sh
test_windows:
if: "!contains(github.event.head_commit.message, '[ci skip]')"
name: Windows Build
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Compile
run: pwsh tools/ci/build.ps1
- name: Create artifact
run: |
md deploy
bash tools/deploy.sh ./deploy
- name: Deploy artifact
uses: actions/upload-artifact@v2
with:
name: deploy
path: deploy

View File

@@ -15,7 +15,7 @@ jobs:
CHANGELOG_ENABLER: ${{ secrets.CHANGELOG_ENABLER }}
run: |
unset SECRET_EXISTS
if [-n $CHANGELOG_ENABLER]; then SECRET_EXISTS='true' ; fi
if [ -n $CHANGELOG_ENABLER ]; then SECRET_EXISTS='true' ; fi
echo ::set-output name=CL_ENABLED::${SECRET_EXISTS}
- name: "Setup python"
if: steps.value_holder.outputs.CL_ENABLED

22
.github/workflows/docker_publish.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Docker Build
on:
push:
branches:
- master
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build and Publish Docker Image to Registry
uses: elgohr/Publish-Docker-Github-Action@master
with:
name: tgstation/tgstation
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
dockerfile: Dockerfile
tags: "latest"
cache: true

View File

@@ -0,0 +1,31 @@
name: Generate documentation
on:
push:
branches:
- master
jobs:
generate_documentation:
if: "!contains(github.event.head_commit.message, '[ci skip]')"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup cache
uses: actions/cache@v2
with:
path: $HOME/SpacemanDMM
key: ${{ runner.os }}-spacemandmm
- name: Install SpacemanDMM
run: bash tools/ci/install_spaceman_dmm.sh dmdoc
- name: Generate documentation
run: |
~/dmdoc
touch dmdoc/.nojekyll
echo codedocs.tgstation13.org > dmdoc/CNAME
- name: Deploy
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
BRANCH: gh-pages
CLEAN: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SINGLE_COMMIT: true
FOLDER: dmdoc

View File

@@ -26,6 +26,7 @@ jobs:
library-path: 'code/modules/tgs'
- name: Commit and Push
continue-on-error: true
run: |
git config user.name tgstation-server
git config user.email tgstation-server@users.noreply.github.com
@@ -35,6 +36,7 @@ jobs:
- name: Create Pull Request
uses: repo-sync/pull-request@v2
if: ${{ success() }}
with:
source_branch: "tgs-dmapi-update"
destination_branch: "master"
@@ -42,4 +44,4 @@ jobs:
pr_body: "This pull request updates the TGS DMAPI to the latest version. Please note any breaking or unimplemented changes before merging."
pr_label: "Tools"
pr_allow_empty: false
github_token: ${{ secrets.GITHUB_TOKEN }}
github_token: ${{ secrets.TGS_UPDATER }}

View File

@@ -1,102 +0,0 @@
language: generic
os: linux
dist: xenial
branches:
except:
- ___TGS3TempBranch
- ___TGSTempBranch
jobs:
include:
- name: "Run Linters"
addons:
apt:
packages:
- python3
- python3-pip
- python3-setuptools
- pcregrep
- rustc
- cargo
cache:
directories:
- $HOME/SpacemanDMM
install:
- tools/travis/install_build_tools.sh
- tools/travis/install_spaceman_dmm.sh dreamchecker
script:
- tools/travis/check_filedirs.sh tgstation.dme
- tools/travis/check_changelogs.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
- tools/travis/build_tgui.sh
- tools/travis/check_grep.sh
- python3 tools/travis/check_line_endings.py
- ~/dreamchecker
- name: "Compile All Maps"
addons:
apt:
packages:
- libstdc++6:i386
cache:
directories:
- $HOME/BYOND
install:
- tools/travis/install_byond.sh
- source $HOME/BYOND/byond/bin/byondsetup
before_script:
- tools/travis/template_dm_generator.py
script:
- tools/travis/dm.sh -DTRAVISBUILDING -DTRAVISTESTING -DALL_MAPS tgstation.dme
- name: "Compile and Run Tests"
addons:
mariadb: '10.2'
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libstdc++6:i386
- gcc-multilib
- g++-7
- g++-7-multilib
- libmariadb-client-lgpl-dev:i386
- libmariadbd-dev
cache:
directories:
- $HOME/BYOND
- $HOME/libmariadb
install:
- tools/travis/install_byond.sh
- source $HOME/BYOND/byond/bin/byondsetup
- tools/travis/install_libmariadb.sh
- tools/travis/install_rust_g.sh
before_script:
- mysql -u root -e 'CREATE DATABASE tg_travis;'
- mysql -u root tg_travis < SQL/tgstation_schema.sql
- mysql -u root -e 'CREATE DATABASE tg_travis_prefixed;'
- mysql -u root tg_travis_prefixed < SQL/tgstation_schema_prefixed.sql
- tools/travis/build_bsql.sh
script:
- tools/travis/dm.sh -DTRAVISBUILDING tgstation.dme || travis_terminate 1
- tools/travis/run_server.sh
# - name: "Generate Documentation"
# # Only run for non-PR commits to the real master branch.
# if: branch = master AND head_branch IS blank
# install:
# - tools/travis/install_spaceman_dmm.sh dmdoc
# before_script:
# # Travis checks out a hash, try to get back on a branch.
# - git checkout $TRAVIS_BRANCH || true
# script:
# - ~/dmdoc
# - touch dmdoc/.nojekyll
# deploy:
# provider: pages
# skip_cleanup: true
# local_dir: dmdoc
# token: $DMDOC_GITHUB_TOKEN
# fqdn: codedocs.tgstation13.org

View File

@@ -1,9 +1,10 @@
{
"recommendations": [
"gbasood.byond-dm-language-support",
"platymuus.dm-langclient",
"recommendations": [
"gbasood.byond-dm-language-support",
"platymuus.dm-langclient",
"EditorConfig.EditorConfig",
"arcanis.vscode-zipfs",
"dbaeumer.vscode-eslint"
]
"dbaeumer.vscode-eslint",
"kevinkyang.auto-comment-blocks"
]
}

View File

@@ -1,14 +1,12 @@
FROM tgstation/byond:513.1508 as base
FROM tgstation/byond:513.1533 as base
FROM base as build_base
FROM base as rust_g
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
git \
ca-certificates
FROM build_base as rust_g
WORKDIR /rust_g
RUN apt-get install -y --no-install-recommends \
@@ -27,36 +25,6 @@ RUN /bin/bash -c "source dependencies.sh \
&& git checkout FETCH_HEAD \
&& ~/.cargo/bin/cargo build --release
FROM build_base as bsql
WORKDIR /bsql
RUN apt-get install -y --no-install-recommends software-properties-common \
&& add-apt-repository ppa:ubuntu-toolchain-r/test \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
cmake \
make \
g++-7 \
libmariadb-client-lgpl-dev \
&& git init \
&& git remote add origin https://github.com/tgstation/BSQL
COPY dependencies.sh .
RUN /bin/bash -c "source dependencies.sh \
&& git fetch --depth 1 origin \$BSQL_VERSION" \
&& git checkout FETCH_HEAD
WORKDIR /bsql/artifacts
ENV CC=gcc-7 CXX=g++-7
RUN ln -s /usr/include/mariadb /usr/include/mysql \
&& ln -s /usr/lib/i386-linux-gnu /root/MariaDB \
&& cmake .. \
&& make
FROM base as dm_base
WORKDIR /tgstation
@@ -65,26 +33,30 @@ FROM dm_base as build
COPY . .
RUN DreamMaker -max_errors 0 tgstation.dme && tools/deploy.sh /deploy
RUN DreamMaker -max_errors 0 tgstation.dme \
&& tools/deploy.sh /deploy \
&& rm /deploy/*.dll
FROM dm_base
EXPOSE 1337
RUN apt-get update \
&& apt-get install -y --no-install-recommends software-properties-common \
&& add-apt-repository ppa:ubuntu-toolchain-r/test \
&& apt-get update \
&& apt-get upgrade -y \
&& apt-get dist-upgrade -y \
&& apt-get install -y --no-install-recommends \
libmariadb2 \
mariadb-client \
libssl1.0.0 \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /root/.byond/bin
COPY --from=rust_g /rust_g/target/release/librust_g.so /root/.byond/bin/rust_g
COPY --from=bsql /bsql/artifacts/src/BSQL/libBSQL.so ./
COPY --from=build /deploy ./
#bsql fexists memes
RUN ln -s /tgstation/libBSQL.so /root/.byond/bin/libBSQL.so
VOLUME [ "/tgstation/config", "/tgstation/data" ]
ENTRYPOINT [ "DreamDaemon", "tgstation.dmb", "-port", "1337", "-trusted", "-close", "-verbose" ]

View File

@@ -1,2 +1,9 @@
[langserver]
dreamchecker = true
[code_standards]
disallow_relative_type_definitions = true
disallow_relative_proc_definitions = true
[dmdoc]
use_typepath_names = true

View File

@@ -1,22 +1,9 @@
{
"documentation": "/tg/station server 3 configuration file",
"changelog": {
"script": "tools/ss13_genchangelog.py",
"arguments": "html/changelog.html html/changelogs",
"pip_dependancies": [
"PyYaml",
"beautifulsoup4"
]
},
"synchronize_paths": [
"html/changelog.html",
"html/changelogs/*"
],
"synchronize_paths": [],
"static_directories": [
"config",
"data"
],
"dlls": [
"libmariadb.dll"
]
"dlls": []
}

View File

@@ -18,7 +18,7 @@
/obj/item/mining_scanner,
/obj/item/flashlight/lantern,
/obj/item/card/id/mining,
/obj/item/gps/mining,
/obj/item/gps/mining/off,
/turf/open/floor/plating,
/area/ruin/powered/golem_ship)
"d" = (
@@ -32,7 +32,7 @@
/obj/item/mining_scanner,
/obj/item/flashlight/lantern,
/obj/item/card/id/mining,
/obj/item/gps/mining,
/obj/item/gps/mining/off,
/turf/open/floor/plating,
/area/ruin/powered/golem_ship)
"e" = (
@@ -71,8 +71,8 @@
/area/ruin/powered/golem_ship)
"k" = (
/obj/machinery/computer/arcade/battle{
icon_state = "arcade";
dir = 4
dir = 4;
icon_state = "arcade"
},
/turf/open/floor/mineral/titanium/purple,
/area/ruin/powered/golem_ship)
@@ -112,8 +112,8 @@
/area/ruin/powered/golem_ship)
"s" = (
/obj/machinery/computer/arcade/orion_trail{
icon_state = "arcade";
dir = 4
dir = 4;
icon_state = "arcade"
},
/turf/open/floor/mineral/titanium/purple,
/area/ruin/powered/golem_ship)

View File

@@ -111,6 +111,17 @@
/obj/structure/alien/resin/membrane,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"ax" = (
/obj/structure/alien/weeds,
/obj/effect/decal/cleanable/blood/gibs,
/obj/structure/alien/weeds/node,
/mob/living/simple_animal/hostile/alien/drone,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"ay" = (
/obj/structure/stone_tile/slab/cracked,
/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"aA" = (
/obj/structure/alien/weeds,
/obj/item/flamethrower,
@@ -130,6 +141,17 @@
},
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"aD" = (
/obj/structure/stone_tile/surrounding_tile{
dir = 1
},
/obj/structure/stone_tile/surrounding_tile,
/obj/structure/stone_tile/surrounding_tile/cracked{
dir = 4
},
/obj/structure/stone_tile/center,
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"aE" = (
/obj/structure/alien/weeds,
/obj/effect/decal/cleanable/ash,
@@ -160,6 +182,19 @@
/obj/effect/decal/cleanable/blood,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"aK" = (
/obj/structure/stone_tile/surrounding_tile/cracked{
dir = 4
},
/obj/structure/stone_tile/surrounding_tile/cracked{
dir = 8
},
/obj/structure/stone_tile/surrounding_tile/cracked{
dir = 1
},
/obj/structure/stone_tile/center/cracked,
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"aL" = (
/obj/structure/alien/weeds,
/obj/item/tank/internals/plasma,
@@ -170,6 +205,26 @@
/obj/effect/decal/cleanable/blood/xeno,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"aN" = (
/obj/structure/stone_tile/block{
dir = 8
},
/obj/structure/stone_tile{
dir = 1
},
/obj/structure/stone_tile/cracked,
/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"aO" = (
/obj/structure/alien/weeds,
/obj/effect/mob_spawn/alien/corpse/humanoid/sentinel,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"aP" = (
/obj/structure/alien/weeds,
/obj/effect/mob_spawn/alien/corpse/humanoid/hunter,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"aQ" = (
/obj/structure/alien/weeds,
/obj/structure/bed/nest,
@@ -215,13 +270,6 @@
/obj/effect/gibspawner/xeno,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"aY" = (
/obj/structure/alien/weeds,
/obj/effect/decal/cleanable/blood/gibs,
/mob/living/simple_animal/hostile/alien/drone,
/obj/structure/alien/weeds/node,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"aZ" = (
/turf/closed/indestructible/riveted/boss,
/area/ruin/unpowered/xenonest)
@@ -338,10 +386,6 @@
/obj/structure/stone_tile,
/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bm" = (
/obj/structure/stone_tile/slab/cracked,
/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bn" = (
/obj/structure/stone_tile/block{
dir = 4
@@ -365,12 +409,6 @@
/obj/structure/stone_tile/center,
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"bp" = (
/obj/structure/stone_tile/block{
dir = 4
},
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"bq" = (
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
@@ -391,33 +429,6 @@
},
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"bt" = (
/obj/structure/stone_tile/surrounding_tile{
dir = 1
},
/obj/structure/stone_tile/surrounding_tile,
/obj/structure/stone_tile/surrounding_tile/cracked{
dir = 4
},
/obj/structure/stone_tile/center,
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"bu" = (
/obj/structure/stone_tile/block/cracked{
dir = 1
},
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"bv" = (
/obj/structure/stone_tile/block{
dir = 8
},
/obj/structure/stone_tile{
dir = 1
},
/obj/structure/stone_tile/cracked,
/turf/open/indestructible/boss,
/area/ruin/unpowered/xenonest)
"bw" = (
/obj/structure/stone_tile/cracked{
dir = 4
@@ -492,19 +503,6 @@
/obj/structure/alien/weeds,
/turf/template_noop,
/area/ruin/unpowered/xenonest)
"bE" = (
/obj/structure/stone_tile/surrounding_tile/cracked{
dir = 4
},
/obj/structure/stone_tile/surrounding_tile/cracked{
dir = 8
},
/obj/structure/stone_tile/surrounding_tile/cracked{
dir = 1
},
/obj/structure/stone_tile/center/cracked,
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"dE" = (
/obj/structure/alien/weeds,
/obj/structure/bed/nest,
@@ -514,6 +512,12 @@
/obj/item/clothing/mask/facehugger/impregnated,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"gA" = (
/obj/structure/alien/weeds,
/obj/structure/bed/nest,
/obj/effect/mob_spawn/alien/corpse/humanoid/sentinel,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"iA" = (
/obj/structure/alien/weeds,
/obj/structure/bed/nest,
@@ -522,18 +526,24 @@
/obj/item/clothing/mask/facehugger/impregnated,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"kp" = (
/obj/structure/alien/weeds,
/obj/item/reagent_containers/syringe/alien,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"lG" = (
/obj/structure/alien/weeds,
/obj/effect/mob_spawn/alien/corpse/humanoid/drone,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"pE" = (
/obj/effect/mob_spawn/alien/corpse/humanoid/queen,
"lM" = (
/obj/structure/stone_tile/block{
dir = 4
},
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"nj" = (
/obj/effect/mob_spawn/alien/corpse/humanoid/praetorian,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"tY" = (
/obj/structure/alien/weeds/node,
/obj/effect/mob_spawn/alien/corpse/humanoid/hunter,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"wA" = (
@@ -546,12 +556,23 @@
/mob/living/simple_animal/hostile/alien/sentinel,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"zj" = (
/obj/structure/stone_tile/block/cracked{
dir = 1
},
/turf/open/chasm/lavaland,
/area/ruin/unpowered/xenonest)
"Dd" = (
/obj/structure/alien/weeds,
/obj/effect/decal/cleanable/blood/gibs,
/obj/item/storage/backpack/duffelbag/sec/surgery,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"Ha" = (
/obj/structure/alien/weeds,
/obj/item/reagent_containers/syringe/alien,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"JM" = (
/obj/structure/alien/weeds/node,
/obj/effect/mob_spawn/alien/corpse/humanoid/drone,
@@ -1075,7 +1096,7 @@ ac
ac
ac
bi
aY
ax
ac
ac
ac
@@ -1123,7 +1144,7 @@ an
an
ac
ac
am
gA
ac
ac
aJ
@@ -1278,10 +1299,10 @@ ac
Dd
ag
ak
ag
aP
af
ac
lG
ag
ac
ac
an
@@ -1357,7 +1378,7 @@ ab
ac
af
ag
ar
tY
lG
ag
ag
@@ -1511,7 +1532,7 @@ ac
ah
af
ah
JM
ar
Vi
ak
ag
@@ -1618,7 +1639,7 @@ ag
wA
ag
ag
pE
nj
ag
at
ag
@@ -1640,7 +1661,7 @@ ab
aZ
aZ
aZ
bm
ay
aZ
aZ
aZ
@@ -1718,7 +1739,7 @@ ah
ar
ah
ak
kp
Ha
at
ag
ag
@@ -1742,8 +1763,8 @@ ac
aZ
bc
bj
bp
bt
lM
aD
bx
aZ
ab
@@ -1794,7 +1815,7 @@ ba
bd
bk
bq
bu
zj
by
aZ
ab
@@ -1823,7 +1844,7 @@ ac
ag
ar
ag
ag
aO
ac
ab
ab
@@ -1845,7 +1866,7 @@ aZ
be
bo
bs
bE
aK
bz
aZ
ab
@@ -1896,7 +1917,7 @@ aZ
bf
bl
br
bv
aN
bA
aZ
ab

View File

@@ -2729,9 +2729,7 @@
/turf/open/floor/carpet,
/area/ruin/space/has_grav/skelter/admin)
"gx" = (
/obj/machinery/door/firedoor{
pixel_x = 0
},
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/cable/yellow{
icon_state = "1-2"
@@ -2742,9 +2740,7 @@
/turf/open/floor/plasteel/showroomfloor,
/area/ruin/space/has_grav/skelter/shields)
"gy" = (
/obj/machinery/door/firedoor{
pixel_x = 0
},
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/door/airlock/engineering{
name = "Shields"

View File

@@ -3170,7 +3170,9 @@
/turf/open/lava/smooth/lava_land_surface,
/area/lavaland/surface/outdoors)
"VY" = (
/obj/structure/closet/emcloset,
/obj/structure/closet/emcloset{
anchored = 1
},
/obj/effect/turf_decal/tile/purple{
dir = 1
},

View File

@@ -13,7 +13,7 @@
#include "map_files\BoxStation\BoxStation.dmm"
#include "map_files\LambdaStation\lambda.dmm"
#ifdef TRAVISBUILDING
#ifdef CIBUILDING
#include "templates.dm"
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -6004,12 +6004,12 @@
c_tag = "Security Checkpoint";
pixel_x = 22
},
/obj/machinery/newscaster/security_unit{
pixel_y = 32
},
/obj/structure/cable{
icon_state = "4-8"
},
/obj/machinery/airalarm{
pixel_y = 23
},
/turf/open/floor/plasteel,
/area/security/checkpoint)
"aoz" = (
@@ -32290,10 +32290,6 @@
dir = 8;
light_color = "#e8eaff"
},
/obj/machinery/airalarm{
dir = 4;
pixel_x = -22
},
/turf/open/floor/plasteel,
/area/hydroponics)
"bsl" = (
@@ -71184,6 +71180,13 @@
/obj/machinery/atmospherics/pipe/simple/yellow/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"pMW" = (
/obj/machinery/airalarm{
dir = 1;
pixel_y = -22
},
/turf/open/floor/plasteel,
/area/hydroponics)
"pZq" = (
/obj/structure/disposalpipe/sorting/mail/flip{
dir = 8;
@@ -121382,7 +121385,7 @@ amV
aqI
aqB
aGO
auy
pMW
aqB
aqI
amV

View File

@@ -49530,7 +49530,7 @@
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/stripes/line{
dir = 10
dir = 8
},
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
@@ -113323,10 +113323,6 @@
/obj/item/clothing/gloves/color/black,
/obj/item/storage/box/evidence,
/obj/item/taperecorder,
/obj/machinery/airalarm{
dir = 8;
pixel_x = 24
},
/obj/effect/turf_decal/tile/neutral{
dir = 1
},

View File

@@ -30529,9 +30529,6 @@
dir = 8
},
/obj/structure/closet/bombcloset,
/obj/machinery/airalarm{
pixel_y = 24
},
/turf/open/floor/plasteel/dark,
/area/science/mixing)
"aXC" = (
@@ -43701,10 +43698,6 @@
/obj/structure/window/reinforced{
dir = 1
},
/obj/machinery/airalarm{
dir = 4;
pixel_x = -22
},
/mob/living/simple_animal/chicken{
desc = "The arch-nemesis of Kentucky.";
name = "Popeye";
@@ -46363,9 +46356,6 @@
"bwK" = (
/obj/structure/flora/grass/jungle/b,
/obj/structure/flora/ausbushes/sparsegrass,
/obj/machinery/airalarm{
pixel_y = 22
},
/turf/open/floor/grass,
/area/chapel/main)
"bwL" = (
@@ -48132,16 +48122,6 @@
},
/turf/open/floor/plasteel/showroomfloor,
/area/security/brig)
"bzx" = (
/obj/effect/turf_decal/tile/neutral,
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
/obj/effect/turf_decal/tile/neutral{
dir = 4
},
/turf/closed/wall,
/area/crew_quarters/locker)
"bzy" = (
/obj/machinery/light/small{
dir = 8
@@ -58156,10 +58136,6 @@
icon_state = "plant-02";
pixel_y = 3
},
/obj/machinery/airalarm{
dir = 4;
pixel_x = -22
},
/obj/machinery/camera{
c_tag = "Prison Wing Cells";
dir = 4;
@@ -61358,7 +61334,7 @@
dir = 10
},
/turf/open/floor/plasteel,
/area/space)
/area/security/warden)
"bUs" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/command/glass{
@@ -67210,10 +67186,6 @@
/obj/structure/cable{
icon_state = "1-4"
},
/obj/machinery/airalarm{
dir = 1;
pixel_y = -22
},
/turf/open/floor/plasteel,
/area/security/main)
"cdU" = (
@@ -71327,9 +71299,9 @@
icon_gib = "magicarp_gib";
icon_living = "magicarp";
icon_state = "magicarp";
maxHealth = 200;
max_co2 = 5;
max_tox = 2;
maxHealth = 200;
melee_damage_lower = 15;
melee_damage_upper = 20;
min_oxy = 5;
@@ -83281,10 +83253,6 @@
/obj/machinery/atmospherics/pipe/simple/yellow/visible{
dir = 5
},
/obj/machinery/airalarm{
dir = 4;
pixel_x = -23
},
/obj/machinery/camera{
c_tag = "Atmospherics Port Tanks";
dir = 4;
@@ -108992,7 +108960,7 @@ bss
btV
aEu
bxW
bzx
bIV
bKq
bKq
bKq

View File

@@ -1111,10 +1111,6 @@
/turf/open/floor/plasteel,
/area/security/prison)
"acx" = (
/obj/machinery/airalarm{
dir = 8;
pixel_x = 24
},
/obj/machinery/cryopod{
dir = 8
},
@@ -40497,10 +40493,9 @@
/area/maintenance/port)
"bBr" = (
/obj/machinery/airalarm{
dir = 4;
pixel_x = -23
dir = 1;
pixel_y = -22
},
/obj/structure/displaycase/trophy,
/turf/open/floor/wood,
/area/library)
"bBs" = (
@@ -45866,10 +45861,6 @@
/area/library)
"bML" = (
/obj/machinery/light/small,
/obj/machinery/airalarm{
dir = 1;
pixel_y = -22
},
/turf/open/floor/wood,
/area/library)
"bMM" = (
@@ -59581,6 +59572,10 @@
/obj/structure/chair{
dir = 1
},
/obj/machinery/airalarm{
dir = 4;
pixel_x = -23
},
/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"coz" = (
@@ -60135,9 +60130,6 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/obj/structure/disposalpipe/junction/flip{
dir = 8
},
@@ -60145,6 +60137,9 @@
/obj/effect/turf_decal/tile/purple{
dir = 4
},
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 1
},
/turf/open/floor/plasteel/white,
/area/science/research)
"cpx" = (
@@ -60947,9 +60942,6 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 1
},
/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/tile/purple,
/obj/effect/turf_decal/tile/purple{
@@ -60958,6 +60950,10 @@
/obj/effect/turf_decal/tile/purple{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/turf/open/floor/plasteel/white,
/area/science/research)
"cqP" = (
@@ -61465,7 +61461,6 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/door/firedoor,
/obj/structure/disposalpipe/segment,
/obj/machinery/door/airlock/research{
@@ -61477,6 +61472,7 @@
name = "biohazard containment shutters"
},
/obj/effect/turf_decal/delivery,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/science/storage)
"crU" = (
@@ -61595,10 +61591,6 @@
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"csl" = (
/obj/machinery/airalarm{
dir = 1;
pixel_y = -22
},
/obj/structure/window/reinforced{
dir = 8
},
@@ -62156,11 +62148,11 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/stripes/line{
dir = 9
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/science/storage)
"cth" = (
@@ -62531,24 +62523,21 @@
/obj/structure/cable/yellow{
icon_state = "1-4"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 5
},
/obj/structure/disposalpipe/segment{
dir = 5
},
/obj/effect/turf_decal/stripes/line{
dir = 8
},
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 1
},
/turf/open/floor/plasteel,
/area/science/storage)
"ctY" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 10
},
/obj/structure/chair/stool,
/obj/structure/disposalpipe/segment{
dir = 10
@@ -62568,10 +62557,6 @@
/area/science/storage)
"cua" = (
/obj/machinery/portable_atmospherics/canister/oxygen,
/obj/machinery/airalarm{
dir = 8;
pixel_x = 24
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
/area/science/storage)
@@ -63127,7 +63112,6 @@
/turf/open/floor/plasteel,
/area/science/storage)
"cuU" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -63668,12 +63652,12 @@
/turf/open/floor/plasteel,
/area/science/storage)
"cvW" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/disposalpipe/segment,
/obj/effect/landmark/blobstart,
/obj/effect/turf_decal/stripes/line{
dir = 4
},
/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
/turf/open/floor/plasteel,
/area/science/storage)
"cvX" = (
@@ -68931,13 +68915,13 @@
pixel_x = -25;
pixel_y = -5
},
/obj/machinery/airalarm{
dir = 1;
pixel_y = -22
},
/obj/effect/turf_decal/stripes/corner{
dir = 4
},
/obj/machinery/airalarm/unlocked{
dir = 1;
pixel_y = -22
},
/turf/open/floor/plasteel/white,
/area/science/mixing)
"cGm" = (
@@ -102705,7 +102689,7 @@ bue
bwa
bxU
bzD
bBr
dmD
bSx
bEw
bzE
@@ -103740,7 +103724,7 @@ bGs
bHS
bzE
bLk
bzE
bBr
bue
bPS
bPR
@@ -117641,7 +117625,7 @@ cmQ
cok
cpy
cqQ
cgq
crR
cti
ctZ
cuV

View File

@@ -4924,11 +4924,11 @@
/obj/effect/turf_decal/stripes/end{
dir = 1
},
/obj/item/gun/energy/e_gun/hos,
/obj/effect/turf_decal/tile/neutral,
/obj/effect/turf_decal/tile/neutral{
dir = 4
},
/obj/item/gun/energy/e_gun/hos,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/captain/private)
"ahI" = (
@@ -40544,6 +40544,9 @@
name = "Starboard Quater Maintenance APC";
pixel_y = -26
},
/obj/structure/cable/white{
icon_state = "0-8"
},
/turf/open/floor/plating{
icon_state = "panelscorched"
},

View File

@@ -2337,9 +2337,12 @@
/turf/open/floor/plasteel/dark,
/area/security/prison)
"afJ" = (
/obj/effect/landmark/carpspawn,
/turf/open/space/basic,
/area/space/nearstation)
/obj/effect/turf_decal/tile/neutral,
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 8
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
"afK" = (
/obj/machinery/atmospherics/components/unary/tank/air{
dir = 1
@@ -16527,6 +16530,9 @@
/obj/structure/cable{
icon_state = "4-8"
},
/obj/machinery/airalarm{
pixel_y = 22
},
/turf/open/floor/plasteel,
/area/quartermaster/warehouse)
"aMr" = (
@@ -20027,9 +20033,7 @@
/obj/structure/cable{
icon_state = "1-8"
},
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 4
},
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/bar)
"aUQ" = (
@@ -20044,6 +20048,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 10
},
/turf/open/floor/plasteel/dark,
/area/hydroponics)
"aUR" = (
@@ -20485,8 +20492,16 @@
/turf/closed/wall,
/area/janitor)
"aVT" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall,
/obj/machinery/door/firedoor,
/obj/machinery/door/poddoor/shutters{
id = "jangarage";
name = "Custodial Closet Shutters"
},
/obj/effect/turf_decal/delivery,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel,
/area/janitor)
"aVU" = (
/obj/machinery/door/window/eastright{
@@ -20510,6 +20525,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/dark,
/area/janitor)
"aVV" = (
@@ -20892,9 +20908,6 @@
/obj/machinery/camera{
c_tag = "Custodial Quarters"
},
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 1
},
/obj/machinery/light/small{
dir = 1
},
@@ -20915,6 +20928,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 4
},
/turf/open/floor/plasteel/dark,
/area/janitor)
"aWO" = (
@@ -20934,6 +20950,9 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 9
},
/turf/open/floor/plasteel/dark,
/area/janitor)
"aWP" = (
@@ -23004,9 +23023,6 @@
/turf/open/floor/plasteel,
/area/hallway/primary/central)
"baW" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 8
},
/obj/machinery/button/door{
id = "jangarage";
name = "Custodial Closet Shutters Control";
@@ -23014,14 +23030,12 @@
req_access_txt = "26"
},
/obj/effect/turf_decal/tile/neutral,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/hallway/primary/central)
"baX" = (
/obj/vehicle/ridden/janicart,
/obj/structure/disposalpipe/segment,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/obj/machinery/light{
dir = 8
},
@@ -23034,6 +23048,9 @@
/obj/structure/cable{
icon_state = "2-4"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 6
},
/turf/open/floor/plasteel,
/area/janitor)
"baY" = (
@@ -23398,6 +23415,9 @@
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 9
},
/turf/open/floor/plasteel,
/area/janitor)
"bbY" = (
@@ -31173,17 +31193,26 @@
"bup" = (
/obj/machinery/rnd/destructive_analyzer,
/obj/effect/turf_decal/delivery,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel,
/area/science/lab)
"buq" = (
/obj/structure/disposalpipe/segment,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/effect/turf_decal/bot,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel,
/area/science/lab)
"bur" = (
/obj/effect/turf_decal/delivery,
/obj/machinery/rnd/production/protolathe/department/science,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel,
/area/science/lab)
"bus" = (
@@ -31202,6 +31231,9 @@
/obj/machinery/light{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 10
},
/turf/open/floor/plasteel/white,
/area/science/lab)
"but" = (
@@ -31664,6 +31696,7 @@
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel/white,
/area/science/lab)
"bvA" = (
@@ -32372,6 +32405,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel/white,
/area/science/lab)
"bxh" = (
@@ -33056,12 +33090,6 @@
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"byD" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 6
},
/obj/structure/cable{
icon_state = "2-4"
},
/obj/machinery/door/airlock/research{
name = "R&D Lab";
req_one_access_txt = "7;29;30"
@@ -33070,6 +33098,12 @@
/obj/structure/disposalpipe/segment{
dir = 6
},
/obj/structure/cable{
icon_state = "4-8"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/turf/open/floor/plasteel,
/area/science/lab)
"byE" = (
@@ -33091,7 +33125,6 @@
/turf/open/floor/plasteel/white,
/area/science/lab)
"byG" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/obj/structure/cable{
icon_state = "1-2"
},
@@ -33919,10 +33952,6 @@
/area/hallway/primary/aft)
"bAm" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall,
/area/hallway/primary/aft)
"bAo" = (
@@ -33952,7 +33981,6 @@
/obj/structure/cable{
icon_state = "1-4"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/tile/purple{
dir = 1
},
@@ -34404,17 +34432,14 @@
name = "RD Office APC";
pixel_x = -25
},
/obj/structure/cable{
icon_state = "0-4"
},
/obj/effect/turf_decal/tile/purple{
dir = 1
},
/obj/effect/turf_decal/tile/purple{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/hor)
@@ -34425,8 +34450,8 @@
/obj/structure/disposalpipe/segment{
dir = 5
},
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 4
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 6
},
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/hor)
@@ -34434,6 +34459,9 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/hor)
"bBt" = (
@@ -34441,6 +34469,9 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/hor)
"bBu" = (
@@ -34478,6 +34509,9 @@
/obj/effect/turf_decal/tile/purple{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 9
},
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/hor)
"bBw" = (
@@ -35240,6 +35274,7 @@
/obj/structure/cable{
icon_state = "0-8"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plating,
/area/crew_quarters/heads/hor)
"bCK" = (
@@ -44248,9 +44283,11 @@
/turf/open/floor/engine/co2,
/area/engine/atmos)
"bWh" = (
/obj/effect/turf_decal/sand,
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 8
},
/turf/open/floor/plasteel,
/area/chapel/office)
/area/hallway/primary/aft)
"bWi" = (
/obj/structure/flora/ausbushes/leafybush,
/obj/structure/flora/ausbushes/reedbush,
@@ -47597,6 +47634,9 @@
pixel_x = -25;
specialfunctions = 4
},
/obj/machinery/airalarm{
pixel_y = 22
},
/turf/open/floor/plasteel/grimy,
/area/chapel/main/monastery)
"cgM" = (
@@ -47945,6 +47985,9 @@
pixel_x = -25;
specialfunctions = 4
},
/obj/machinery/airalarm{
pixel_y = 22
},
/turf/open/floor/plasteel/grimy,
/area/chapel/main/monastery)
"cip" = (
@@ -51432,6 +51475,10 @@
name = "Coffin Storage";
req_one_access_txt = "22"
},
/obj/machinery/airalarm{
dir = 8;
pixel_x = 24
},
/turf/open/floor/plasteel/dark,
/area/chapel/main/monastery)
"cvu" = (
@@ -52824,6 +52871,9 @@
/turf/closed/wall/r_wall,
/area/science/lab)
"cCt" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 1
},
/turf/open/floor/plasteel/white,
/area/science/lab)
"cCB" = (
@@ -53058,6 +53108,9 @@
freq = 1400;
location = "Research Division"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel/dark,
/area/science/lab)
"cXW" = (
@@ -53151,10 +53204,6 @@
/area/maintenance/department/security/brig)
"dhz" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/chair{
dir = 8;
name = "Defense"
@@ -53163,9 +53212,6 @@
/obj/effect/turf_decal/tile/purple{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"dir" = (
@@ -53960,11 +54006,11 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/structure/cable{
icon_state = "4-8"
},
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 1
dir = 4
},
/obj/structure/cable{
icon_state = "1-8"
},
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
@@ -55488,6 +55534,12 @@
/obj/effect/turf_decal/tile/purple{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 6
},
/obj/structure/cable{
icon_state = "2-4"
},
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"ioj" = (
@@ -55591,6 +55643,9 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"iyg" = (
@@ -56345,9 +56400,13 @@
/turf/open/floor/plasteel/white,
/area/science/mixing)
"koz" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
/obj/effect/turf_decal/tile/purple,
/obj/effect/turf_decal/tile/purple{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"kpK" = (
@@ -56634,10 +56693,14 @@
/turf/open/floor/plasteel/dark,
/area/science/xenobiology)
"kSb" = (
/obj/structure/lattice,
/obj/structure/grille,
/turf/open/space/basic,
/area/space)
/obj/structure/chair/office/light{
dir = 8
},
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 1
},
/turf/open/floor/plasteel/white,
/area/science/lab)
"kSF" = (
/obj/structure/cable{
icon_state = "1-4"
@@ -56711,6 +56774,10 @@
/obj/effect/turf_decal/tile/purple{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
"lcU" = (
@@ -57121,6 +57188,7 @@
/obj/effect/turf_decal/tile/purple{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel/white,
/area/science/lab)
"meF" = (
@@ -57128,8 +57196,9 @@
/turf/closed/wall/r_wall,
/area/engine/supermatter)
"mfC" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
@@ -59343,6 +59412,7 @@
/area/hallway/secondary/exit/departure_lounge)
"qVk" = (
/obj/machinery/door/poddoor/incinerator_atmos_aux,
/obj/structure/lattice/catwalk,
/turf/open/space/basic,
/area/maintenance/disposal/incinerator)
"qVP" = (
@@ -59377,6 +59447,10 @@
/obj/effect/turf_decal/tile/yellow{
dir = 8
},
/obj/machinery/airalarm{
dir = 8;
pixel_x = 23
},
/turf/open/floor/plasteel,
/area/construction/mining/aux_base)
"qXq" = (
@@ -60493,6 +60567,9 @@
id = "research_shutters_2";
name = "research shutters"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/open/floor/plasteel,
/area/science/lab)
"tLP" = (
@@ -60815,12 +60892,6 @@
/obj/structure/disposalpipe/segment{
dir = 9
},
/obj/structure/cable{
icon_state = "1-8"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 9
},
/obj/structure/chair{
dir = 8;
name = "Defense"
@@ -61500,12 +61571,6 @@
},
/turf/open/floor/plasteel,
/area/science/xenobiology)
"wfG" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
/turf/closed/wall/r_wall,
/area/crew_quarters/heads/hor)
"wfO" = (
/mob/living/simple_animal/hostile/retaliate/poison/snake,
/turf/open/floor/plating,
@@ -76969,7 +77034,7 @@ aaa
bOv
bNs
bNs
bWh
bQg
bQg
bQg
bQg
@@ -84176,7 +84241,7 @@ bIZ
cbb
bDi
ccO
bIZ
bva
cjm
cjm
xgh
@@ -84436,8 +84501,8 @@ bva
bva
aht
aht
kSb
kSb
fon
fon
aht
aht
mau
@@ -86691,7 +86756,7 @@ aXL
aYL
aZN
baW
aKI
afJ
aKI
beb
aKI
@@ -86947,8 +87012,8 @@ aVS
aXM
aVS
aVS
aXM
bbW
aVS
aVT
bbW
aVS
aVS
@@ -87149,7 +87214,7 @@ aaa
aaa
aaa
aaa
afJ
cFB
aby
aaa
agQ
@@ -87456,7 +87521,7 @@ aRJ
aSz
aSz
aUP
aVT
aVS
aWN
aXO
aYM
@@ -89468,7 +89533,7 @@ aaa
aaa
aaa
aaa
afJ
cFB
aaa
aaa
abI
@@ -94932,12 +94997,12 @@ jcT
xje
tTl
tTl
tTl
bWh
gkS
tTl
tTl
tTl
koz
tTl
dgg
phJ
phJ
@@ -95189,7 +95254,7 @@ bjm
mhn
cqi
cqi
cqi
koz
cqi
cqi
imE
@@ -95708,7 +95773,7 @@ duF
bxa
byE
bBp
wfG
bBp
bBp
bBp
bBp
@@ -95961,7 +96026,7 @@ cCl
brq
byF
cCt
byF
kSb
bxc
nIU
bAo

View File

@@ -1,15 +0,0 @@
version: '{build}'
skip_branch_with_pr: true
shallow_clone: true
branches:
except:
- ___TGS3TempBranch
- ___TGSTempBranch
cache:
- C:\byond\ -> dependencies.sh
build_script:
- ps: tools/appveyor/build.ps1
- ps: "$deployPath = $env:APPVEYOR_BUILD_FOLDER + '/deploy'; bash tools/deploy.sh $deployPath"
- ps: "[System.IO.Compression.ZipFile]::CreateFromDirectory($env:APPVEYOR_BUILD_FOLDER + '/deploy', $env:APPVEYOR_BUILD_FOLDER + '/deploy.zip')"
artifacts:
- path: deploy.zip

View File

@@ -22,49 +22,45 @@
#define START_PROCESSING(Processor, Datum) if (!(Datum.datum_flags & DF_ISPROCESSING)) {Datum.datum_flags |= DF_ISPROCESSING;Processor.processing += Datum}
#define STOP_PROCESSING(Processor, Datum) Datum.datum_flags &= ~DF_ISPROCESSING;Processor.processing -= Datum;Processor.currentrun -= Datum
//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
//! SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
//subsystem does not initialize.
#define SS_NO_INIT (1<<0)
/// subsystem does not initialize.
#define SS_NO_INIT 1
//subsystem does not fire.
// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
// (Requires a MC restart to change)
#define SS_NO_FIRE (1<<1)
/** subsystem does not fire. */
/// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
/// (Requires a MC restart to change)
#define SS_NO_FIRE 2
//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick)
// SS_BACKGROUND has its own priority bracket
#define SS_BACKGROUND (1<<2)
/** Subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) */
/// SS_BACKGROUND has its own priority bracket, this overrides SS_TICKER's priority bump
#define SS_BACKGROUND 4
//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
#define SS_NO_TICK_CHECK (1<<3)
/// subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
#define SS_NO_TICK_CHECK 8
//Treat wait as a tick count, not DS, run every wait ticks.
// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems)
// (implies all runlevels because of how it works)
// (overrides SS_BACKGROUND)
// This is designed for basically anything that works as a mini-mc (like SStimer)
#define SS_TICKER (1<<4)
/** Treat wait as a tick count, not DS, run every wait ticks. */
/// (also forces it to run first in the tick (unless SS_BACKGROUND))
/// (implies all runlevels because of how it works)
/// This is designed for basically anything that works as a mini-mc (like SStimer)
#define SS_TICKER 16
//keep the subsystem's timing on point by firing early if it fired late last fire because of lag
// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
#define SS_KEEP_TIMING (1<<5)
/** keep the subsystem's timing on point by firing early if it fired late last fire because of lag */
/// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
#define SS_KEEP_TIMING 32
//Calculate its next fire after its fired.
// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
// This flag overrides SS_KEEP_TIMING
#define SS_POST_FIRE_TIMING (1<<6)
/** Calculate its next fire after its fired. */
/// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
/// This flag overrides SS_KEEP_TIMING
#define SS_POST_FIRE_TIMING 64
/// Show in stat() by default even if SS_NO_FIRE
#define SS_ALWAYS_SHOW_STAT (1<<7)
//SUBSYSTEM STATES
#define SS_IDLE 0 //aint doing shit.
#define SS_QUEUED 1 //queued to run
#define SS_RUNNING 2 //actively running
#define SS_PAUSED 3 //paused by mc_tick_check
#define SS_SLEEPING 4 //fire() slept.
#define SS_PAUSING 5 //in the middle of pausing
//! SUBSYSTEM STATES
#define SS_IDLE 0 /// ain't doing shit.
#define SS_QUEUED 1 /// queued to run
#define SS_RUNNING 2 /// actively running
#define SS_PAUSED 3 /// paused by mc_tick_check
#define SS_SLEEPING 4 /// fire() slept.
#define SS_PAUSING 5 /// in the middle of pausing
#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\
/datum/controller/subsystem/##X/New(){\

View File

@@ -1 +1,38 @@
#define EXTOOLS (world.system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so")
// _extools_api.dm - DM API for extools extension library
// (blatently stolen from rust_g)
//
// To configure, create a `extools.config.dm` and set what you care about from
// the following options:
//
// #define EXTOOLS "path/to/extools"
// Override the .dll/.so detection logic with a fixed path or with detection
// logic of your own.
#ifndef EXTOOLS
// Default automatic EXTOOLS detection.
// On Windows, looks in the standard places for `byond-extools.dll`.
// On Linux, looks in the standard places for`libbyond-extools.so`.
/* This comment bypasses grep checks */ /var/__extools
/proc/__detect_extools()
if (world.system_type == UNIX)
if (fexists("./libbyond-extools.so"))
// No need for LD_LIBRARY_PATH badness.
return __extools = "./libbyond-extools.so"
else
// It's not in the current directory, so try others
return __extools = "libbyond-extools.so"
else
return __extools = "byond-extools.dll"
#define EXTOOLS (__extools || __detect_extools())
#endif
#ifndef UNIT_TESTS // use default logging as extools is broken on travis
#define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined
#endif
/proc/extools_log_write()
/proc/extools_finalize_logging()

View File

@@ -163,5 +163,19 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
else if(!HAS_TRAIT(x, TRAIT_KEEP_TOGETHER))\
x.appearance_flags &= ~KEEP_TOGETHER
//dir macros
///Returns true if the dir is diagonal, false otherwise
#define ISDIAGONALDIR(d) (d&(d-1))
///True if the dir is north or south, false therwise
#define NSCOMPONENT(d) (d&(NORTH|SOUTH))
///True if the dir is east/west, false otherwise
#define EWCOMPONENT(d) (d&(EAST|WEST))
///Flips the dir for north/south directions
#define NSDIRFLIP(d) (d^(NORTH|SOUTH))
///Flips the dir for east/west directions
#define EWDIRFLIP(d) (d^(EAST|WEST))
///Turns the dir by 180 degrees
#define DIRFLIP(d) turn(d, 180)
/// 33554431 (2^24 - 1) is the maximum value our bitflags can reach.
#define MAX_BITFLAG_DIGITS 8

View File

@@ -91,3 +91,6 @@
#define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu
#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you
#define STICKYBAN_DB_CACHE_TIME 10 SECONDS
#define STICKYBAN_ROGUE_CHECK_TIME 5

View File

@@ -69,6 +69,9 @@
#define LINGBLOOD_EXPLOSION_THRESHOLD (LINGBLOOD_DETECTION_THRESHOLD * LINGBLOOD_EXPLOSION_MULT) //Hey, important to note here: the explosion threshold is explicitly more than, rather than more than or equal to. This stops a single loud ability from triggering the explosion threshold.
///Heretics --
GLOBAL_LIST_EMPTY(living_heart_cache) //A list of all living hearts in existance, for us to iterate through.
#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
#define IS_HERETIC_MONSTER(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic_monster))

View File

@@ -6,9 +6,16 @@
#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
/// Signifies that this proc is used to handle signals.
/// Every proc you pass to RegisterSignal must have this.
#define SIGNAL_HANDLER SHOULD_NOT_SLEEP(TRUE)
/// Signifies that this proc is used to handle signals, but also sleeps.
/// Do not use this for new work.
#define SIGNAL_HANDLER_DOES_SLEEP
/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
#define AddElement(arguments...) _AddElement(list(##arguments))
/// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments
#define RemoveElement(arguments...) _RemoveElement(list(##arguments))

View File

@@ -541,6 +541,9 @@
#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt" //from turf AltClickOn(): (/mob)
#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl" //from monkey CtrlClickOn(): (/mob)
// /datum/element/ventcrawling signals
#define COMSIG_HANDLE_VENTCRAWL "handle_ventcrawl" //when atom with ventcrawling element attempts to ventcrawl
#define COMSIG_CHECK_VENTCRAWL "check_ventcrawl" //to check an atom's ventcrawling element tier (if applicable)
// twitch plays
/// Returns direction: (wipe_votes)
#define COMSIG_TWITCH_PLAYS_MOVEMENT_DATA "twitch_plays_movement_data"

View File

@@ -72,9 +72,11 @@
#define LOADOUT_LIMBS list(LOADOUT_LIMB_NORMAL,LOADOUT_LIMB_PROSTHETIC,LOADOUT_LIMB_AMPUTATED) //you can amputate your legs/arms though
//loadout saving/loading specific defines
#define MAXIMUM_LOADOUT_SAVES 5
#define LOADOUT_ITEM "loadout_item"
#define LOADOUT_COLOR "loadout_color"
#define MAXIMUM_LOADOUT_SAVES 5
#define LOADOUT_ITEM "loadout_item"
#define LOADOUT_COLOR "loadout_color"
#define LOADOUT_CUSTOM_NAME "loadout_custom_name"
#define LOADOUT_CUSTOM_DESCRIPTION "loadout_custom_description"
//loadout item flags
#define LOADOUT_CAN_NAME (1<<0) //renaming items

View File

@@ -0,0 +1,26 @@
/// The minimum for glide_size to be clamped to.
#define MIN_GLIDE_SIZE 1
/// The maximum for glide_size to be clamped to.
/// This shouldn't be higher than the icon size, and generally you shouldn't be changing this, but it's here just in case.
#define MAX_GLIDE_SIZE 32
/// Compensating for time dialation
GLOBAL_VAR_INIT(glide_size_multiplier, 1.0)
///Broken down, here's what this does:
/// divides the world icon_size (32) by delay divided by ticklag to get the number of pixels something should be moving each tick.
/// The division result is given a min value of 1 to prevent obscenely slow glide sizes from being set
/// Then that's multiplied by the global glide size multiplier. 1.25 by default feels pretty close to spot on. This is just to try to get byond to behave.
/// The whole result is then clamped to within the range above.
/// Not very readable but it works
#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((32 / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE))
/// Enables smooth movement
// #define SMOOTH_MOVEMENT
/// Set appearance flags in vars
#ifdef SMOOTH_MOVEMENT
#define SET_APPEARANCE_FLAGS(_flags) appearance_flags = (_flags | LONG_GLIDE)
#else
#define SET_APPEARANCE_FLAGS(_flags) appearance_flags = _flags
#endif

View File

@@ -1,19 +1,76 @@
// rust_g.dm - DM API for rust_g extension library
#define RUST_G "rust_g"
//
// To configure, create a `rust_g.config.dm` and set what you care about from
// the following options:
//
// #define RUST_G "path/to/rust_g"
// Override the .dll/.so detection logic with a fixed path or with detection
// logic of your own.
//
// #define RUSTG_OVERRIDE_BUILTINS
// Enable replacement rust-g functions for certain builtins. Off by default.
#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB"
#define RUSTG_JOB_ERROR "JOB PANICKED"
#ifndef RUST_G
// Default automatic RUST_G detection.
// On Windows, looks in the standard places for `rust_g.dll`.
// On Linux, looks in `.`, `$LD_LIBRARY_PATH`, and `~/.byond/bin` for either of
// `librust_g.so` (preferred) or `rust_g` (old).
/* This comment bypasses grep checks */ /var/__rust_g
/proc/__detect_rust_g()
if (world.system_type == UNIX)
if (fexists("./librust_g.so"))
// No need for LD_LIBRARY_PATH badness.
return __rust_g = "./librust_g.so"
else if (fexists("./rust_g"))
// Old dumb filename.
return __rust_g = "./rust_g"
else if (fexists("[world.GetConfig("env", "HOME")]/.byond/bin/rust_g"))
// Old dumb filename in `~/.byond/bin`.
return __rust_g = "rust_g"
else
// It's not in the current directory, so try others
return __rust_g = "librust_g.so"
else
return __rust_g = "rust_g"
#define RUST_G (__rust_g || __detect_rust_g())
#endif
/**
* This proc generates a cellular automata noise grid which can be used in procedural generation methods.
*
* Returns a single string that goes row by row, with values of 1 representing an alive cell, and a value of 0 representing a dead cell.
*
* Arguments:
* * percentage: The chance of a turf starting closed
* * smoothing_iterations: The amount of iterations the cellular automata simulates before returning the results
* * birth_limit: If the number of neighboring cells is higher than this amount, a cell is born
* * death_limit: If the number of neighboring cells is lower than this amount, a cell dies
* * width: The width of the grid.
* * height: The height of the grid.
*/
#define rustg_cnoise_generate(percentage, smoothing_iterations, birth_limit, death_limit, width, height) \
call(RUST_G, "cnoise_generate")(percentage, smoothing_iterations, birth_limit, death_limit, width, height)
#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname)
#define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data)
#define rustg_dmi_resize_png(path, width, height, resizetype) call(RUST_G, "dmi_resize_png")(path, width, height, resizetype)
#define rustg_file_read(fname) call(RUST_G, "file_read")(fname)
#define rustg_file_exists(fname) call(RUST_G, "file_exists")(fname)
#define rustg_file_write(text, fname) call(RUST_G, "file_write")(text, fname)
#define rustg_file_append(text, fname) call(RUST_G, "file_append")(text, fname)
#ifdef RUSTG_OVERRIDE_BUILTINS
#define file2text(fname) rustg_file_read("[fname]")
#define text2file(text, fname) rustg_file_append(text, "[fname]")
#endif
#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev)
#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev)
#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format)
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
#define RUSTG_HTTP_METHOD_GET "get"
#define RUSTG_HTTP_METHOD_PUT "put"
#define RUSTG_HTTP_METHOD_DELETE "delete"
@@ -23,3 +80,22 @@
#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_check_request(req_id) call(RUST_G, "http_check_request")(req_id)
#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB"
#define RUSTG_JOB_ERROR "JOB PANICKED"
#define rustg_json_is_valid(text) (call(RUST_G, "json_is_valid")(text) == "true")
#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format)
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y)
#define rustg_sql_connect_pool(options) call(RUST_G, "sql_connect_pool")(options)
#define rustg_sql_query_async(handle, query, params) call(RUST_G, "sql_query_async")(handle, query, params)
#define rustg_sql_query_blocking(handle, query, params) call(RUST_G, "sql_query_blocking")(handle, query, params)
#define rustg_sql_connected(handle) call(RUST_G, "sql_connected")(handle)
#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]")

View File

@@ -3,6 +3,7 @@
#define CHANNEL_ADMIN 1023
#define CHANNEL_VOX 1022
#define CHANNEL_JUKEBOX 1021
#define CHANNEL_JUKEBOX_START 1016 //The gap between this and CHANNEL_JUKEBOX determines the amount of free jukebox channels. This currently allows 6 jukebox channels to exist.
#define CHANNEL_JUSTICAR_ARK 1015
#define CHANNEL_HEARTBEAT 1014 //sound channel for heartbeats
@@ -15,6 +16,17 @@
#define CHANNEL_DIGEST 1009
#define CHANNEL_PREYLOOP 1008
///Default range of a sound.
#define SOUND_RANGE 17
///default extra range for sounds considered to be quieter
#define SHORT_RANGE_SOUND_EXTRARANGE -9
///The range deducted from sound range for things that are considered silent / sneaky
#define SILENCED_SOUND_EXTRARANGE -11
///Percentage of sound's range where no falloff is applied
#define SOUND_DEFAULT_FALLOFF_DISTANCE 1 //For a normal sound this would be 1 tile of no falloff
///The default exponent of sound falloff
#define SOUND_FALLOFF_EXPONENT 6
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
//KEEP IT UPDATED
@@ -23,6 +35,7 @@
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
#define SOUND_MINIMUM_PRESSURE 10
/// remove
#define FALLOFF_SOUNDS 1
@@ -53,7 +66,8 @@
#define MINING list('sound/ambience/ambimine.ogg', 'sound/ambience/ambicave.ogg', 'sound/ambience/ambiruin.ogg',\
'sound/ambience/ambiruin2.ogg', 'sound/ambience/ambiruin3.ogg', 'sound/ambience/ambiruin4.ogg',\
'sound/ambience/ambiruin5.ogg', 'sound/ambience/ambiruin6.ogg', 'sound/ambience/ambiruin7.ogg',\
'sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg', 'sound/ambience/ambimaint1.ogg', 'sound/ambience/ambilava.ogg')
'sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg', 'sound/ambience/ambimaint1.ogg',\
'sound/ambience/ambilava.ogg')
#define MEDICAL list('sound/ambience/ambinice.ogg')
@@ -80,3 +94,55 @@
'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\
'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\
'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg')
#define INTERACTION_SOUND_RANGE_MODIFIER -3
#define EQUIP_SOUND_VOLUME 30
#define PICKUP_SOUND_VOLUME 15
#define DROP_SOUND_VOLUME 20
#define YEET_SOUND_VOLUME 90
//default byond sound environments
#define SOUND_ENVIRONMENT_NONE -1
#define SOUND_ENVIRONMENT_GENERIC 0
#define SOUND_ENVIRONMENT_PADDED_CELL 1
#define SOUND_ENVIRONMENT_ROOM 2
#define SOUND_ENVIRONMENT_BATHROOM 3
#define SOUND_ENVIRONMENT_LIVINGROOM 4
#define SOUND_ENVIRONMENT_STONEROOM 5
#define SOUND_ENVIRONMENT_AUDITORIUM 6
#define SOUND_ENVIRONMENT_CONCERT_HALL 7
#define SOUND_ENVIRONMENT_CAVE 8
#define SOUND_ENVIRONMENT_ARENA 9
#define SOUND_ENVIRONMENT_HANGAR 10
#define SOUND_ENVIRONMENT_CARPETED_HALLWAY 11
#define SOUND_ENVIRONMENT_HALLWAY 12
#define SOUND_ENVIRONMENT_STONE_CORRIDOR 13
#define SOUND_ENVIRONMENT_ALLEY 14
#define SOUND_ENVIRONMENT_FOREST 15
#define SOUND_ENVIRONMENT_CITY 16
#define SOUND_ENVIRONMENT_MOUNTAINS 17
#define SOUND_ENVIRONMENT_QUARRY 18
#define SOUND_ENVIRONMENT_PLAIN 19
#define SOUND_ENVIRONMENT_PARKING_LOT 20
#define SOUND_ENVIRONMENT_SEWER_PIPE 21
#define SOUND_ENVIRONMENT_UNDERWATER 22
#define SOUND_ENVIRONMENT_DRUGGED 23
#define SOUND_ENVIRONMENT_DIZZY 24
#define SOUND_ENVIRONMENT_PSYCHOTIC 25
//If we ever make custom ones add them here
//"sound areas": easy way of keeping different types of areas consistent.
#define SOUND_AREA_STANDARD_STATION SOUND_ENVIRONMENT_PARKING_LOT
#define SOUND_AREA_LARGE_ENCLOSED SOUND_ENVIRONMENT_QUARRY
#define SOUND_AREA_SMALL_ENCLOSED SOUND_ENVIRONMENT_BATHROOM
#define SOUND_AREA_TUNNEL_ENCLOSED SOUND_ENVIRONMENT_STONEROOM
#define SOUND_AREA_LARGE_SOFTFLOOR SOUND_ENVIRONMENT_CARPETED_HALLWAY
#define SOUND_AREA_MEDIUM_SOFTFLOOR SOUND_ENVIRONMENT_LIVINGROOM
#define SOUND_AREA_SMALL_SOFTFLOOR SOUND_ENVIRONMENT_ROOM
#define SOUND_AREA_ASTEROID SOUND_ENVIRONMENT_CAVE
#define SOUND_AREA_SPACE SOUND_ENVIRONMENT_UNDERWATER
#define SOUND_AREA_LAVALAND SOUND_ENVIRONMENT_MOUNTAINS
#define SOUND_AREA_ICEMOON SOUND_ENVIRONMENT_CAVE
#define SOUND_AREA_WOODFLOOR SOUND_ENVIRONMENT_CITY

View File

@@ -29,5 +29,5 @@
#endif
/world/proc/enable_debugger()
if (fexists(EXTOOLS))
call(EXTOOLS, "debug_initialize")()
if (fexists(EXTOOLS))
call(EXTOOLS, "debug_initialize")()

View File

@@ -1,40 +1,90 @@
//Update this whenever the db schema changes
//make sure you add an update to the schema_version stable in the db changelog
//! Defines for subsystems and overlays
//!
//! Lots of important stuff in here, make sure you have your brain switched on
//! when editing this file
//! ## DB defines
/**
* DB major schema version
*
* Update this whenever the db schema changes
*
* make sure you add an update to the schema_version stable in the db changelog
*/
#define DB_MAJOR_VERSION 4
/**
* DB minor schema version
*
* Update this whenever the db schema changes
*
* make sure you add an update to the schema_version stable in the db changelog
*/
#define DB_MINOR_VERSION 7
//Timing subsystem
//Don't run if there is an identical unique timer active
//if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer, and returns the id of the existing timer
//! ## Timing subsystem
/**
* Don't run if there is an identical unique timer active
*
* if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer,
* and returns the id of the existing timer
*/
#define TIMER_UNIQUE (1<<0)
//For unique timers: Replace the old timer rather then not start this one
///For unique timers: Replace the old timer rather then not start this one
#define TIMER_OVERRIDE (1<<1)
//Timing should be based on how timing progresses on clients, not the sever.
// tracking this is more expensive,
// should only be used in conjuction with things that have to progress client side, such as animate() or sound()
/**
* Timing should be based on how timing progresses on clients, not the server.
*
* Tracking this is more expensive,
* should only be used in conjuction with things that have to progress client side, such as
* animate() or sound()
*/
#define TIMER_CLIENT_TIME (1<<2)
//Timer can be stopped using deltimer()
///Timer can be stopped using deltimer()
#define TIMER_STOPPABLE (1<<3)
//To be used with TIMER_UNIQUE
//prevents distinguishing identical timers with the wait variable
///prevents distinguishing identical timers with the wait variable
///
///To be used with TIMER_UNIQUE
#define TIMER_NO_HASH_WAIT (1<<4)
//Loops the timer repeatedly until qdeleted
//In most cases you want a subsystem instead
///Loops the timer repeatedly until qdeleted
///
///In most cases you want a subsystem instead, so don't use this unless you have a good reason
#define TIMER_LOOP (1<<5)
#define TIMER_NO_INVOKE_WARNING 600 //number of byond ticks that are allowed to pass before the timer subsystem thinks it hung on something
///Empty ID define
#define TIMER_ID_NULL -1
#define INITIALIZATION_INSSATOMS 0 //New should not call Initialize
#define INITIALIZATION_INNEW_MAPLOAD 2 //New should call Initialize(TRUE)
#define INITIALIZATION_INNEW_REGULAR 1 //New should call Initialize(FALSE)
//! ## Initialization subsystem
#define INITIALIZE_HINT_NORMAL 0 //Nothing happens
#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize
#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom
///New should not call Initialize
#define INITIALIZATION_INSSATOMS 0
///New should call Initialize(TRUE)
#define INITIALIZATION_INNEW_MAPLOAD 2
///New should call Initialize(FALSE)
#define INITIALIZATION_INNEW_REGULAR 1
//type and all subtypes should always call Initialize in New()
//! ### Initialization hints
///Nothing happens
#define INITIALIZE_HINT_NORMAL 0
/**
* call LateInitialize at the end of all atom Initalization
*
* The item will be added to the late_loaders list, this is iterated over after
* initalization of subsystems is complete and calls LateInitalize on the atom
* see [this file for the LateIntialize proc](atom.html#proc/LateInitialize)
*/
#define INITIALIZE_HINT_LATELOAD 1
///Call qdel on the atom after intialization
#define INITIALIZE_HINT_QDEL 2
///type and all subtypes should always immediately call Initialize in New()
#define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\
..();\
if(!(flags_1 & INITIALIZED_1)) {\
@@ -47,35 +97,40 @@
// Subsystems shutdown in the reverse of the order they initialize in
// The numbers just define the ordering, they are meaningless otherwise.
#define INIT_ORDER_PROFILER 100
#define INIT_ORDER_FAIL2TOPIC 99
#define INIT_ORDER_TITLE 98
#define INIT_ORDER_GARBAGE 95
#define INIT_ORDER_DBCORE 94
#define INIT_ORDER_STATPANELS 93
#define INIT_ORDER_BLACKBOX 92
#define INIT_ORDER_SERVER_MAINT 91
#define INIT_ORDER_INPUT 90
#define INIT_ORDER_SOUNDS 85
#define INIT_ORDER_PROFILER 102
#define INIT_ORDER_FAIL2TOPIC 101
#define INIT_ORDER_TITLE 100
#define INIT_ORDER_GARBAGE 99
#define INIT_ORDER_DBCORE 95
#define INIT_ORDER_BLACKBOX 94
#define INIT_ORDER_SERVER_MAINT 93
#define INIT_ORDER_INPUT 85
#define INIT_ORDER_SOUNDS 83
#define INIT_ORDER_INSTRUMENTS 82
#define INIT_ORDER_VIS 80
// #define INIT_ORDER_ACHIEVEMENTS 77
#define INIT_ORDER_RESEARCH 75
#define INIT_ORDER_EVENTS 70
#define INIT_ORDER_JOBS 65
#define INIT_ORDER_QUIRKS 60
#define INIT_ORDER_TICKER 55
#define INIT_ORDER_INSTRUMENTS 53
// #define INIT_ORDER_TCG 55
#define INIT_ORDER_MAPPING 50
#define INIT_ORDER_ECONOMY 45
#define INIT_ORDER_NETWORKS 40
#define INIT_ORDER_TIMETRACK 47
#define INIT_ORDER_NETWORKS 45
#define INIT_ORDER_ECONOMY 40
#define INIT_ORDER_HOLODECK 35
// #define INIT_ORDER_OUTPUTS 35
#define INIT_ORDER_ATOMS 30
#define INIT_ORDER_LANGUAGE 25
#define INIT_ORDER_MACHINES 20
#define INIT_ORDER_CIRCUIT 15
// #define INIT_ORDER_SKILLS 15
#define INIT_ORDER_TIMER 1
#define INIT_ORDER_DEFAULT 0
#define INIT_ORDER_AIR -1
#define INIT_ORDER_AIR_TURFS -2
#define INIT_ORDER_PERSISTENCE -2 //before assets because some assets take data from SSPersistence
#define INIT_ORDER_MINIMAP -3
#define INIT_ORDER_ASSETS -4
#define INIT_ORDER_ICON_SMOOTHING -5
@@ -86,7 +141,9 @@
#define INIT_ORDER_SHUTTLE -21
#define INIT_ORDER_MINOR_MAPPING -40
#define INIT_ORDER_PATH -50
#define INIT_ORDER_PERSISTENCE -95
// #define INIT_ORDER_DISCORD -60
// #define INIT_ORDER_EXPLOSIONS -69
#define INIT_ORDER_STATPANELS -98
#define INIT_ORDER_DEMO -99 // o avoid a bunch of changes related to initialization being written, do this last
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
@@ -102,6 +159,7 @@
#define FIRE_PRIORITY_GARBAGE 15
#define FIRE_PRIORITY_WET_FLOORS 20
#define FIRE_PRIORITY_AIR 20
#define FIRE_PRIORITY_NPC 20
#define FIRE_PRIORITY_PROCESS 25
#define FIRE_PRIORITY_THROWING 25
#define FIRE_PRIORITY_SPACEDRIFT 30
@@ -116,7 +174,6 @@
#define FIRE_PRIORITY_AIR_TURFS 40
#define FIRE_PRIORITY_DEFAULT 50
#define FIRE_PRIORITY_PARALLAX 65
#define FIRE_PRIORITY_NPC 80
#define FIRE_PRIORITY_MOBS 100
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_PROJECTILES 200
@@ -126,6 +183,8 @@
#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_RUNECHAT 410
#define FIRE_PRIORITY_OVERLAYS 500
// #define FIRE_PRIORITY_EXPLOSIONS 666
#define FIRE_PRIORITY_TIMER 700
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
// SS runlevels
@@ -138,6 +197,37 @@
#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
//! ## Overlays subsystem
///Compile all the overlays for an atom from the cache lists
// |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway.
#define COMPILE_OVERLAYS(A)\
if (TRUE) {\
var/list/ad = A.add_overlays;\
var/list/rm = A.remove_overlays;\
if(LAZYLEN(rm)){\
A.overlays -= rm;\
rm.Cut();\
}\
if(LAZYLEN(ad)){\
A.overlays |= ad;\
ad.Cut();\
}\
A.flags_1 &= ~OVERLAY_QUEUED_1;\
}
/**
Create a new timer and add it to the queue.
* Arguments:
* * callback the callback to call on timer finish
* * wait deciseconds to run the timer for
* * flags flags for this timer, see: code\__DEFINES\subsystems.dm
*/
#define addtimer(args...) _addtimer(args, file = __FILE__, line = __LINE__)
// SSair run section
#define SSAIR_PIPENETS 1
#define SSAIR_ATMOSMACHINERY 2
@@ -148,19 +238,3 @@
#define SSAIR_REBUILD_PIPENETS 7
#define SSAIR_EQUALIZE 8
#define SSAIR_ACTIVETURFS 9
// |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway.
#define COMPILE_OVERLAYS(A)\
if (TRUE) {\
var/list/ad = A.add_overlays;\
var/list/rm = A.remove_overlays;\
if(LAZYLEN(rm)){\
A.overlays -= rm;\
A.remove_overlays = null;\
}\
if(LAZYLEN(ad)){\
A.overlays |= ad;\
A.add_overlays = null;\
}\
A.flags_1 &= ~OVERLAY_QUEUED_1;\
}

View File

@@ -253,6 +253,7 @@
// item traits
#define TRAIT_NODROP "nodrop"
#define TRAIT_SPOOKY_THROW "spooky_throw"
// common trait sources
#define TRAIT_GENERIC "generic"

View File

@@ -2,7 +2,7 @@
#define APPROVAL_VOTING "APPROVAL"
#define SCHULZE_VOTING "SCHULZE"
#define SCORE_VOTING "SCORE"
#define MAJORITY_JUDGEMENT_VOTING "MAJORITY_JUDGEMENT"
#define HIGHEST_MEDIAN_VOTING "HIGHEST_MEDIAN"
#define INSTANT_RUNOFF_VOTING "IRV"
#define SHOW_RESULTS (1<<0)
@@ -18,7 +18,7 @@ GLOBAL_LIST_INIT(vote_type_names,list(\
"IRV (single winner ranked choice)" = INSTANT_RUNOFF_VOTING,\
"Schulze (ranked choice, higher result=better)" = SCHULZE_VOTING,\
"Raw Score (returns results from 0 to 1, winner is 1)" = SCORE_VOTING,\
"Majority Judgement (single-winner score voting)" = MAJORITY_JUDGEMENT_VOTING,\
"Highest Median (single-winner score voting)" = HIGHEST_MEDIAN_VOTING,\
))
GLOBAL_LIST_INIT(display_vote_settings, list(\

View File

@@ -1,5 +0,0 @@
#define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined
/proc/extools_log_write()
/proc/extools_finalize_logging()

View File

@@ -37,7 +37,7 @@
* TYPECONT: The typepath of the contents of the list
* COMPARE: The object to compare against, usualy the same as INPUT
* COMPARISON: The variable on the objects to compare
* COMPTYPE: How the current bin item to compare against COMPARE is fetched. By key or value.
* COMPTYPE: How should the values be compared? Either COMPARE_KEY or COMPARE_VALUE.
*/
#define BINARY_INSERT(INPUT, LIST, TYPECONT, COMPARE, COMPARISON, COMPTYPE) \
do {\
@@ -49,7 +49,7 @@
var/__BIN_LEFT = 1;\
var/__BIN_RIGHT = __BIN_CTTL;\
var/__BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\
var/##TYPECONT/__BIN_ITEM;\
var ##TYPECONT/__BIN_ITEM;\
while(__BIN_LEFT < __BIN_RIGHT) {\
__BIN_ITEM = COMPTYPE;\
if(__BIN_ITEM.##COMPARISON <= COMPARE.##COMPARISON) {\
@@ -67,24 +67,25 @@
//Returns a list in plain english as a string
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
var/total = input.len
if (!total)
return nothing_text
else if (total == 1)
return "[input[1]]"
else if (total == 2)
return "[input[1]][and_text][input[2]]"
else
var/output = ""
var/index = 1
while (index < total)
if (index == total - 1)
comma_text = final_comma_text
var/total = length(input)
switch(total)
if (0)
return "[nothing_text]"
if (1)
return "[input[1]]"
if (2)
return "[input[1]][and_text][input[2]]"
else
var/output = ""
var/index = 1
while (index < total)
if (index == total - 1)
comma_text = final_comma_text
output += "[input[index]][comma_text]"
index++
output += "[input[index]][comma_text]"
index++
return "[output][and_text][input[index]]"
return "[output][and_text][input[index]]"
//Returns list element or null. Should prevent "index out of bounds" error.
/proc/listgetindex(list/L, index)

View File

@@ -32,7 +32,7 @@
#define testing(msg)
#endif
#ifdef UNIT_TESTS
#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM)
/proc/log_test(text)
WRITE_LOG(GLOB.test_log, text)
SEND_TEXT(world.log, text)
@@ -191,6 +191,10 @@
/proc/log_mapping(text)
WRITE_LOG(GLOB.world_map_error_log, text)
/proc/log_perf(list/perf_info)
. = "[perf_info.Join(",")]\n"
WRITE_LOG_NO_FORMAT(GLOB.perf_log, .)
/proc/log_reagent(text)
WRITE_LOG(GLOB.reagent_log, text)

View File

@@ -19,22 +19,6 @@
/proc/arachnid_name()
return "[pick(GLOB.arachnid_first)] [pick(GLOB.arachnid_last)]"
/proc/church_name()
var/static/church_name
if (church_name)
return church_name
var/name = ""
name += pick("Holy", "United", "First", "Second", "Last")
if (prob(20))
name += " Space"
name += " " + pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses")
name += " of [religion_name()]"
return name
GLOBAL_VAR(command_name)
/proc/command_name()
@@ -52,17 +36,6 @@ GLOBAL_VAR(command_name)
return name
/proc/religion_name()
var/static/religion_name
if (religion_name)
return religion_name
var/name = ""
name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob")
name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity")
return capitalize(name)
/proc/station_name()
if(!GLOB.station_name)

View File

@@ -78,21 +78,21 @@
//Turns a direction into text
/proc/dir2text(direction)
switch(direction)
if(1)
if(NORTH)
return "north"
if(2)
if(SOUTH)
return "south"
if(4)
if(EAST)
return "east"
if(8)
if(WEST)
return "west"
if(5)
if(NORTHEAST)
return "northeast"
if(6)
if(SOUTHEAST)
return "southeast"
if(9)
if(NORTHWEST)
return "northwest"
if(10)
if(SOUTHWEST)
return "southwest"
else
return
@@ -101,21 +101,21 @@
/proc/text2dir(direction)
switch(uppertext(direction))
if("NORTH")
return 1
return NORTH
if("SOUTH")
return 2
return SOUTH
if("EAST")
return 4
return EAST
if("WEST")
return 8
return WEST
if("NORTHEAST")
return 5
return NORTHEAST
if("NORTHWEST")
return 9
return NORTHWEST
if("SOUTHEAST")
return 6
return SOUTHEAST
if("SOUTHWEST")
return 10
return SOUTHWEST
else
return

View File

@@ -263,7 +263,7 @@ Turf and target are separate in case you want to teleport some distance from a t
return .
//Returns a list of all items of interest with their name
/proc/getpois(mobs_only=0,skip_mindless=0)
/proc/getpois(mobs_only = FALSE, skip_mindless = FALSE, specify_dead_role = TRUE)
var/list/mobs = sortmobs()
var/list/namecounts = list()
var/list/pois = list()
@@ -277,7 +277,7 @@ Turf and target are separate in case you want to teleport some distance from a t
if(M.real_name && M.real_name != M.name)
name += " \[[M.real_name]\]"
if(M.stat == DEAD)
if(M.stat == DEAD && specify_dead_role)
if(isobserver(M))
name += " \[ghost\]"
else
@@ -1070,7 +1070,7 @@ B --><-- A
return closest_atom
proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
/proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
if (value == FALSE) //nothing should be calling us with a number, so this is safe
value = input("Enter type to find (blank for all, cancel to cancel)", "Search for type") as null|text
if (isnull(value))
@@ -1202,7 +1202,7 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
//Version of view() which ignores darkness, because BYOND doesn't have it (I actually suggested it but it was tagged redundant, BUT HEARERS IS A T- /rant).
/proc/dview(var/range = world.view, var/center, var/invis_flags = 0)
/proc/dview(range = world.view, center, invis_flags = 0)
if(!center)
return
@@ -1222,6 +1222,10 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
var/ready_to_die = FALSE
/mob/dview/Initialize() //Properly prevents this mob from gaining huds or joining any global lists
SHOULD_CALL_PARENT(FALSE)
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
flags_1 |= INITIALIZED_1
return INITIALIZE_HINT_NORMAL
/mob/dview/Destroy(force = FALSE)

View File

@@ -46,11 +46,11 @@
//Update this whenever you need to take advantage of more recent byond features
#define MIN_COMPILER_VERSION 513
#define MIN_COMPILER_BUILD 1508
#define MIN_COMPILER_BUILD 1514
#if DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD
//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.1508 or higher
#error You need version 513.1514 or higher
#endif
//Additional code for the above flags.
@@ -62,10 +62,14 @@
#define FIND_REF_NO_CHECK_TICK
#endif
#ifdef TRAVISBUILDING
#ifdef CIBUILDING
#define UNIT_TESTS
#endif
#ifdef TRAVISTESTING
#ifdef CITESTING
#define TESTING
#endif
// A reasonable number of maximum overlays an object needs
// If you think you need more, rethink it
#define MAX_ATOM_OVERLAYS 100

12
code/_globalvars/admin.dm Normal file
View File

@@ -0,0 +1,12 @@
GLOBAL_LIST_EMPTY(stickybanadminexemptions) //stores a list of ckeys exempted from a stickyban (workaround for a bug)
GLOBAL_LIST_EMPTY(stickybanadmintexts) //stores the entire stickyban list temporarily
GLOBAL_VAR(stickbanadminexemptiontimerid) //stores the timerid of the callback that restores all stickybans after an admin joins
// /proc/init_smites() //todo: add on the second wave
// var/list/smites = list()
// for (var/_smite_path in subtypesof(/datum/smite))
// var/datum/smite/smite_path = _smite_path
// smites[initial(smite_path.name)] = smite_path
// return smites
// GLOBAL_LIST_INIT_TYPED(smites, /datum/smite, init_smites())

View File

@@ -274,7 +274,7 @@ GLOBAL_LIST_INIT(redacted_strings, list("\[REDACTED\]", "\[CLASSIFIED\]", "\[ARC
GLOBAL_LIST_INIT(wisdoms, world.file2list("strings/wisdoms.txt"))
//LANGUAGE CHARACTER CUSTOMIZATION
GLOBAL_LIST_INIT(speech_verbs, list("default","says","gibbers", "states", "chitters", "chimpers", "declares", "bellows", "buzzes" ,"beeps", "chirps", "clicks", "hisses" ,"poofs" , "puffs", "rattles", "mewls" ,"barks", "blorbles", "squeaks", "squawks", "flutters", "warbles"))
GLOBAL_LIST_INIT(speech_verbs, list("default","says","gibbers", "states", "chitters", "chimpers", "declares", "bellows", "buzzes" ,"beeps", "chirps", "clicks", "hisses" ,"poofs" , "puffs", "rattles", "mewls" ,"barks", "blorbles", "squeaks", "squawks", "flutters", "warbles", "caws", "gekkers", "clucks"))
GLOBAL_LIST_INIT(roundstart_tongues, list("default","human tongue" = /obj/item/organ/tongue, "lizard tongue" = /obj/item/organ/tongue/lizard, "skeleton tongue" = /obj/item/organ/tongue/bone, "fly tongue" = /obj/item/organ/tongue/fly, "ipc tongue" = /obj/item/organ/tongue/robot/ipc, "xeno tongue" = /obj/item/organ/tongue/alien))
//SPECIES BODYPART LISTS

View File

@@ -8,6 +8,8 @@ GLOBAL_VAR(world_qdel_log)
GLOBAL_PROTECT(world_qdel_log)
GLOBAL_VAR(world_attack_log)
GLOBAL_PROTECT(world_attack_log)
// GLOBAL_VAR(world_econ_log)
// GLOBAL_PROTECT(world_econ_log)
GLOBAL_VAR(world_href_log)
GLOBAL_PROTECT(world_href_log)
GLOBAL_VAR(round_id)
@@ -26,22 +28,28 @@ GLOBAL_VAR(query_debug_log)
GLOBAL_PROTECT(query_debug_log)
GLOBAL_VAR(world_job_debug_log)
GLOBAL_PROTECT(world_job_debug_log)
// GLOBAL_VAR(world_mecha_log)
// GLOBAL_PROTECT(world_mecha_log)
GLOBAL_VAR(world_virus_log)
GLOBAL_PROTECT(world_virus_log)
GLOBAL_VAR(world_asset_log)
GLOBAL_PROTECT(world_asset_log)
// GLOBAL_VAR(world_cloning_log)
// GLOBAL_PROTECT(world_cloning_log)
GLOBAL_VAR(world_map_error_log)
GLOBAL_PROTECT(world_map_error_log)
GLOBAL_VAR(world_paper_log)
GLOBAL_PROTECT(world_paper_log)
GLOBAL_VAR(subsystem_log)
GLOBAL_PROTECT(subsystem_log)
GLOBAL_VAR(reagent_log)
GLOBAL_PROTECT(reagent_log)
GLOBAL_VAR(world_crafting_log)
GLOBAL_PROTECT(world_crafting_log)
GLOBAL_VAR(click_log)
GLOBAL_PROTECT(click_log)
GLOBAL_VAR(tgui_log)
GLOBAL_PROTECT(tgui_log)
GLOBAL_VAR(world_shuttle_log)
GLOBAL_PROTECT(world_shuttle_log)
GLOBAL_VAR(perf_log)
GLOBAL_PROTECT(perf_log)
// GLOBAL_VAR(demo_log)
// GLOBAL_PROTECT(demo_log)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
@@ -51,10 +59,7 @@ GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src]
GLOBAL_PROTECT(lastsignalers)
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
GLOBAL_PROTECT(lawchanges)
GLOBAL_VAR(tgui_log)
GLOBAL_PROTECT(tgui_log)
GLOBAL_VAR(world_shuttle_log)
GLOBAL_PROTECT(world_shuttle_log)
GLOBAL_LIST_EMPTY(combatlog)
GLOBAL_PROTECT(combatlog)
GLOBAL_LIST_EMPTY(IClog)
@@ -75,3 +80,13 @@ GLOBAL_PROTECT(picture_logging_id)
GLOBAL_VAR(picture_logging_prefix)
GLOBAL_PROTECT(picture_logging_prefix)
/////
//// cit logging
GLOBAL_VAR(subsystem_log)
GLOBAL_PROTECT(subsystem_log)
GLOBAL_VAR(reagent_log)
GLOBAL_PROTECT(reagent_log)
GLOBAL_VAR(world_crafting_log)
GLOBAL_PROTECT(world_crafting_log)
GLOBAL_VAR(click_log)
GLOBAL_PROTECT(click_log)

View File

@@ -130,7 +130,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
),
/obj/item = list(
"TRAIT_NODROP" = TRAIT_NODROP,
"TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT
"TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT,
"TRAIT_SPOOKY_THROW" = TRAIT_SPOOKY_THROW
)
))

View File

@@ -220,7 +220,7 @@
/obj/screen/alert/shiver
name = "Shivering"
desc = "You're shivering! Get somewhere warmer and take off any insulating clothing like a space suit."
desc = "You're shivering! Get somewhere warmer and take off any insulating clothing like a space suit."
/obj/screen/alert/lowpressure
name = "Low Pressure"
@@ -306,6 +306,39 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
if(CHECK_MOBILITY(L, MOBILITY_MOVE))
return L.resist_fire() //I just want to start a flame in your hearrrrrrtttttt.
/obj/screen/alert/give // information set when the give alert is made
icon_state = "default"
var/mob/living/carbon/giver
var/obj/item/receiving
/**
* Handles assigning most of the variables for the alert that pops up when an item is offered
*
* Handles setting the name, description and icon of the alert and tracking the person giving
* and the item being offered, also registers a signal that removes the alert from anyone who moves away from the giver
* Arguments:
* * taker - The person receiving the alert
* * giver - The person giving the alert and item
* * receiving - The item being given by the giver
*/
/obj/screen/alert/give/proc/setup(mob/living/carbon/taker, mob/living/carbon/giver, obj/item/receiving)
name = "[giver] is offering [receiving]"
desc = "[giver] is offering [receiving]. Click this alert to take it."
icon_state = "template"
cut_overlays()
add_overlay(receiving)
src.receiving = receiving
src.giver = giver
RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/removeAlert)
/obj/screen/alert/give/proc/removeAlert()
to_chat(usr, "<span class='warning'>You moved out of range of [giver]!</span>")
usr.clear_alert("[giver]")
/obj/screen/alert/give/Click(location, control, params)
. = ..()
var/mob/living/carbon/C = usr
C.take(giver, receiving)
//ALIENS

View File

@@ -149,6 +149,15 @@
/obj/screen/fullscreen/color_vision/blue
color = "#0000ff"
/obj/screen/fullscreen/cinematic_backdrop
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
plane = SPLASHSCREEN_PLANE
layer = SPLASHSCREEN_LAYER - 1
color = "#000000"
show_when_dead = TRUE
/obj/screen/fullscreen/lighting_backdrop
icon = 'icons/mob/screen_gen.dmi'
icon_state = "flash"

View File

@@ -10,6 +10,8 @@
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_1(null, C.view)
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_2(null, C.view)
C.parallax_layers_cached += new /obj/screen/parallax_layer/planet(null, C.view)
if(SSparallax.random_layer)
C.parallax_layers_cached += new SSparallax.random_layer
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_3(null, C.view)
C.parallax_layers = C.parallax_layers_cached.Copy()
@@ -52,12 +54,12 @@
switch(C.prefs.parallax)
if (PARALLAX_INSANE)
C.parallax_throttle = FALSE
C.parallax_layers_max = 4
C.parallax_layers_max = 5
return TRUE
if (PARALLAX_MED)
C.parallax_throttle = PARALLAX_DELAY_MED
C.parallax_layers_max = 2
C.parallax_layers_max = 3
return TRUE
if (PARALLAX_LOW)
@@ -68,8 +70,9 @@
if (PARALLAX_DISABLE)
return FALSE
//This is high parallax.
C.parallax_throttle = PARALLAX_DELAY_DEFAULT
C.parallax_layers_max = 3
C.parallax_layers_max = 4
return TRUE
/datum/hud/proc/update_parallax_pref(mob/viewmob)
@@ -219,15 +222,14 @@
L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]"
/atom/movable/proc/update_parallax_contents()
set waitfor = FALSE
if(length(client_mobs_in_contents))
for(var/thing in client_mobs_in_contents)
var/mob/M = thing
if(M && M.client && M.hud_used && length(M.client.parallax_layers))
if(M?.client && M.hud_used && length(M.client.parallax_layers))
M.hud_used.update_parallax()
/mob/proc/update_parallax_teleport() //used for arrivals shuttle
if(client && client.eye && hud_used && length(client.parallax_layers))
if(client?.eye && hud_used && length(client.parallax_layers))
var/area/areaobj = get_area(client.eye)
hud_used.set_parallax_movedir(areaobj.parallax_movedir, TRUE)
@@ -287,6 +289,21 @@
speed = 1.4
layer = 3
/obj/screen/parallax_layer/random
blend_mode = BLEND_OVERLAY
speed = 3
layer = 3
/obj/screen/parallax_layer/random/space_gas
icon_state = "space_gas"
/obj/screen/parallax_layer/random/space_gas/Initialize(mapload, view)
. = ..()
src.add_atom_colour(SSparallax.random_parallax_color, ADMIN_COLOUR_PRIORITY)
/obj/screen/parallax_layer/random/asteroids
icon_state = "asteroids"
/obj/screen/parallax_layer/planet
icon_state = "planet"
blend_mode = BLEND_OVERLAY
@@ -295,11 +312,11 @@
layer = 30
/obj/screen/parallax_layer/planet/update_status(mob/M)
var/turf/T = get_turf(M)
if(is_station_level(T.z))
invisibility = 0
else
invisibility = INVISIBILITY_ABSTRACT
var/client/C = M.client
var/turf/posobj = get_turf(C.eye)
if(!posobj)
return
invisibility = is_station_level(posobj.z) ? 0 : INVISIBILITY_ABSTRACT
/obj/screen/parallax_layer/planet/update_o()
return //Shit wont move
return //Shit won't move

View File

@@ -28,8 +28,6 @@
. = ..()
filters += filter(type="alpha", render_source=FIELD_OF_VISION_RENDER_TARGET, flags=MASK_INVERSE)
/obj/screen/plane_master/openspace/backdrop(mob/mymob)
filters = list()
filters += filter(type = "drop_shadow", color = "#04080FAA", size = -10)
filters += filter(type = "drop_shadow", color = "#04080FAA", size = -15)
filters += filter(type = "drop_shadow", color = "#04080FAA", size = -20)
@@ -93,13 +91,6 @@
else
remove_filter("ambient_occlusion")
//Reserved to chat messages, so they are still displayed above the field of vision masking.
/obj/screen/plane_master/chat_messages
name = "chat messages plane master"
plane = CHAT_PLANE
appearance_flags = PLANE_MASTER
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
///Contains all shadow cone masks, whose image overrides are displayed only to their respective owners.
/obj/screen/plane_master/field_of_vision
name = "field of vision mask plane master"
@@ -135,10 +126,14 @@
blend_mode = BLEND_MULTIPLY
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/obj/screen/plane_master/lighting/backdrop(mob/mymob)
mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit)
mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit)
/obj/screen/plane_master/lighting/Initialize()
. = ..()
filters += filter(type="alpha", render_source=EMISSIVE_RENDER_TARGET, flags=MASK_INVERSE)
filters += filter(type="alpha", render_source=EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags=MASK_INVERSE)
filters += filter(type="alpha", render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE)
filters += filter(type="alpha", render_source = EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags = MASK_INVERSE)
/**
* Things placed on this mask the lighting plane. Doesn't render directly.
@@ -186,7 +181,6 @@
render_target = EMISSIVE_BLOCKER_RENDER_TARGET
///Contains space parallax
/obj/screen/plane_master/parallax
name = "parallax plane master"
plane = PLANE_SPACE_PARALLAX
@@ -197,12 +191,16 @@
name = "parallax whitifier plane master"
plane = PLANE_SPACE
/obj/screen/plane_master/lighting/backdrop(mob/mymob)
mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit)
mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit)
/obj/screen/plane_master/camera_static
name = "camera static plane master"
plane = CAMERA_STATIC_PLANE
appearance_flags = PLANE_MASTER
blend_mode = BLEND_OVERLAY
//Reserved to chat messages, so they are still displayed above the field of vision masking.
/obj/screen/plane_master/chat_messages
name = "runechat plane master"
plane = CHAT_PLANE
appearance_flags = PLANE_MASTER
blend_mode = BLEND_OVERLAY

View File

@@ -12,9 +12,14 @@
layer = HUD_LAYER
plane = HUD_PLANE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
animate_movement = SLIDE_STEPS
speech_span = SPAN_ROBOT
vis_flags = VIS_INHERIT_PLANE
appearance_flags = APPEARANCE_UI
var/obj/master = null //A reference to the object in the slot. Grabs or items, generally.
var/datum/hud/hud = null // A reference to the owner HUD, if any.
/// A reference to the object in the slot. Grabs or items, generally.
var/obj/master = null
/// A reference to the owner HUD, if any.
var/datum/hud/hud = null
/**
* Map name assigned to this object.
* Automatically set by /client/proc/add_obj_to_map.
@@ -60,7 +65,17 @@
name = "swap hand"
/obj/screen/swap_hand/Click()
usr.swap_hand()
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
// if(world.time <= usr.next_move)
// return 1
if(usr.incapacitated())
return 1
if(ismob(usr))
var/mob/M = usr
M.swap_hand()
return 1
/obj/screen/craft
@@ -96,17 +111,27 @@
H.open_language_menu(usr)
/obj/screen/inventory
var/slot_id // The indentifier for the slot. It has nothing to do with ID cards.
var/icon_empty // Icon when empty. For now used only by humans.
var/icon_full // Icon when contains an item. For now used only by humans.
/// The identifier for the slot. It has nothing to do with ID cards.
var/slot_id
/// Icon when empty. For now used only by humans.
var/icon_empty
/// Icon when contains an item. For now used only by humans.
var/icon_full
/// The overlay when hovering over with an item in your hand
var/list/object_overlays = list()
layer = HUD_LAYER
plane = HUD_PLANE
/obj/screen/inventory/Click(location, control, params)
if(hud?.mymob && (hud.mymob != usr))
return
// just redirect clicks
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
// if(world.time <= usr.next_move)
// return TRUE
if(usr.incapacitated()) // ignore_stasis = TRUE
return TRUE
if(ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
if(hud?.mymob && slot_id)
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
@@ -150,12 +175,13 @@
var/image/item_overlay = image(holding)
item_overlay.alpha = 92
if(!user.can_equip(holding, slot_id, TRUE, TRUE, TRUE))
if(!user.can_equip(holding, slot_id, TRUE))
item_overlay.color = "#FF0000"
else
item_overlay.color = "#00ff00"
object_overlays += item_overlay
cut_overlay(object_overlays)
// object_overlay = item_overlay
add_overlay(object_overlays)
/obj/screen/inventory/hand
@@ -187,10 +213,17 @@
/obj/screen/inventory/hand/Click(location, control, params)
if(hud?.mymob && (hud.mymob != usr))
return
var/mob/user = hud.mymob
// just redirect clicks
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
var/mob/user = hud?.mymob
if(usr != user)
return TRUE
// if(world.time <= user.next_move)
// return TRUE
if(user.incapacitated())
return TRUE
if (ismecha(user.loc)) // stops inventory actions in a mech
return TRUE
if(user.active_hand_index == held_index)
var/obj/item/I = user.get_active_held_item()

View File

@@ -85,7 +85,7 @@
if(force && damtype != STAMINA && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
return
if(!UseStaminaBufferStandard(user, STAM_COST_ATTACK_MOB_MULT, null, TRUE))
return DISCARD_LAST_ACTION

View File

@@ -3,7 +3,7 @@
name = "Initializing..."
var/target
INITIALIZE_IMMEDIATE(/obj/effect/statclick) //it's new, but rebranded.
INITIALIZE_IMMEDIATE(/obj/effect/statclick)
/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical
. = ..()
@@ -33,14 +33,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) //it's new, but rebranded.
usr.client.debug_variables(target)
message_admins("Admin [key_name_admin(usr)] is debugging the [target] [class].")
/obj/effect/statclick/misc_subsystems/Click()
if(!usr.client.holder)
return
var/subsystem = input(usr, "Debug which subsystem?", "Debug nonprocessing subsystem") as null|anything in (Master.subsystems - Master.statworthy_subsystems)
if(!subsystem)
return
usr.client.debug_variables(subsystem)
message_admins("Admin [key_name_admin(usr)] is debugging the [subsystem] subsystem.")
// Debug verbs.
/client/proc/restart_controller(controller in list("Master", "Failsafe"))

View File

@@ -1,7 +1,7 @@
/**
* Failsafe
*
* Pretty much pokes the MC to make sure it's still alive.
* Failsafe
*
* Pretty much pokes the MC to make sure it's still alive.
**/
GLOBAL_REAL(Failsafe, /datum/controller/failsafe)

View File

@@ -1,10 +1,10 @@
/**
* StonedMC
*
* Designed to properly split up a given tick among subsystems
* Note: if you read parts of this code and think "why is it doing it that way"
* Odds are, there is a reason
*
/**
* StonedMC
*
* Designed to properly split up a given tick among subsystems
* Note: if you read parts of this code and think "why is it doing it that way"
* Odds are, there is a reason
*
**/
//This is the ABSOLUTE ONLY THING that should init globally like this
@@ -28,8 +28,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// List of subsystems to process().
var/list/subsystems
/// List of subsystems to include in the MC stat panel.
var/list/statworthy_subsystems
// Vars for keeping track of tick drift.
var/init_timeofday
@@ -41,7 +39,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
///Only run ticker subsystems for the next n ticks.
var/skip_ticks = 0
var/make_runtime = 0
var/make_runtime = FALSE
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
@@ -67,9 +65,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
//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
/// Statclick for misc subsystems
var/obj/effect/statclick/misc_subsystems/misc_statclick
/datum/controller/master/New()
if(!config)
config = new
@@ -96,11 +91,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
_subsystems += new I
Master = src
// We want to see all subsystems during init.
statworthy_subsystems = subsystems.Copy()
misc_statclick = new(null, "Debug")
if(!GLOB)
new /datum/controller/global_vars
@@ -217,7 +207,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// Sort subsystems by display setting for easy access.
sortTim(subsystems, /proc/cmp_subsystem_display)
// Set world options.
world.fps = CONFIG_GET(number/fps)
world.change_fps(CONFIG_GET(number/fps))
var/initialized_tod = REALTIMEOFDAY
if(tgs_prime)
@@ -271,14 +261,10 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/list/tickersubsystems = list()
var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel
var/timer = world.time
statworthy_subsystems = list()
for (var/thing in subsystems)
var/datum/controller/subsystem/SS = thing
if (SS.flags & SS_NO_FIRE)
if(SS.flags & SS_ALWAYS_SHOW_STAT)
statworthy_subsystems += SS
continue
statworthy_subsystems += SS
SS.queued_time = 0
SS.queue_next = null
SS.queue_prev = null

View File

@@ -23,7 +23,7 @@
var/priority = FIRE_PRIORITY_DEFAULT
/// [Subsystem Flags][SS_NO_INIT] to control binary behavior. Flags must be set at compile time or before preinit finishes to take full effect. (You can also restart the mc to force them to process again)
var/flags = 0
var/flags = NONE
/// This var is set to TRUE after the subsystem has been initialized.
var/initialized = FALSE
@@ -114,7 +114,7 @@
//previously, this would have been named 'process()' but that name is used everywhere for different things!
//fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds.
//Sleeping in here prevents future fires until returned.
/datum/controller/subsystem/proc/fire(resumed = 0)
/datum/controller/subsystem/proc/fire(resumed = FALSE)
flags |= SS_NO_FIRE
CRASH("Subsystem [src]([type]) does not fire() but did not set the SS_NO_FIRE flag. Please add the SS_NO_FIRE flag to any subsystem that doesn't fire so it doesn't get added to the processing list and waste cpu.")

View File

@@ -241,7 +241,8 @@ SUBSYSTEM_DEF(air)
return
/datum/controller/subsystem/air/proc/process_turf_equalize(resumed = 0)
return process_turf_equalize_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)
if(process_turf_equalize_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag))
pause()
/*
//cache for sanic speed
var/fire_count = times_fired
@@ -260,7 +261,8 @@ SUBSYSTEM_DEF(air)
*/
/datum/controller/subsystem/air/proc/process_active_turfs(resumed = 0)
return process_active_turfs_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)
if(process_active_turfs_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag))
pause()
/*
//cache for sanic speed
var/fire_count = times_fired
@@ -278,7 +280,8 @@ SUBSYSTEM_DEF(air)
*/
/datum/controller/subsystem/air/proc/process_excited_groups(resumed = 0)
return process_excited_groups_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)
if(process_excited_groups_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag))
pause()
/*
if (!resumed)
src.currentrun = excited_groups.Copy()

View File

@@ -11,7 +11,7 @@ SUBSYSTEM_DEF(assets)
switch (CONFIG_GET(string/asset_transport))
if ("webroot")
newtransporttype = /datum/asset_transport/webroot
if (newtransporttype == transport.type)
return

View File

@@ -10,33 +10,37 @@ SUBSYSTEM_DEF(atoms)
var/old_initialized
var/list/late_loaders
var/list/late_loaders = list()
var/list/BadInitializeCalls = list()
initialized = INITIALIZATION_INSSATOMS
/datum/controller/subsystem/atoms/Initialize(timeofday)
GLOB.fire_overlay.appearance_flags = RESET_COLOR
setupGenetics()
setupGenetics() //to set the mutations' sequence
initialized = INITIALIZATION_INNEW_MAPLOAD
InitializeAtoms()
initialized = INITIALIZATION_INNEW_REGULAR
return ..()
/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms)
if(initialized == INITIALIZATION_INSSATOMS)
return
old_initialized = initialized
initialized = INITIALIZATION_INNEW_MAPLOAD
LAZYINITLIST(late_loaders)
var/count
var/list/mapload_arg = list(TRUE)
if(atoms)
count = atoms.len
for(var/I in atoms)
var/atom/A = I
for(var/I in 1 to count)
var/atom/A = atoms[I]
if(!(A.flags_1 & INITIALIZED_1))
InitAtom(I, mapload_arg)
InitAtom(A, mapload_arg)
CHECK_TICK
else
count = 0
@@ -49,15 +53,16 @@ SUBSYSTEM_DEF(atoms)
testing("Initialized [count] atoms")
pass(count)
initialized = INITIALIZATION_INNEW_REGULAR
initialized = old_initialized
if(late_loaders.len)
for(var/I in late_loaders)
var/atom/A = I
for(var/I in 1 to late_loaders.len)
var/atom/A = late_loaders[I]
A.LateInitialize()
testing("Late initialized [late_loaders.len] atoms")
late_loaders.Cut()
/// Init this specific atom
/datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments)
var/the_type = A.type
if(QDELING(A))
@@ -150,8 +155,3 @@ SUBSYSTEM_DEF(atoms)
var/initlog = InitLog()
if(initlog)
text2file(initlog, "[GLOB.log_directory]/initialize.log")
#undef BAD_INIT_QDEL_BEFORE
#undef BAD_INIT_DIDNT_INIT
#undef BAD_INIT_SLEPT
#undef BAD_INIT_NO_HINT

View File

@@ -14,12 +14,14 @@ SUBSYSTEM_DEF(blackbox)
"explosion" = 2,
"time_dilation_current" = 3,
"science_techweb_unlock" = 2,
"round_end_stats" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
"round_end_stats" = 2,
"testmerged_prs" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
/datum/controller/subsystem/blackbox/Initialize()
triggertime = world.time
record_feedback("amount", "random_seed", Master.random_seed)
record_feedback("amount", "dm_version", DM_VERSION)
record_feedback("amount", "dm_build", DM_BUILD)
record_feedback("amount", "byond_version", world.byond_version)
record_feedback("amount", "byond_build", world.byond_build)
. = ..()
@@ -39,10 +41,7 @@ SUBSYSTEM_DEF(blackbox)
if(!SSdbcore.Connect())
return
var/playercount = 0
for(var/mob/M in GLOB.player_list)
if(M.client)
playercount += 1
var/playercount = LAZYLEN(GLOB.player_list)
var/admincount = GLOB.admins.len
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port, round_id) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]')")
query_record_playercount.Execute()
@@ -88,18 +87,24 @@ SUBSYSTEM_DEF(blackbox)
if (!SSdbcore.Connect())
return
// var/list/special_columns = list(
// "datetime" = "NOW()"
// )
var/list/sqlrowlist = list()
for (var/datum/feedback_variable/FV in feedback)
var/sqlversion = 1
if(FV.key in versions)
sqlversion = versions[FV.key]
sqlrowlist += list(list("datetime" = "Now()", "round_id" = GLOB.round_id, "key_name" = "'[sanitizeSQL(FV.key)]'", "key_type" = "'[FV.key_type]'", "version" = "[sqlversion]", "json" = "'[sanitizeSQL(json_encode(FV.json))]'"))
sqlrowlist += list(list(
"datetime" = "Now()", //legacy
"round_id" = GLOB.round_id,
"key_name" = sanitizeSQL(FV.key),
"key_type" = FV.key_type,
"version" = versions[FV.key] || 1,
"json" = sanitizeSQL(json_encode(FV.json))
))
if (!length(sqlrowlist))
return
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)//, special_columns = special_columns)
/datum/controller/subsystem/blackbox/proc/Seal()
if(sealed)
@@ -169,7 +174,7 @@ feedback data can be recorded in 5 formats:
"tally"
used to track the number of occurances of multiple related values i.e. how many times each type of gun is fired
further calls to the same key will:
add or subtract from the saved value of the data key if it already exists
add or subtract from the saved value of the data key if it already exists
append the key and it's value if it doesn't exist
calls: SSblackbox.record_feedback("tally", "example", 1, "sample data")
SSblackbox.record_feedback("tally", "example", 4, "sample data")
@@ -181,7 +186,7 @@ feedback data can be recorded in 5 formats:
the final element in the data list is used as the tracking key, all prior elements are used for nesting
all data list elements must be strings
further calls to the same key will:
add or subtract from the saved value of the data key if it already exists in the same multi-dimensional position
add or subtract from the saved value of the data key if it already exists in the same multi-dimensional position
append the key and it's value if it doesn't exist
calls: SSblackbox.record_feedback("nested tally", "example", 1, list("fruit", "orange", "apricot"))
SSblackbox.record_feedback("nested tally", "example", 2, list("fruit", "orange", "orange"))
@@ -270,6 +275,18 @@ Versioning
/datum/feedback_variable/New(new_key, new_key_type)
key = new_key
key_type = new_key_type
/*
/datum/controller/subsystem/blackbox/proc/LogAhelp(ticket, action, message, recipient, sender)
if(!SSdbcore.Connect())
return
var/datum/db_query/query_log_ahelp = SSdbcore.NewQuery({"
INSERT INTO [format_table_name("ticket")] (ticket, action, message, recipient, sender, server_ip, server_port, round_id, timestamp)
VALUES (:ticket, :action, :message, :recipient, :sender, INET_ATON(:server_ip), :server_port, :round_id, :time)
"}, list("ticket" = ticket, "action" = action, "message" = message, "recipient" = recipient, "sender" = sender, "server_ip" = world.internet_address || "0", "server_port" = world.port, "round_id" = GLOB.round_id, "time" = SQLtime()))
query_log_ahelp.Execute()
qdel(query_log_ahelp)
*/
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
set waitfor = FALSE

View File

@@ -1,4 +1,4 @@
/**
/*!
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/

View File

@@ -177,6 +177,25 @@ SUBSYSTEM_DEF(dbcore)
return FALSE
return new /datum/DBQuery(sql_query, connection)
/datum/controller/subsystem/dbcore/proc/QuerySelect(list/querys, warn = FALSE, qdel = FALSE)
if (!islist(querys))
if (!istype(querys, /datum/DBQuery))
CRASH("Invalid query passed to QuerySelect: [querys]")
querys = list(querys)
for (var/thing in querys)
var/datum/DBQuery/query = thing
if (warn)
INVOKE_ASYNC(query, /datum/DBQuery.proc/warn_execute)
else
INVOKE_ASYNC(query, /datum/DBQuery.proc/Execute)
for (var/thing in querys)
var/datum/DBQuery/query = thing
UNTIL(!query.in_progress)
if (qdel)
qdel(query)
/*
Takes a list of rows (each row being an associated list of column => value) and inserts them via a single mass query.
Rows missing columns present in other rows will resolve to SQL NULL
@@ -361,5 +380,5 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table
//strip sensitive stuff
if(findtext(message, ": CreateConnection("))
message = "CreateConnection CENSORED"
log_sql("BSQL_DEBUG: [message]")

View File

@@ -25,7 +25,7 @@ SUBSYSTEM_DEF(events)
return ..()
/datum/controller/subsystem/events/fire(resumed = 0)
/datum/controller/subsystem/events/fire(resumed = FALSE)
if(!resumed)
checkEvent() //only check these if we aren't resuming a paused fire
src.currentrun = running.Copy()
@@ -37,7 +37,7 @@ SUBSYSTEM_DEF(events)
var/datum/thing = currentrun[currentrun.len]
currentrun.len--
if(thing)
thing.process()
thing.process(wait * 0.1)
else
running.Remove(thing)
if (MC_TICK_CHECK)
@@ -91,13 +91,13 @@ SUBSYSTEM_DEF(events)
if(. == EVENT_CANT_RUN)//we couldn't run this event for some reason, set its max_occurrences to 0
E.max_occurrences = 0
else if(. == EVENT_READY)
E.random = TRUE
E.runEvent(TRUE)
E.runEvent(random = TRUE)
//allows a client to trigger an event
//aka Badmin Central
// > Not in modules/admin
// REEEEEEEEE
// Why the heck is this here! Took me so damn long to find!
/client/proc/forceEvent()
set name = "Trigger Event"
set category = "Admin.Events"

View File

@@ -18,6 +18,7 @@ SUBSYSTEM_DEF(fire_burning)
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
var/delta_time = wait * 0.1
while(currentrun.len)
var/obj/O = currentrun[currentrun.len]
@@ -28,10 +29,12 @@ SUBSYSTEM_DEF(fire_burning)
return
continue
if(O.resistance_flags & ON_FIRE)
O.take_damage(20, BURN, "fire", 0)
else
processing -= O
if(O.resistance_flags & ON_FIRE) //in case an object is extinguished while still in currentrun
if(!(O.resistance_flags & FIRE_PROOF))
O.take_damage(10 * delta_time, BURN, "fire", 0)
else
O.extinguish()
if (MC_TICK_CHECK)
return

View File

@@ -1,3 +1,26 @@
/*!
## Debugging GC issues
In order to debug `qdel()` failures, there are several tools available.
To enable these tools, define `TESTING` in [_compile_options.dm](https://github.com/tgstation/-tg-station/blob/master/code/_compile_options.dm).
First is a verb called "Find References", which lists **every** refererence to an object in the world. This allows you to track down any indirect or obfuscated references that you might have missed.
Complementing this is another verb, "qdel() then Find References".
This does exactly what you'd expect; it calls `qdel()` on the object and then it finds all references remaining.
This is great, because it means that `Destroy()` will have been called before it starts to find references,
so the only references you'll find will be the ones preventing the object from `qdel()`ing gracefully.
If you have a datum or something you are not destroying directly (say via the singulo),
the next tool is `QDEL_HINT_FINDREFERENCE`. You can return this in `Destroy()` (where you would normally `return ..()`),
to print a list of references once it enters the GC queue.
Finally is a verb, "Show qdel() Log", which shows the deletion log that the garbage subsystem keeps. This is helpful if you are having race conditions or need to review the order of deletions.
Note that for any of these tools to work `TESTING` must be defined.
By using these methods of finding references, you can make your life far, far easier when dealing with `qdel()` failures.
*/
SUBSYSTEM_DEF(garbage)
name = "Garbage"
priority = FIRE_PRIORITY_GARBAGE
@@ -6,7 +29,7 @@ SUBSYSTEM_DEF(garbage)
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
init_order = INIT_ORDER_GARBAGE
var/list/collection_timeout = list(15 SECONDS, 30 SECONDS) // deciseconds to wait before moving something up in the queue to the next level
var/list/collection_timeout = list(2 MINUTES, 10 SECONDS) // 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
@@ -24,10 +47,8 @@ SUBSYSTEM_DEF(garbage)
//Queue
var/list/queues
#ifdef LEGACY_REFERENCE_TRACKING
var/list/reference_find_on_fail = list()
var/list/reference_find_on_fail_types = list()
#endif
@@ -99,6 +120,9 @@ SUBSYSTEM_DEF(garbage)
state = SS_RUNNING
break
/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK)
if (level == GC_QUEUE_CHECK)
delslasttick = 0
@@ -139,7 +163,7 @@ SUBSYSTEM_DEF(garbage)
++totalgcs
pass_counts[level]++
#ifdef LEGACY_REFERENCE_TRACKING
reference_find_on_fail -= refID //It's deleted we don't care anymore.
reference_find_on_fail -= refID //It's deleted we don't care anymore.
#endif
if (MC_TICK_CHECK)
return
@@ -153,10 +177,10 @@ SUBSYSTEM_DEF(garbage)
D.find_references()
#elif defined(LEGACY_REFERENCE_TRACKING)
if(reference_find_on_fail[refID])
D.find_references()
D.find_references_legacy()
#ifdef GC_FAILURE_HARD_LOOKUP
else
D.find_references()
D.find_references_legacy()
#endif
reference_find_on_fail -= refID
#endif
@@ -190,24 +214,6 @@ SUBSYSTEM_DEF(garbage)
queue.Cut(1,count+1)
count = 0
/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK)
if (isnull(D))
return
if (level > GC_QUEUE_COUNT)
HardDelete(D)
return
var/gctime = world.time
var/refid = "\ref[D]"
#ifdef LEGACY_REFERENCE_TRACKING
if(reference_find_on_fail_types[D.type])
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
#ifdef LEGACY_REFERENCE_TRACKING
/datum/controller/subsystem/garbage/proc/add_type_to_findref(type)
if(!ispath(type))
@@ -223,6 +229,24 @@ SUBSYSTEM_DEF(garbage)
reference_find_on_fail_types = list()
#endif
/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK)
if (isnull(D))
return
if (level > GC_QUEUE_COUNT)
HardDelete(D)
return
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
@@ -275,8 +299,10 @@ SUBSYSTEM_DEF(garbage)
/datum/qdel_item/New(mytype)
name = "[mytype]"
// Should be treated as a replacement for the 'del' keyword.
// Datums passed to this will be given a chance to clean up references to allow the GC to collect them.
/// Should be treated as a replacement for the 'del' keyword.
///
/// Datums passed to this will be given a chance to clean up references to allow the GC to collect them.
/proc/qdel(datum/D, force=FALSE, ...)
if(!istype(D))
del(D)
@@ -331,9 +357,10 @@ SUBSYSTEM_DEF(garbage)
#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.
SSgarbage.Queue(D)
D.find_references_legacy()
if (QDEL_HINT_IFFAIL_FINDREFERENCE)
SSgarbage.Queue(D)
SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE
SSgarbage.reference_find_on_fail[REF(D)] = TRUE
#endif
else
#ifdef TESTING

View File

@@ -33,8 +33,9 @@ SUBSYSTEM_DEF(idlenpcpool)
while(currentrun.len)
var/mob/living/simple_animal/SA = currentrun[currentrun.len]
--currentrun.len
if (!SA)
if (QDELETED(SA))
GLOB.simple_animals[AI_IDLE] -= SA
log_world("Found a null in simple_animals list!")
continue
if(!SA.ckey)

View File

@@ -2,13 +2,13 @@ SUBSYSTEM_DEF(ipintel)
name = "XKeyScore"
init_order = INIT_ORDER_XKEYSCORE
flags = SS_NO_FIRE
var/enabled = 0 //disable at round start to avoid checking reconnects
var/enabled = FALSE //disable at round start to avoid checking reconnects
var/throttle = 0
var/errors = 0
var/list/cache = list()
/datum/controller/subsystem/ipintel/Initialize(timeofday, zlevel)
enabled = 1
enabled = TRUE
. = ..()

View File

@@ -691,21 +691,29 @@ SUBSYSTEM_DEF(job)
if(!permitted)
continue
var/obj/item/I = new G.path
if(I && length(i[LOADOUT_COLOR])) //handle loadout colors
//handle polychromic items
if((G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC) && length(G.loadout_initial_colors))
var/datum/element/polychromic/polychromic = I.comp_lookup["item_worn_overlays"] //stupid way to do it but GetElement does not work for this
if(polychromic && istype(polychromic))
var/list/polychromic_entry = polychromic.colors_by_atom[I]
if(polychromic_entry)
if(polychromic.suits_with_helmet_typecache[I.type]) //is this one of those toggleable hood/helmet things?
polychromic.connect_helmet(I,i[LOADOUT_COLOR])
polychromic.colors_by_atom[I] = i[LOADOUT_COLOR]
I.update_icon()
else
//handle non-polychromic items (they only have one color)
I.add_atom_colour(i[LOADOUT_COLOR][1], FIXED_COLOUR_PRIORITY)
I.update_icon()
if(I)
if(length(i[LOADOUT_COLOR])) //handle loadout colors
//handle polychromic items
if((G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC) && length(G.loadout_initial_colors))
var/datum/element/polychromic/polychromic = I.comp_lookup["item_worn_overlays"] //stupid way to do it but GetElement does not work for this
if(polychromic && istype(polychromic))
var/list/polychromic_entry = polychromic.colors_by_atom[I]
if(polychromic_entry)
if(polychromic.suits_with_helmet_typecache[I.type]) //is this one of those toggleable hood/helmet things?
polychromic.connect_helmet(I,i[LOADOUT_COLOR])
polychromic.colors_by_atom[I] = i[LOADOUT_COLOR]
I.update_icon()
else
//handle non-polychromic items (they only have one color)
I.add_atom_colour(i[LOADOUT_COLOR][1], FIXED_COLOUR_PRIORITY)
I.update_icon()
//when inputting the data it's already sanitized
if(i[LOADOUT_CUSTOM_NAME])
var/custom_name = i[LOADOUT_CUSTOM_NAME]
I.name = custom_name
if(i[LOADOUT_CUSTOM_DESCRIPTION])
var/custom_description = i[LOADOUT_CUSTOM_DESCRIPTION]
I.desc = custom_description
if(!M.equip_to_slot_if_possible(I, G.slot, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first
if(iscarbon(M))
var/mob/living/carbon/C = M

View File

@@ -94,8 +94,8 @@ SUBSYSTEM_DEF(jukeboxes)
stack_trace("Nonexistant or invalid object associated with jukebox.")
continue
var/sound/song_played = sound(juketrack.song_path)
var/area/currentarea = get_area(jukebox)
var/turf/currentturf = get_turf(jukebox)
var/area/currentarea = get_area(jukebox)
var/list/hearerscache = hearers(7, jukebox)
song_played.falloff = jukeinfo[4]
@@ -116,7 +116,6 @@ SUBSYSTEM_DEF(jukeboxes)
inrange = TRUE
else
song_played.status = SOUND_MUTE | SOUND_UPDATE //Setting volume = 0 doesn't let the sound properties update at all, which is lame.
M.playsound_local(currentturf, null, 100, channel = jukeinfo[2], S = song_played, envwet = (inrange ? -250 : 0), envdry = (inrange ? 0 : -10000))
CHECK_TICK
return

View File

@@ -6,6 +6,7 @@ SUBSYSTEM_DEF(lighting)
name = "Lighting"
wait = 2
init_order = INIT_ORDER_LIGHTING
flags = SS_TICKER
/datum/controller/subsystem/lighting/stat_entry(msg)
msg = "L:[length(GLOB.lighting_update_lights)]|C:[length(GLOB.lighting_update_corners)]|O:[length(GLOB.lighting_update_objects)]"

View File

@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(machines)
name = "Machines"
init_order = INIT_ORDER_MACHINES
flags = SS_KEEP_TIMING
wait = 2 SECONDS
var/list/processing = list()
var/list/currentrun = list()
var/list/powernets = list()
@@ -27,7 +28,7 @@ SUBSYSTEM_DEF(machines)
return ..()
/datum/controller/subsystem/machines/fire(resumed = 0)
/datum/controller/subsystem/machines/fire(resumed = FALSE)
if (!resumed)
for(var/datum/powernet/Powernet in powernets)
Powernet.reset() //reset the power state.
@@ -36,11 +37,10 @@ SUBSYSTEM_DEF(machines)
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
var/seconds = wait * 0.1
while(currentrun.len)
var/obj/machinery/thing = currentrun[currentrun.len]
currentrun.len--
if(!QDELETED(thing) && thing.process(seconds) != PROCESS_KILL)
if(!QDELETED(thing) && thing.process(wait * 0.1) != PROCESS_KILL)
if(thing.use_power)
thing.auto_use_power() //add back the power state
else

View File

@@ -1,7 +1,7 @@
SUBSYSTEM_DEF(min_spawns)
name = "Minimum Spawns" /// this hot steaming pile of garbage makes sure theres a minimum of tendrils scattered around
init_order = INIT_ORDER_DEFAULT
flags = SS_BACKGROUND | SS_NO_FIRE | SS_ALWAYS_SHOW_STAT
flags = SS_BACKGROUND | SS_NO_FIRE
wait = 2
var/where_we_droppin_boys_iterations = 0
var/snaxi_snowflake_check = FALSE
@@ -71,7 +71,7 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list(
continue
if(typesof(/turf/open/lava) in orange(9, TT))
continue
valid_mining_turfs_2.Add(TT)
valid_mining_turfs_2.Add(TT)
else
for(var/z_level in SSmapping.levels_by_trait(ZTRAIT_LAVA_RUINS))
for(var/turf/TT in Z_TURFS(z_level))
@@ -103,14 +103,14 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list(
for(var/mob/living/simple_animal/hostile/megafauna/H in urange(70,RT)) //prevents mob clumps
if((istype(MS_tospawn, /mob/living/simple_animal/hostile/megafauna)) && get_dist(RT, H) <= 70)
active_spawns.Add(MS_tospawn)
continue //let's try not to dump megas too close to each other?
continue //let's try not to dump megas too close to each other?
if((istype(MS_tospawn, /obj/structure/spawner)) && get_dist(RT, H) <= 40)
active_spawns.Add(MS_tospawn)
continue //let's at least /try/ to space these out?
for(var/obj/structure/spawner/LT in urange(70,RT)) //prevents tendril/mega clumps
if((istype(MS_tospawn, /mob/living/simple_animal/hostile/megafauna)) && get_dist(RT, LT) <= 70)
active_spawns.Add(MS_tospawn)
continue //let's try not to dump megas too close to each other?
continue //let's try not to dump megas too close to each other?
if((istype(MS_tospawn, /obj/structure/spawner)) && get_dist(RT, LT) <= 40)
active_spawns.Add(MS_tospawn)
continue //let's at least /try/ to space these out?
@@ -127,7 +127,7 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list(
for(var/mob/living/simple_animal/hostile/H in urange(70,RT2)) //prevents mob clumps
if((istype(MS2_tospawn, /mob/living/simple_animal/hostile/megafauna) || ismegafauna(H)) && get_dist(RT2, H) <= 70)
active_spawns_2.Add(MS2_tospawn)
continue //let's try not to dump megas too close to each other?
continue //let's try not to dump megas too close to each other?
if((istype(MS2_tospawn, /obj/structure/spawner)) && get_dist(RT2, H) <= 40)
active_spawns_2.Add(MS2_tospawn)
continue //let's at least /try/ to space these out?

View File

@@ -1,3 +1,5 @@
#define PROB_MOUSE_SPAWN 98
SUBSYSTEM_DEF(minor_mapping)
name = "Minor Mapping"
init_order = INIT_ORDER_MINOR_MAPPING
@@ -5,29 +7,43 @@ SUBSYSTEM_DEF(minor_mapping)
/datum/controller/subsystem/minor_mapping/Initialize(timeofday)
trigger_migration(CONFIG_GET(number/mice_roundstart))
// place_satchels()
return ..()
/datum/controller/subsystem/minor_mapping/proc/trigger_migration(num_mice=10)
var/list/exposed_wires = find_exposed_wires()
var/mob/living/simple_animal/mouse/M
var/mob/living/simple_animal/mouse/mouse
var/turf/proposed_turf
while((num_mice > 0) && exposed_wires.len)
proposed_turf = pick_n_take(exposed_wires)
if(!M)
M = new(proposed_turf)
else
M.forceMove(proposed_turf)
if(M.environment_is_safe())
num_mice -= 1
M = null
if(prob(PROB_MOUSE_SPAWN))
if(!mouse)
mouse = new(proposed_turf)
else
mouse.forceMove(proposed_turf)
// else
// mouse = new /mob/living/simple_animal/hostile/regalrat/controlled(proposed_turf)
if(mouse.environment_is_safe())
num_mice -= 1
mouse = null
// /datum/controller/subsystem/minor_mapping/proc/place_satchels(amount=10)
// var/list/turfs = find_satchel_suitable_turfs()
// while(turfs.len && amount > 0)
// var/turf/T = pick_n_take(turfs)
// var/obj/item/storage/backpack/satchel/flat/F = new(T)
// SEND_SIGNAL(F, COMSIG_OBJ_HIDE, T.intact)
// amount--
/proc/find_exposed_wires()
var/list/exposed_wires = list()
exposed_wires.Cut()
var/list/all_turfs
for (var/z in SSmapping.levels_by_trait(ZTRAIT_STATION))
for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION))
all_turfs += block(locate(1,1,z), locate(world.maxx,world.maxy,z))
for(var/turf/open/floor/plating/T in all_turfs)
if(is_blocked_turf(T))
@@ -36,3 +52,15 @@ SUBSYSTEM_DEF(minor_mapping)
exposed_wires += T
return shuffle(exposed_wires)
// /proc/find_satchel_suitable_turfs()
// var/list/suitable = list()
// for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION))
// for(var/t in block(locate(1,1,z), locate(world.maxx,world.maxy,z)))
// if(isfloorturf(t) && !isplatingturf(t))
// suitable += t
// return shuffle(suitable)
#undef PROB_MOUSE_SPAWN

View File

@@ -48,9 +48,16 @@ SUBSYSTEM_DEF(overlays)
for (var/thing in queue)
count++
if(thing)
STAT_START_STOPWATCH
var/atom/A = thing
if(A.overlays.len >= MAX_ATOM_OVERLAYS)
//Break it real GOOD
stack_trace("Too many overlays on [A.type] - [A.overlays.len], refusing to update and cutting")
A.overlays.Cut()
continue
STAT_START_STOPWATCH
COMPILE_OVERLAYS(A)
UNSETEMPTY(A.add_overlays)
UNSETEMPTY(A.remove_overlays)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(stats, A.type)
if(mc_check)
@@ -117,9 +124,8 @@ SUBSYSTEM_DEF(overlays)
#define QUEUE_FOR_COMPILE flags_1 |= OVERLAY_QUEUED_1; SSoverlays.queue += src;
/atom/proc/cut_overlays()
LAZYINITLIST(remove_overlays)
LAZYINITLIST(add_overlays)
remove_overlays = overlays.Copy()
add_overlays.Cut()
add_overlays = null
//If not already queued for work and there are overlays to remove
if(NOT_QUEUED_ALREADY && remove_overlays.len)
@@ -129,7 +135,7 @@ SUBSYSTEM_DEF(overlays)
if(!overlays)
return
overlays = build_appearance_list(overlays)
LAZYINITLIST(add_overlays) //always initialized after this point
LAZYINITLIST(add_overlays)
LAZYINITLIST(remove_overlays)
var/a_len = add_overlays.len
var/r_len = remove_overlays.len
@@ -140,8 +146,9 @@ SUBSYSTEM_DEF(overlays)
var/fr_len = remove_overlays.len
//If not already queued and there is work to be done
if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len))
if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len ))
QUEUE_FOR_COMPILE
UNSETEMPTY(add_overlays)
/atom/proc/add_overlay(list/overlays)
if(!overlays)

View File

@@ -7,13 +7,21 @@ SUBSYSTEM_DEF(parallax)
var/list/currentrun
var/planet_x_offset = 128
var/planet_y_offset = 128
var/random_layer
var/random_parallax_color
/datum/controller/subsystem/parallax/Initialize(timeofday)
//These are cached per client so needs to be done asap so people joining at roundstart do not miss these.
/datum/controller/subsystem/parallax/PreInit()
. = ..()
if(prob(70)) //70% chance to pick a special extra layer
random_layer = pick(/obj/screen/parallax_layer/random/space_gas, /obj/screen/parallax_layer/random/asteroids)
random_parallax_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)//Special color for random_layer1. Has to be done here so everyone sees the same color. [COLOR_SILVER]
planet_y_offset = rand(100, 160)
planet_x_offset = rand(100, 160)
/datum/controller/subsystem/parallax/fire(resumed = 0)
/datum/controller/subsystem/parallax/fire(resumed = FALSE)
if (!resumed)
src.currentrun = GLOB.clients.Copy()
@@ -21,24 +29,27 @@ SUBSYSTEM_DEF(parallax)
var/list/currentrun = src.currentrun
while(length(currentrun))
var/client/C = currentrun[currentrun.len]
var/client/processing_client = currentrun[currentrun.len]
currentrun.len--
if (!C || !C.eye)
if (QDELETED(processing_client) || !processing_client.eye)
if (MC_TICK_CHECK)
return
continue
var/atom/movable/A = C.eye
if(!istype(A))
continue
for (A; isloc(A.loc) && !isturf(A.loc); A = A.loc);
if(A != C.movingmob)
if(C.movingmob != null)
C.movingmob.client_mobs_in_contents -= C.mob
UNSETEMPTY(C.movingmob.client_mobs_in_contents)
LAZYINITLIST(A.client_mobs_in_contents)
A.client_mobs_in_contents += C.mob
C.movingmob = A
var/atom/movable/movable_eye = processing_client.eye
if(!istype(movable_eye))
continue
for (movable_eye; isloc(movable_eye.loc) && !isturf(movable_eye.loc); movable_eye = movable_eye.loc);
if(movable_eye == processing_client.movingmob)
if (MC_TICK_CHECK)
return
continue
if(!isnull(processing_client.movingmob))
LAZYREMOVE(processing_client.movingmob.client_mobs_in_contents, processing_client.mob)
LAZYADD(movable_eye.client_mobs_in_contents, processing_client.mob)
processing_client.movingmob = movable_eye
if (MC_TICK_CHECK)
return
currentrun = null

View File

@@ -18,7 +18,7 @@ SUBSYSTEM_DEF(pathfinder)
var/free
var/list/flow
/datum/flowcache/New(var/n)
/datum/flowcache/New(n)
. = ..()
lcount = n
run = 0

View File

@@ -58,6 +58,7 @@ SUBSYSTEM_DEF(persistence)
if(CONFIG_GET(flag/use_antag_rep))
LoadAntagReputation()
LoadRandomizedRecipes()
LoadPaintings()
/**
* Saves persistent data relevant to the server: Configurations, past gamemodes, votes, antag rep, etc

View File

@@ -1,6 +1,4 @@
//Fires five times every second.
PROCESSING_SUBSYSTEM_DEF(fastprocess)
name = "Fast Processing"
wait = 2
wait = 0.2 SECONDS
stat_tag = "FP"

View File

@@ -1,7 +1,7 @@
PROCESSING_SUBSYSTEM_DEF(nanites)
name = "Nanites"
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
wait = 10
wait = 1 SECONDS
var/list/datum/nanite_cloud_backup/cloud_backups = list()
var/list/mob/living/nanite_monitored_mobs = list()

View File

@@ -2,4 +2,4 @@ PROCESSING_SUBSYSTEM_DEF(obj)
name = "Objects"
priority = FIRE_PRIORITY_OBJ
flags = SS_NO_INIT
wait = 20
wait = 2 SECONDS

View File

@@ -1,10 +1,10 @@
//Used to process objects. Fires once every second.
//Used to process objects.
SUBSYSTEM_DEF(processing)
name = "Processing"
priority = FIRE_PRIORITY_PROCESS
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
wait = 10
wait = 1 SECONDS
var/stat_tag = "P" //Used for logging
var/list/processing = list()
@@ -14,9 +14,10 @@ SUBSYSTEM_DEF(processing)
msg = "[stat_tag]:[length(processing)]"
return ..()
/datum/controller/subsystem/processing/fire(resumed = 0)
/datum/controller/subsystem/processing/fire(resumed = FALSE)
if (!resumed)
currentrun = processing.Copy()
var/delta_time = (flags & SS_TICKER)? (wait * world.tick_lag * 0.1) : (wait * 0.1)
//cache for sanic speed (lists are references anyways)
var/list/current_run = currentrun
@@ -25,12 +26,26 @@ SUBSYSTEM_DEF(processing)
current_run.len--
if(QDELETED(thing))
processing -= thing
else if(thing.process(wait) == PROCESS_KILL)
else if(thing.process(delta_time) == PROCESS_KILL)
// fully stop so that a future START_PROCESSING will work
STOP_PROCESSING(src, thing)
if (MC_TICK_CHECK)
return
/datum/proc/process()
set waitfor = 0
/**
* This proc is called on a datum on every "cycle" if it is being processed by a subsystem. The time between each cycle is determined by the subsystem's "wait" setting.
* You can start and stop processing a datum using the START_PROCESSING and STOP_PROCESSING defines.
*
* Since the wait setting of a subsystem can be changed at any time, it is important that any rate-of-change that you implement in this proc is multiplied by the delta_time that is sent as a parameter,
* Additionally, any "prob" you use in this proc should instead use the DT_PROB define to make sure that the final probability per second stays the same even if the subsystem's wait is altered.
* Examples where this must be considered:
* - Implementing a cooldown timer, use `mytimer -= delta_time`, not `mytimer -= 1`. This way, `mytimer` will always have the unit of seconds
* - Damaging a mob, do `L.adjustFireLoss(20 * delta_time)`, not `L.adjustFireLoss(20)`. This way, the damage per second stays constant even if the wait of the subsystem is changed
* - Probability of something happening, do `if(DT_PROB(25, delta_time))`, not `if(prob(25))`. This way, if the subsystem wait is e.g. lowered, there won't be a higher chance of this event happening per second
*
* If you override this do not call parent, as it will return PROCESS_KILL. This is done to prevent objects that dont override process() from staying in the processing list
*/
/datum/proc/process(delta_time)
set waitfor = FALSE
return PROCESS_KILL

View File

@@ -5,8 +5,8 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
name = "Quirks"
init_order = INIT_ORDER_QUIRKS
flags = SS_BACKGROUND
wait = 10
runlevels = RUNLEVEL_GAME
wait = 1 SECONDS
var/list/quirks = list() //Assoc. list of all roundstart quirk datum types; "name" = /path/
var/list/quirk_names_by_path = list()

View File

@@ -18,7 +18,7 @@ SUBSYSTEM_DEF(profiler)
if(CONFIG_GET(flag/auto_profile))
StartProfiling()
else
StopProfiling() //Stop the early start from world/New
StopProfiling() //Stop the early start profiler
return ..()
/datum/controller/subsystem/profiler/fire()
@@ -31,12 +31,23 @@ SUBSYSTEM_DEF(profiler)
return ..()
/datum/controller/subsystem/profiler/proc/StartProfiling()
#if DM_BUILD < 1506
stack_trace("Auto profiling unsupported on this byond version")
CONFIG_SET(flag/auto_profile, FALSE)
#else
world.Profile(PROFILE_START)
#endif
/datum/controller/subsystem/profiler/proc/StopProfiling()
#if DM_BUILD >= 1506
world.Profile(PROFILE_STOP)
#endif
/datum/controller/subsystem/profiler/proc/DumpFile()
#if DM_BUILD < 1506
stack_trace("Auto profiling unsupported on this byond version")
CONFIG_SET(flag/auto_profile, FALSE)
#else
var/timer = TICK_USAGE_REAL
var/current_profile_data = world.Profile(PROFILE_REFRESH,format="json")
fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
@@ -49,3 +60,4 @@ SUBSYSTEM_DEF(profiler)
timer = TICK_USAGE_REAL
WRITE_FILE(json_file, current_profile_data)
write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
#endif

View File

@@ -1,6 +1,7 @@
PROCESSING_SUBSYSTEM_DEF(radiation)
name = "Radiation"
flags = SS_NO_INIT | SS_BACKGROUND
wait = 1 SECONDS
var/list/warned_atoms = list()
@@ -13,5 +14,5 @@ PROCESSING_SUBSYSTEM_DEF(radiation)
warned_atoms[ref] = TRUE
var/atom/master = contamination.parent
SSblackbox.record_feedback("tally", "contaminated", 1, master.type)
var/msg = "has become contamintaed with enough radiation to contaminate other objects. || Source: [contamination.source] || Strength: [contamination.strength]"
var/msg = "has become contaminated with enough radiation to contaminate other objects. || Source: [contamination.source] || Strength: [contamination.strength]"
master.investigate_log(msg, INVESTIGATE_RADIATION)

View File

@@ -6,15 +6,15 @@
#define BUCKET_LIMIT (world.time + TICKS2DS(min(BUCKET_LEN - (SSrunechat.practical_offset - DS2TICKS(world.time - SSrunechat.head_offset)) - 1, BUCKET_LEN - 1)))
/**
* # Runechat Subsystem
*
* Maintains a timer-like system to handle destruction of runechat messages. Much of this code is modeled
* after or adapted from the timer subsystem.
*
* Note that this has the same structure for storing and queueing messages as the timer subsystem does
* for handling timers: the bucket_list is a list of chatmessage datums, each of which are the head
* of a circularly linked list. Any given index in bucket_list could be null, representing an empty bucket.
*/
* # Runechat Subsystem
*
* Maintains a timer-like system to handle destruction of runechat messages. Much of this code is modeled
* after or adapted from the timer subsystem.
*
* Note that this has the same structure for storing and queueing messages as the timer subsystem does
* for handling timers: the bucket_list is a list of chatmessage datums, each of which are the head
* of a circularly linked list. Any given index in bucket_list could be null, representing an empty bucket.
*/
SUBSYSTEM_DEF(runechat)
name = "Runechat"
flags = SS_TICKER | SS_NO_INIT
@@ -131,14 +131,14 @@ SUBSYSTEM_DEF(runechat)
bucket_resolution = world.tick_lag
/**
* Enters the runechat subsystem with this chatmessage, inserting it into the end-of-life queue
*
* This will also account for a chatmessage already being registered, and in which case
* the position will be updated to remove it from the previous location if necessary
*
* Arguments:
* * new_sched_destruction Optional, when provided is used to update an existing message with the new specified time
*/
* Enters the runechat subsystem with this chatmessage, inserting it into the end-of-life queue
*
* This will also account for a chatmessage already being registered, and in which case
* the position will be updated to remove it from the previous location if necessary
*
* Arguments:
* * new_sched_destruction Optional, when provided is used to update an existing message with the new specified time
*/
/datum/chatmessage/proc/enter_subsystem(new_sched_destruction = 0)
// Get local references from subsystem as they are faster to access than the datum references
var/list/bucket_list = SSrunechat.bucket_list
@@ -169,7 +169,7 @@ SUBSYSTEM_DEF(runechat)
// Handle insertion into the secondary queue if the required time is outside our tracked amounts
if (scheduled_destruction >= BUCKET_LIMIT)
BINARY_INSERT(src, SSrunechat.second_queue, datum/chatmessage, src, scheduled_destruction, COMPARE_KEY)
BINARY_INSERT(src, SSrunechat.second_queue, /datum/chatmessage, src, scheduled_destruction, COMPARE_KEY)
return
// Get bucket position and a local reference to the datum var, it's faster to access this way
@@ -194,8 +194,8 @@ SUBSYSTEM_DEF(runechat)
/**
* Removes this chatmessage datum from the runechat subsystem
*/
* Removes this chatmessage datum from the runechat subsystem
*/
/datum/chatmessage/proc/leave_subsystem()
// Attempt to find the bucket that contains this chat message
var/bucket_pos = BUCKET_POS(scheduled_destruction)

View File

@@ -56,12 +56,13 @@ SUBSYSTEM_DEF(server_maint)
for(var/I in currentrun)
var/client/C = I
//handle kicking inactive players
if(round_started && kick_inactive && C.is_afk(afk_period))
if(round_started && kick_inactive && !C.holder && C.is_afk(afk_period))
var/cmob = C.mob
if(!(isobserver(cmob) || (isdead(cmob) && C.holder)))
if (!isnewplayer(cmob) || !SSticker.queued_players.Find(cmob))
log_access("AFK: [key_name(C)]")
to_chat(C, "<span class='danger'>You have been inactive for more than [DisplayTimeText(afk_period)] and have been disconnected.</span>")
qdel(C)
to_chat(C, "<span class='userdanger'>You have been inactive for more than [DisplayTimeText(afk_period)] and have been disconnected.</span><br><span class='danger'>You may reconnect via the button in the file menu or by <b><u><a href='byond://winset?command=.reconnect'>clicking here to reconnect</a></u></b>.</span>")
QDEL_IN(C, 1) //to ensure they get our message before getting disconnected
continue
if (!(!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1)))
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*TICK_USAGE_REAL/100]")
@@ -83,4 +84,15 @@ SUBSYSTEM_DEF(server_maint)
if(tgsversion)
SSblackbox.record_feedback("text", "server_tools", 1, tgsversion.raw_parameter)
/datum/controller/subsystem/server_maint/proc/UpdateHubStatus()
// if(!CONFIG_GET(flag/hub) || !CONFIG_GET(number/max_hub_pop))
// return FALSE //no point, hub / auto hub controls are disabled
// var/max_pop = CONFIG_GET(number/max_hub_pop)
// if(GLOB.clients.len > max_pop)
// world.update_hub_visibility(FALSE)
// else
// world.update_hub_visibility(TRUE)
#undef PING_BUFFER_TIME

View File

@@ -5,34 +5,48 @@ SUBSYSTEM_DEF(sounds)
flags = SS_NO_FIRE
init_order = INIT_ORDER_SOUNDS
var/static/using_channels_max = CHANNEL_HIGHEST_AVAILABLE //BYOND max channels
/// Amount of channels to reserve for random usage rather than reservations being allowed to reserve all channels. Also a nice safeguard for when someone screws up.
var/static/random_channels_min = 50
// Hey uh these two needs to be initialized fast because the whole "things get deleted before init" thing.
/// Assoc list, "[channel]" = either the datum using it or TRUE for an unsafe-reserved (datumless reservation) channel
var/list/using_channels = list()
/// Assoc list, `"[channel]" =` either the datum using it or TRUE for an unsafe-reserved (datumless reservation) channel
var/list/using_channels
/// Assoc list datum = list(channel1, channel2, ...) for what channels something reserved.
var/list/using_channels_by_datum = list()
/// List of all available channels with associations set to TRUE for fast lookups/allocation.
var/list/available_channels
var/list/using_channels_by_datum
// Special datastructure for fast channel management
/// List of all channels as numbers
var/list/channel_list
/// Associative list of all reserved channels associated to their position. `"[channel_number]" =` index as number
var/list/reserved_channels
/// lower iteration position - Incremented and looped to get "random" sound channels for normal sounds. The channel at this index is returned when asking for a random channel.
var/channel_random_low
/// higher reserve position - decremented and incremented to reserve sound channels, anything above this is reserved. The channel at this index is the highest unreserved channel.
var/channel_reserve_high
/datum/controller/subsystem/sounds/Initialize()
setup_available_channels()
return ..()
/datum/controller/subsystem/sounds/proc/setup_available_channels()
available_channels = list()
channel_list = list()
reserved_channels = list()
using_channels = list()
using_channels_by_datum = list()
for(var/i in 1 to using_channels_max)
available_channels[num2text(i)] = TRUE
channel_list += i
channel_random_low = 1
channel_reserve_high = length(channel_list)
/// Removes a channel from using list.
/datum/controller/subsystem/sounds/proc/free_sound_channel(channel)
channel = num2text(channel)
var/using = using_channels[channel]
using_channels -= channel
if(using)
var/text_channel = num2text(channel)
var/using = using_channels[text_channel]
using_channels -= text_channel
if(using != TRUE) // datum channel
using_channels_by_datum[using] -= channel
if(!length(using_channels_by_datum[using]))
using_channels_by_datum -= using
available_channels[channel] = TRUE
free_channel(channel)
/// Frees all the channels a datum is using.
/datum/controller/subsystem/sounds/proc/free_datum_channels(datum/D)
@@ -40,8 +54,8 @@ SUBSYSTEM_DEF(sounds)
if(!L)
return
for(var/channel in L)
using_channels -= channel
available_channels[channel] = TRUE
using_channels -= num2text(channel)
free_channel(channel)
using_channels_by_datum -= D
/// Frees all datumless channels
@@ -50,42 +64,72 @@ SUBSYSTEM_DEF(sounds)
/// NO AUTOMATIC CLEANUP - If you use this, you better manually free it later! Returns an integer for channel.
/datum/controller/subsystem/sounds/proc/reserve_sound_channel_datumless()
var/channel = random_available_channel_text()
if(!channel) //oh no..
. = reserve_channel()
if(!.) //oh no..
return FALSE
available_channels -= channel
using_channels[channel] = DATUMLESS
var/text_channel = num2text(.)
using_channels[text_channel] = DATUMLESS
LAZYINITLIST(using_channels_by_datum[DATUMLESS])
using_channels_by_datum[DATUMLESS] += channel
return text2num(channel)
using_channels_by_datum[DATUMLESS] += .
/// Reserves a channel for a datum. Automatic cleanup only when the datum is deleted. Returns an integer for channel.
/datum/controller/subsystem/sounds/proc/reserve_sound_channel(datum/D)
if(!D) //i don't like typechecks but someone will fuck it up
CRASH("Attempted to reserve sound channel without datum using the managed proc.")
var/channel = random_available_channel_text()
if(!channel)
.= reserve_channel()
if(!.)
return FALSE
available_channels -= channel
using_channels[channel] = D
var/text_channel = num2text(.)
using_channels[text_channel] = D
LAZYINITLIST(using_channels_by_datum[D])
using_channels_by_datum[D] += channel
return text2num(channel)
using_channels_by_datum[D] += .
/**
* Reserves a channel and updates the datastructure. Private proc.
*/
/datum/controller/subsystem/sounds/proc/reserve_channel()
PRIVATE_PROC(TRUE)
if(channel_reserve_high <= random_channels_min) // out of channels
return
var/channel = channel_list[channel_reserve_high]
reserved_channels[num2text(channel)] = channel_reserve_high--
return channel
/**
* Frees a channel and updates the datastructure. Private proc.
*/
/datum/controller/subsystem/sounds/proc/free_channel(number)
PRIVATE_PROC(TRUE)
var/text_channel = num2text(number)
var/index = reserved_channels[text_channel]
if(!index)
CRASH("Attempted to (internally) free a channel that wasn't reserved.")
reserved_channels -= text_channel
// push reserve index up, which makes it now on a channel that is reserved
channel_reserve_high++
// swap the reserved channel wtih the unreserved channel so the reserve index is now on an unoccupied channel and the freed channel is next to be used.
channel_list.Swap(channel_reserve_high, index)
// now, an existing reserved channel will likely (exception: unreserving last reserved channel) be at index
// get it, and update position.
var/text_reserved = num2text(channel_list[index])
if(!reserved_channels[text_reserved]) //if it isn't already reserved make sure we don't accidently mistakenly put it on reserved list!
return
reserved_channels[text_reserved] = index
/// Random available channel, returns text.
/datum/controller/subsystem/sounds/proc/random_available_channel_text()
return pick(available_channels)
if(channel_random_low > channel_reserve_high)
channel_random_low = 1
. = "[channel_list[channel_random_low++]]"
/// Random available channel, returns number
/datum/controller/subsystem/sounds/proc/random_available_channel()
return text2num(pick(available_channels))
/// If a channel is available
/datum/controller/subsystem/sounds/proc/is_channel_available(channel)
return available_channels[num2text(channel)]
if(channel_random_low > channel_reserve_high)
channel_random_low = 1
. = channel_list[channel_random_low++]
/// How many channels we have left.
/datum/controller/subsystem/sounds/proc/available_channels_left()
return length(available_channels)
return length(channel_list) - random_channels_min
#undef DATUMLESS

View File

@@ -13,7 +13,7 @@ SUBSYSTEM_DEF(spacedrift)
return ..()
/datum/controller/subsystem/spacedrift/fire(resumed = 0)
/datum/controller/subsystem/spacedrift/fire(resumed = FALSE)
if (!resumed)
src.currentrun = processing.Copy()
@@ -47,6 +47,7 @@ SUBSYSTEM_DEF(spacedrift)
var/old_dir = AM.dir
var/old_loc = AM.loc
AM.inertia_moving = TRUE
AM.set_glide_size(DELAY_TO_GLIDE_SIZE(AM.inertia_move_delay), FALSE)
step(AM, AM.inertia_dir)
AM.inertia_moving = FALSE
AM.inertia_next_move = world.time + AM.inertia_move_delay

View File

@@ -203,3 +203,4 @@ SUBSYSTEM_DEF(statpanels)
set hidden = TRUE
statbrowser_ready = TRUE
init_verbs()

View File

@@ -1,34 +1,231 @@
SUBSYSTEM_DEF(stickyban)
name = "Sticky Ban"
name = "PRISM"
init_order = INIT_ORDER_STICKY_BAN
flags = SS_NO_FIRE
var/list/cache = list()
var/list/dbcache = list()
var/list/confirmed_exempt = list()
var/dbcacheexpire = 0
/datum/controller/subsystem/stickyban/Initialize(timeofday)
var/list/bannedkeys = world.GetConfig("ban")
if (length(GLOB.stickybanadminexemptions))
restore_stickybans()
var/list/bannedkeys = sticky_banned_ckeys()
//sanitize the sticky ban list
//delete db bans that no longer exist in the database and add new legacy bans to the database
if (SSdbcore.Connect() || length(SSstickyban.dbcache))
if (length(GLOB.stickybanadminexemptions))
restore_stickybans()
for (var/oldban in (world.GetConfig("ban") - bannedkeys))
var/ckey = ckey(oldban)
if (ckey != oldban && (ckey in bannedkeys))
continue
var/list/ban = params2list(world.GetConfig("ban", oldban))
if (ban && !ban["fromdb"])
if (!import_raw_stickyban_to_db(ckey, ban))
log_world("Could not import stickyban on [oldban] into the database. Ignoring")
continue
dbcacheexpire = 0
bannedkeys += ckey
world.SetConfig("ban", oldban, null)
if (length(GLOB.stickybanadminexemptions)) //the previous loop can sleep
restore_stickybans()
for (var/bannedkey in bannedkeys)
var/ckey = ckey(bannedkey)
var/list/ban = stickyban2list(world.GetConfig("ban", bannedkey))
var/list/ban = get_stickyban_from_ckey(bannedkey)
//byond stores sticky bans by key, that can end up confusing things
//i also remove it here so that if any stickybans cause a runtime, they just stop existing
world.SetConfig("ban", bannedkey, null)
//byond stores sticky bans by key, that's lame
if (ckey != bannedkey)
world.SetConfig("ban", bannedkey, null)
if (!ban["ckey"])
ban["ckey"] = ckey
//storing these can break things and isn't needed for sticky ban tracking
ban -= "IP"
ban -= "computer_id"
ban["matches_this_round"] = list()
ban["existing_user_matches_this_round"] = list()
ban["admin_matches_this_round"] = list()
ban["pending_matches_this_round"] = list()
cache[ckey] = ban
for (var/bannedckey in cache)
world.SetConfig("ban", bannedckey, list2stickyban(cache[bannedckey]))
world.SetConfig("ban", ckey, list2stickyban(ban))
return ..()
/datum/controller/subsystem/stickyban/proc/Populatedbcache()
var/newdbcache = list() //so if we runtime or the db connection dies we don't kill the existing cache
// var/datum/db_query/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey")
// var/datum/db_query/query_ckey_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, last_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched")
// var/datum/db_query/query_cid_matches = SSdbcore.NewQuery("SELECT stickyban, matched_cid, first_matched, last_matched FROM [format_table_name("stickyban_matched_cid")] ORDER BY first_matched")
// var/datum/db_query/query_ip_matches = SSdbcore.NewQuery("SELECT stickyban, INET_NTOA(matched_ip), first_matched, last_matched FROM [format_table_name("stickyban_matched_ip")] ORDER BY first_matched")
var/datum/DBQuery/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey")
var/datum/DBQuery/query_ckey_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, last_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched")
var/datum/DBQuery/query_cid_matches = SSdbcore.NewQuery("SELECT stickyban, matched_cid, first_matched, last_matched FROM [format_table_name("stickyban_matched_cid")] ORDER BY first_matched")
var/datum/DBQuery/query_ip_matches = SSdbcore.NewQuery("SELECT stickyban, INET_NTOA(matched_ip), first_matched, last_matched FROM [format_table_name("stickyban_matched_ip")] ORDER BY first_matched")
SSdbcore.QuerySelect(list(query_stickybans, query_ckey_matches, query_cid_matches, query_ip_matches))
if (query_stickybans.last_error)
qdel(query_stickybans)
qdel(query_ckey_matches)
qdel(query_cid_matches)
qdel(query_ip_matches)
return
while (query_stickybans.NextRow())
var/list/ban = list()
ban["ckey"] = query_stickybans.item[1]
ban["message"] = query_stickybans.item[2]
ban["reason"] = "(InGameBan)([query_stickybans.item[3]])"
ban["admin"] = query_stickybans.item[3]
ban["datetime"] = query_stickybans.item[4]
ban["type"] = list("sticky")
newdbcache["[query_stickybans.item[1]]"] = ban
if (!query_ckey_matches.last_error)
while (query_ckey_matches.NextRow())
var/list/match = list()
match["stickyban"] = query_ckey_matches.item[1]
match["matched_ckey"] = query_ckey_matches.item[2]
match["first_matched"] = query_ckey_matches.item[3]
match["last_matched"] = query_ckey_matches.item[4]
match["exempt"] = text2num(query_ckey_matches.item[5])
var/ban = newdbcache[query_ckey_matches.item[1]]
if (!ban)
continue
var/keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"]
if (!keys)
keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"] = list()
keys[query_ckey_matches.item[2]] = match
if (!query_cid_matches.last_error)
while (query_cid_matches.NextRow())
var/list/match = list()
match["stickyban"] = query_cid_matches.item[1]
match["matched_cid"] = query_cid_matches.item[2]
match["first_matched"] = query_cid_matches.item[3]
match["last_matched"] = query_cid_matches.item[4]
var/ban = newdbcache[query_cid_matches.item[1]]
if (!ban)
continue
var/computer_ids = ban["computer_id"]
if (!computer_ids)
computer_ids = ban["computer_id"] = list()
computer_ids[query_cid_matches.item[2]] = match
if (!query_ip_matches.last_error)
while (query_ip_matches.NextRow())
var/list/match = list()
match["stickyban"] = query_ip_matches.item[1]
match["matched_ip"] = query_ip_matches.item[2]
match["first_matched"] = query_ip_matches.item[3]
match["last_matched"] = query_ip_matches.item[4]
var/ban = newdbcache[query_ip_matches.item[1]]
if (!ban)
continue
var/IPs = ban["IP"]
if (!IPs)
IPs = ban["IP"] = list()
IPs[query_ip_matches.item[2]] = match
dbcache = newdbcache
dbcacheexpire = world.time+STICKYBAN_DB_CACHE_TIME
qdel(query_stickybans)
qdel(query_ckey_matches)
qdel(query_cid_matches)
qdel(query_ip_matches)
/datum/controller/subsystem/stickyban/proc/import_raw_stickyban_to_db(ckey, list/ban)
. = FALSE
if (!ban["admin"])
ban["admin"] = "LEGACY"
if (!ban["message"])
ban["message"] = "Evasion"
// TODO: USE NEW DB IMPLEMENTATION
var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery(
"INSERT IGNORE INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES ([ckey], [ban["message"]], ban["admin"]))"
)
if (query_create_stickyban.warn_execute())
qdel(query_create_stickyban)
return
qdel(query_create_stickyban)
// var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery(
// "INSERT IGNORE INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES (:ckey, :message, :admin)",
// list("ckey" = ckey, "message" = ban["message"], "admin" = ban["admin"])
// )
// if (!query_create_stickyban.warn_execute())
// qdel(query_create_stickyban)
// return
// qdel(query_create_stickyban)
var/list/sqlckeys = list()
var/list/sqlcids = list()
var/list/sqlips = list()
if (ban["keys"])
var/list/keys = splittext(ban["keys"], ",")
for (var/key in keys)
var/list/sqlckey = list()
sqlckey["stickyban"] = ckey
sqlckey["matched_ckey"] = ckey(key)
sqlckey["exempt"] = FALSE
sqlckeys[++sqlckeys.len] = sqlckey
if (ban["whitelist"])
var/list/keys = splittext(ban["whitelist"], ",")
for (var/key in keys)
var/list/sqlckey = list()
sqlckey["stickyban"] = ckey
sqlckey["matched_ckey"] = ckey(key)
sqlckey["exempt"] = TRUE
sqlckeys[++sqlckeys.len] = sqlckey
if (ban["computer_id"])
var/list/cids = splittext(ban["computer_id"], ",")
for (var/cid in cids)
var/list/sqlcid = list()
sqlcid["stickyban"] = ckey
sqlcid["matched_cid"] = cid
sqlcids[++sqlcids.len] = sqlcid
if (ban["IP"])
var/list/ips = splittext(ban["IP"], ",")
for (var/ip in ips)
var/list/sqlip = list()
sqlip["stickyban"] = ckey
sqlip["matched_ip"] = ip
sqlips[++sqlips.len] = sqlip
if (length(sqlckeys))
SSdbcore.MassInsert(format_table_name("stickyban_matched_ckey"), sqlckeys, ignore_errors = TRUE)
if (length(sqlcids))
SSdbcore.MassInsert(format_table_name("stickyban_matched_cid"), sqlcids, ignore_errors = TRUE)
if (length(sqlips))
SSdbcore.MassInsert(format_table_name("stickyban_matched_ip"), sqlips, ignore_errors = TRUE)
return TRUE

View File

@@ -57,6 +57,7 @@ SUBSYSTEM_DEF(throwing)
var/dx
var/dy
var/force = MOVE_FORCE_DEFAULT
var/gentle = FALSE
var/pure_diagonal
var/diagonal_error
var/datum/callback/callback
@@ -64,15 +65,44 @@ SUBSYSTEM_DEF(throwing)
var/delayed_time = 0
var/last_move = 0
/datum/thrownthing/New(thrownthing, target, target_turf, init_dir, maxrange, speed, thrower, diagonals_first, force, gentle, callback, target_zone)
. = ..()
src.thrownthing = thrownthing
RegisterSignal(thrownthing, COMSIG_PARENT_QDELETING, .proc/on_thrownthing_qdel)
src.target = target
src.target_turf = target_turf
src.init_dir = init_dir
src.maxrange = maxrange
src.speed = speed
src.thrower = thrower
src.diagonals_first = diagonals_first
src.force = force
src.gentle = gentle
src.callback = callback
src.target_zone = target_zone
/datum/thrownthing/Destroy()
if(HAS_TRAIT_FROM(thrownthing, TRAIT_SPOOKY_THROW, "revenant"))
REMOVE_TRAIT(thrownthing, TRAIT_SPOOKY_THROW, "revenant")
SSthrowing.processing -= thrownthing
thrownthing.throwing = null
thrownthing = null
target = null
thrower = null
callback = null
if(callback)
QDEL_NULL(callback) //It stores a reference to the thrownthing, its source. Let's clean that.
return ..()
///Defines the datum behavior on the thrownthing's qdeletion event.
/datum/thrownthing/proc/on_thrownthing_qdel(atom/movable/source, force)
SIGNAL_HANDLER
qdel(src)
/datum/thrownthing/proc/tick()
var/atom/movable/AM = thrownthing
if (!isturf(AM.loc) || !AM.throwing)
@@ -112,7 +142,7 @@ SUBSYSTEM_DEF(throwing)
finalize()
return
AM.Move(step, get_dir(AM, step))
AM.Move(step, get_dir(AM, step), DELAY_TO_GLIDE_SIZE(1 / speed))
if (!AM.throwing) // we hit something during our move
finalize(hit = TRUE)
@@ -136,15 +166,21 @@ SUBSYSTEM_DEF(throwing)
if (A == target)
hit = TRUE
thrownthing.throw_impact(A, src)
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
return //deletion should already be handled by on_thrownthing_qdel()
break
if (!hit)
thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground.
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
return //deletion should already be handled by on_thrownthing_qdel()
thrownthing.newtonian_move(init_dir)
else
thrownthing.newtonian_move(init_dir)
if(target)
thrownthing.throw_impact(target, src)
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
return //deletion should already be handled by on_thrownthing_qdel()
if (callback)
callback.Invoke()

View File

@@ -1,7 +1,8 @@
SUBSYSTEM_DEF(time_track)
name = "Time Tracking"
wait = 1 SECONDS
flags = SS_NO_INIT|SS_NO_TICK_CHECK
wait = 10
flags = SS_NO_TICK_CHECK
init_order = INIT_ORDER_TIMETRACK
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/time_dilation_current = 0
@@ -16,33 +17,81 @@ SUBSYSTEM_DEF(time_track)
var/last_tick_byond_time = 0
var/last_tick_tickcount = 0
var/last_measurement = 0
var/measurement_delay = 60
var/stat_time_text
var/time_dilation_text
/datum/controller/subsystem/time_track/Initialize(start_timeofday)
. = ..()
GLOB.perf_log = "[GLOB.log_directory]/perf-[GLOB.round_id ? GLOB.round_id : "NULL"]-[SSmapping.config?.map_name].csv"
log_perf(
list(
"time",
"players",
"tidi",
"tidi_fastavg",
"tidi_avg",
"tidi_slowavg",
"maptick",
"num_timers",
"air_turf_cost",
"air_eg_cost",
"air_highpressure_cost",
"air_hotspots_cost",
"air_superconductivity_cost",
"air_pipenets_cost",
"air_rebuilds_cost",
"air_turf_count",
"air_eg_count",
"air_hotspot_count",
"air_network_count",
"air_delta_count",
"air_superconductive_count"
)
)
/datum/controller/subsystem/time_track/fire()
stat_time_text = "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]\n\nRound Time: [DisplayTimeText(world.time - SSticker.round_start_time, 1)] \n\nStation Time: [STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]\n\n[time_dilation_text]"
if(++last_measurement == measurement_delay)
last_measurement = 0
var/current_realtime = REALTIMEOFDAY
var/current_byondtime = world.time
var/current_tickcount = world.time/world.tick_lag
var/current_realtime = REALTIMEOFDAY
var/current_byondtime = world.time
var/current_tickcount = world.time/world.tick_lag
GLOB.glide_size_multiplier = (current_byondtime - last_tick_byond_time) / (current_realtime - last_tick_realtime)
if (!first_run)
var/tick_drift = max(0, (((current_realtime - last_tick_realtime) - (current_byondtime - last_tick_byond_time)) / world.tick_lag))
if(times_fired % 10) // everything else is once every 10 seconds
return
time_dilation_current = tick_drift / (current_tickcount - last_tick_tickcount) * 100
if (!first_run)
var/tick_drift = max(0, (((current_realtime - last_tick_realtime) - (current_byondtime - last_tick_byond_time)) / world.tick_lag))
time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current)
time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast)
time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg)
else
first_run = FALSE
last_tick_realtime = current_realtime
last_tick_byond_time = current_byondtime
last_tick_tickcount = current_tickcount
SSblackbox.record_feedback("associative", "time_dilation_current", 1, list("[SQLtime()]" = list("current" = "[time_dilation_current]", "avg_fast" = "[time_dilation_avg_fast]", "avg" = "[time_dilation_avg]", "avg_slow" = "[time_dilation_avg_slow]")))
time_dilation_text = "Time Dilation: [round(time_dilation_current,1)]% AVG:([round(time_dilation_avg_fast,1)]%, [round(time_dilation_avg,1)]%, [round(time_dilation_avg_slow,1)]%)"
time_dilation_current = tick_drift / (current_tickcount - last_tick_tickcount) * 100
time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current)
time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast)
time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg)
else
first_run = FALSE
last_tick_realtime = current_realtime
last_tick_byond_time = current_byondtime
last_tick_tickcount = current_tickcount
SSblackbox.record_feedback("associative", "time_dilation_current", 1, list("[SQLtime()]" = list("current" = "[time_dilation_current]", "avg_fast" = "[time_dilation_avg_fast]", "avg" = "[time_dilation_avg]", "avg_slow" = "[time_dilation_avg_slow]")))
log_perf(
list(
world.time,
length(GLOB.clients),
time_dilation_current,
time_dilation_avg_fast,
time_dilation_avg,
time_dilation_avg_slow,
MAPTICK_LAST_INTERNAL_TICK_USAGE,
length(SStimer.timer_id_dict),
SSair.cost_turfs,
SSair.cost_groups,
SSair.cost_highpressure,
SSair.cost_hotspots,
SSair.cost_superconductivity,
SSair.cost_pipenets,
SSair.cost_rebuilds,
SSair.get_active_turfs(), //does not return a list, which is what we want
SSair.get_amt_excited_groups(),
length(SSair.hotspots),
length(SSair.networks),
length(SSair.high_pressure_delta),
length(SSair.active_super_conductivity)
)
)

View File

@@ -1,31 +1,51 @@
#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth)
/// Controls how many buckets should be kept, each representing a tick. (1 minutes worth)
#define BUCKET_LEN (world.fps*1*60)
/// Helper for getting the correct bucket for a given timer
#define BUCKET_POS(timer) (((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag)+1) % BUCKET_LEN)||BUCKET_LEN)
/// Gets the maximum time at which timers will be invoked from buckets, used for deferring to secondary queue
#define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1)))
#define TIMER_ID_MAX (2**24) //max float with integer precision
/// Max float with integer precision
#define TIMER_ID_MAX (2**24)
/**
* # Timer Subsystem
*
* Handles creation, callbacks, and destruction of timed events.
*
* It is important to understand the buckets used in the timer subsystem are just a series of circular doubly-linked
* lists. The object at a given index in bucket_list is a /datum/timedevent, the head of a circular list, which has prev
* and next references for the respective elements in that bucket's circular list.
*/
SUBSYSTEM_DEF(timer)
name = "Timer"
wait = 1 //SS_TICKER subsystem, so wait is in ticks
wait = 1 // SS_TICKER subsystem, so wait is in ticks
init_order = INIT_ORDER_TIMER
priority = FIRE_PRIORITY_TIMER
flags = SS_TICKER|SS_NO_INIT
var/list/datum/timedevent/second_queue = list() //awe, yes, you've had first queue, but what about second queue?
/// Queue used for storing timers that do not fit into the current buckets
var/list/datum/timedevent/second_queue = list()
/// A hashlist dictionary used for storing unique timers
var/list/hashes = list()
var/head_offset = 0 //world.time of the first entry in the the bucket.
var/practical_offset = 1 //index of the first non-empty item in the bucket.
var/bucket_resolution = 0 //world.tick_lag the bucket was designed for
var/bucket_count = 0 //how many timers are in the buckets
var/list/bucket_list = list() //list of buckets, each bucket holds every timer that has to run that byond tick.
var/list/timer_id_dict = list() //list of all active timers assoicated to their timer id (for easy lookup)
var/list/clienttime_timers = list() //special snowflake timers that run on fancy pansy "client time"
/// world.time of the first entry in the bucket list, effectively the 'start time' of the current buckets
var/head_offset = 0
/// Index of the wrap around pivot for buckets. buckets before this are later running buckets wrapped around from the end of the bucket list.
var/practical_offset = 1
/// world.tick_lag the bucket was designed for
var/bucket_resolution = 0
/// How many timers are in the buckets
var/bucket_count = 0
/// List of buckets, each bucket holds every timer that has to run that byond tick
var/list/bucket_list = list()
/// List of all active timers associated to their timer ID (for easy lookup)
var/list/timer_id_dict = list()
/// Special timers that run in real-time, not BYOND time; these are more expensive to run and maintain
var/list/clienttime_timers = list()
/// Contains the last time that a timer's callback was invoked, or the last tick the SS fired if no timers are being processed
var/last_invoke_tick = 0
/// Contains the last time that a warning was issued for not invoking callbacks
var/static/last_invoke_warning = 0
/// Boolean operator controlling if the timer SS will automatically reset buckets if it fails to invoke callbacks for an extended period of time
var/static/bucket_auto_reset = TRUE
/datum/controller/subsystem/timer/PreInit()
@@ -38,44 +58,53 @@ SUBSYSTEM_DEF(timer)
return ..()
/datum/controller/subsystem/timer/fire(resumed = FALSE)
// Store local references to datum vars as it is faster to access them
var/lit = last_invoke_tick
var/last_check = world.time - TICKS2DS(BUCKET_LEN*1.5)
var/list/bucket_list = src.bucket_list
var/last_check = world.time - TICKS2DS(BUCKET_LEN * 1.5)
// If there are no timers being tracked, then consider now to be the last invoked time
if(!bucket_count)
last_invoke_tick = world.time
// Check that we have invoked a callback in the last 1.5 minutes of BYOND time,
// and throw a warning and reset buckets if this is true
if(lit && lit < last_check && head_offset < last_check && last_invoke_warning < last_check)
last_invoke_warning = world.time
var/msg = "No regular timers processed in the last [BUCKET_LEN*1.5] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!"
var/msg = "No regular timers processed in the last [BUCKET_LEN * 1.5] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!"
message_admins(msg)
WARNING(msg)
if(bucket_auto_reset)
bucket_resolution = 0
log_world("Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
var/list/to_log = list("Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
for (var/i in 1 to length(bucket_list))
var/datum/timedevent/bucket_head = bucket_list[i]
if (!bucket_head)
continue
log_world("Active timers at index [i]:")
to_log += "Active timers at index [i]:"
var/datum/timedevent/bucket_node = bucket_head
var/anti_loop_check = 1000
do
log_world(get_timer_debug_string(bucket_node))
to_log += get_timer_debug_string(bucket_node)
bucket_node = bucket_node.next
anti_loop_check--
while(bucket_node && bucket_node != bucket_head && anti_loop_check)
log_world("Active timers in the second_queue queue:")
to_log += "Active timers in the second_queue queue:"
for(var/I in second_queue)
log_world(get_timer_debug_string(I))
to_log += get_timer_debug_string(I)
var/next_clienttime_timer_index = 0
var/len = length(clienttime_timers)
// Dump all the logged data to the world log
log_world(to_log.Join("\n"))
for (next_clienttime_timer_index in 1 to len)
// Process client-time timers
var/static/next_clienttime_timer_index = 0
if (next_clienttime_timer_index)
clienttime_timers.Cut(1, next_clienttime_timer_index+1)
next_clienttime_timer_index = 0
for (next_clienttime_timer_index in 1 to length(clienttime_timers))
if (MC_TICK_CHECK)
next_clienttime_timer_index--
break
@@ -86,8 +115,8 @@ SUBSYSTEM_DEF(timer)
var/datum/callback/callBack = ctime_timer.callBack
if (!callBack)
clienttime_timers.Cut(next_clienttime_timer_index,next_clienttime_timer_index+1)
CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]")
CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], \
head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]")
ctime_timer.spent = REALTIMEOFDAY
callBack.InvokeAsync()
@@ -95,135 +124,93 @@ SUBSYSTEM_DEF(timer)
if(ctime_timer.flags & TIMER_LOOP)
ctime_timer.spent = 0
ctime_timer.timeToRun = REALTIMEOFDAY + ctime_timer.wait
BINARY_INSERT(ctime_timer, clienttime_timers, datum/timedevent, ctime_timer, timeToRun, COMPARE_KEY)
BINARY_INSERT(ctime_timer, clienttime_timers, /datum/timedevent, ctime_timer, timeToRun, COMPARE_KEY)
else
qdel(ctime_timer)
// Remove invoked client-time timers
if (next_clienttime_timer_index)
clienttime_timers.Cut(1, next_clienttime_timer_index+1)
next_clienttime_timer_index = 0
if (MC_TICK_CHECK)
return
var/static/list/spent = list()
var/static/datum/timedevent/timer
// Check for when we need to loop the buckets, this occurs when
// the head_offset is approaching BUCKET_LEN ticks in the past
if (practical_offset > BUCKET_LEN)
head_offset += TICKS2DS(BUCKET_LEN)
practical_offset = 1
resumed = FALSE
// Check for when we have to reset buckets, typically from auto-reset
if ((length(bucket_list) != BUCKET_LEN) || (world.tick_lag != bucket_resolution))
reset_buckets()
bucket_list = src.bucket_list
resumed = FALSE
if (!resumed)
timer = null
while (practical_offset <= BUCKET_LEN && head_offset + ((practical_offset-1)*world.tick_lag) <= world.time)
var/datum/timedevent/head = bucket_list[practical_offset]
if (!timer || !head || timer == head)
head = bucket_list[practical_offset]
timer = head
while (timer)
// Iterate through each bucket starting from the practical offset
while (practical_offset <= BUCKET_LEN && head_offset + ((practical_offset - 1) * world.tick_lag) <= world.time)
var/datum/timedevent/timer
while ((timer = bucket_list[practical_offset]))
var/datum/callback/callBack = timer.callBack
if (!callBack)
bucket_resolution = null //force bucket recreation
CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
bucket_resolution = null // force bucket recreation
CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], \
head_offset: [head_offset], practical_offset: [practical_offset]")
timer.bucketEject() //pop the timer off of the bucket list.
// Invoke callback if possible
if (!timer.spent)
spent += timer
timer.spent = world.time
callBack.InvokeAsync()
last_invoke_tick = world.time
if (MC_TICK_CHECK)
return
timer = timer.next
if (timer == head)
break
bucket_list[practical_offset++] = null
//we freed up a bucket, lets see if anything in second_queue needs to be shifted to that bucket.
var/i = 0
var/L = length(second_queue)
for (i in 1 to L)
timer = second_queue[i]
if (timer.timeToRun >= TIMER_MAX)
i--
break
if (timer.timeToRun < head_offset)
bucket_resolution = null //force bucket recreation
stack_trace("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if (timer.callBack && !timer.spent)
timer.callBack.InvokeAsync()
spent += timer
bucket_count++
else if(!QDELETED(timer))
qdel(timer)
continue
if (timer.timeToRun < head_offset + TICKS2DS(practical_offset-1))
bucket_resolution = null //force bucket recreation
stack_trace("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if (timer.callBack && !timer.spent)
timer.callBack.InvokeAsync()
spent += timer
bucket_count++
else if(!QDELETED(timer))
qdel(timer)
continue
bucket_count++
var/bucket_pos = max(1, BUCKET_POS(timer))
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
if (!bucket_head)
bucket_list[bucket_pos] = timer
timer.next = null
timer.prev = null
continue
if (!bucket_head.prev)
bucket_head.prev = bucket_head
timer.next = bucket_head
timer.prev = bucket_head.prev
timer.next.prev = timer
timer.prev.next = timer
if (i)
second_queue.Cut(1, i+1)
timer = null
bucket_count -= length(spent)
for (var/i in spent)
var/datum/timedevent/qtimer = i
if(QDELETED(qtimer))
bucket_count++
continue
if(!(qtimer.flags & TIMER_LOOP))
qdel(qtimer)
else
bucket_count++
qtimer.spent = 0
qtimer.bucketEject()
if(qtimer.flags & TIMER_CLIENT_TIME)
qtimer.timeToRun = REALTIMEOFDAY + qtimer.wait
if (timer.flags & TIMER_LOOP) // Prepare looping timers to re-enter the queue
timer.spent = 0
timer.timeToRun = world.time + timer.wait
timer.bucketJoin()
else
qtimer.timeToRun = world.time + qtimer.wait
qtimer.bucketJoin()
qdel(timer)
spent.len = 0
if (MC_TICK_CHECK)
break
//formated this way to be runtime resistant
if (!bucket_list[practical_offset])
// Empty the bucket, check if anything in the secondary queue should be shifted to this bucket
bucket_list[practical_offset++] = null
var/i = 0
for (i in 1 to length(second_queue))
timer = second_queue[i]
if (timer.timeToRun >= TIMER_MAX)
i--
break
// Check for timers that are scheduled to run in the past
if (timer.timeToRun < head_offset)
bucket_resolution = null // force bucket recreation
stack_trace("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. \
[get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
break
// Check for timers that are not capable of being scheduled to run without rebuilding buckets
if (timer.timeToRun < head_offset + TICKS2DS(practical_offset - 1))
bucket_resolution = null // force bucket recreation
stack_trace("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to \
short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
break
timer.bucketJoin()
if (i)
second_queue.Cut(1, i+1)
if (MC_TICK_CHECK)
break
/**
* Generates a string with details about the timed event for debugging purposes
*/
/datum/controller/subsystem/timer/proc/get_timer_debug_string(datum/timedevent/TE)
. = "Timer: [TE]"
. += "Prev: [TE.prev ? TE.prev : "NULL"], Next: [TE.next ? TE.next : "NULL"]"
@@ -234,12 +221,16 @@ SUBSYSTEM_DEF(timer)
if(!TE.callBack)
. += ", NO CALLBACK"
/**
* Destroys the existing buckets and creates new buckets from the existing timed events
*/
/datum/controller/subsystem/timer/proc/reset_buckets()
var/list/bucket_list = src.bucket_list
var/list/bucket_list = src.bucket_list // Store local reference to datum var, this is faster
var/list/alltimers = list()
//collect the timers currently in the bucket
// Get all timers currently in the buckets
for (var/bucket_head in bucket_list)
if (!bucket_head)
if (!bucket_head) // if bucket is empty for this tick
continue
var/datum/timedevent/bucket_node = bucket_head
do
@@ -247,25 +238,38 @@ SUBSYSTEM_DEF(timer)
bucket_node = bucket_node.next
while(bucket_node && bucket_node != bucket_head)
// Empty the list by zeroing and re-assigning the length
bucket_list.len = 0
bucket_list.len = BUCKET_LEN
// Reset values for the subsystem to their initial values
practical_offset = 1
bucket_count = 0
head_offset = world.time
bucket_resolution = world.tick_lag
// Add all timed events from the secondary queue as well
alltimers += second_queue
// If there are no timers being tracked by the subsystem,
// there is no need to do any further rebuilding
if (!length(alltimers))
return
// Sort all timers by time to run
sortTim(alltimers, .proc/cmp_timer)
// Get the earliest timer, and if the TTR is earlier than the current world.time,
// then set the head offset appropriately to be the earliest time tracked by the
// current set of buckets
var/datum/timedevent/head = alltimers[1]
if (head.timeToRun < head_offset)
head_offset = head.timeToRun
// Iterate through each timed event and insert it into an appropriate bucket,
// up unto the point that we can no longer insert into buckets as the TTR
// is outside the range we are tracking, then insert the remainder into the
// secondary queue
var/new_bucket_count
var/i = 1
for (i in 1 to length(alltimers))
@@ -273,34 +277,38 @@ SUBSYSTEM_DEF(timer)
if (!timer)
continue
var/bucket_pos = BUCKET_POS(timer)
// Check that the TTR is within the range covered by buckets, when exceeded we've finished
if (timer.timeToRun >= TIMER_MAX)
i--
break
// Check that timer has a valid callback and hasn't been invoked
if (!timer.callBack || timer.spent)
WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], \
head_offset: [head_offset], practical_offset: [practical_offset]")
if (timer.callBack)
qdel(timer)
continue
// Insert the timer into the bucket, and perform necessary circular doubly-linked list operations
new_bucket_count++
var/bucket_pos = BUCKET_POS(timer)
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
if (!bucket_head)
bucket_list[bucket_pos] = timer
timer.next = null
timer.prev = null
continue
if (!bucket_head.prev)
bucket_head.prev = bucket_head
timer.next = bucket_head
timer.prev = bucket_head.prev
timer.next.prev = timer
timer.prev.next = timer
// Cut the timers that are tracked by the buckets from the secondary queue
if (i)
alltimers.Cut(1, i+1)
alltimers.Cut(1, i + 1)
second_queue = alltimers
bucket_count = new_bucket_count
@@ -311,45 +319,64 @@ SUBSYSTEM_DEF(timer)
timer_id_dict |= SStimer.timer_id_dict
bucket_list |= SStimer.bucket_list
/**
* # Timed Event
*
* This is the actual timer, it contains the callback and necessary data to maintain
* the timer.
*
* See the documentation for the timer subsystem for an explanation of the buckets referenced
* below in next and prev
*/
/datum/timedevent
/// ID used for timers when the TIMER_STOPPABLE flag is present
var/id
/// The callback to invoke after the timer completes
var/datum/callback/callBack
/// The time at which the callback should be invoked at
var/timeToRun
/// The length of the timer
var/wait
/// Unique hash generated when TIMER_UNIQUE flag is present
var/hash
/// The source of the timedevent, whatever called addtimer
var/source
/// Flags associated with the timer, see _DEFINES/subsystems.dm
var/list/flags
var/spent = 0 //time we ran the timer.
var/name //for easy debugging.
//cicular doublely linked list
/// Time at which the timer was invoked or destroyed
var/spent = 0
/// An informative name generated for the timer as its representation in strings, useful for debugging
var/name
/// Next timed event in the bucket
var/datum/timedevent/next
/// Previous timed event in the bucket
var/datum/timedevent/prev
/datum/timedevent/New(datum/callback/callBack, wait, flags, hash)
/datum/timedevent/New(datum/callback/callBack, wait, flags, hash, source)
var/static/nextid = 1
id = TIMER_ID_NULL
src.callBack = callBack
src.wait = wait
src.flags = flags
src.hash = hash
src.source = source
if (flags & TIMER_CLIENT_TIME)
timeToRun = REALTIMEOFDAY + wait
else
timeToRun = world.time + wait
// Determine time at which the timer's callback should be invoked
timeToRun = (flags & TIMER_CLIENT_TIME ? REALTIMEOFDAY : world.time) + wait
// Include the timer in the hash table if the timer is unique
if (flags & TIMER_UNIQUE)
SStimer.hashes[hash] = src
// Generate ID for the timer if the timer is stoppable, include in the timer id dictionary
if (flags & TIMER_STOPPABLE)
id = num2text(nextid, 100)
if (nextid >= SHORT_REAL_LIMIT)
nextid += min(1, 2**round(nextid/SHORT_REAL_LIMIT))
nextid += min(1, 2 ** round(nextid / SHORT_REAL_LIMIT))
else
nextid++
SStimer.timer_id_dict[id] = src
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
if ((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME))
CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]")
@@ -390,23 +417,39 @@ SUBSYSTEM_DEF(timer)
prev = null
return QDEL_HINT_IWILLGC
/**
* Removes this timed event from any relevant buckets, or the secondary queue
*/
/datum/timedevent/proc/bucketEject()
// Attempt to find bucket that contains this timed event
var/bucketpos = BUCKET_POS(src)
// Store local references for the bucket list and secondary queue
// This is faster than referencing them from the datum itself
var/list/bucket_list = SStimer.bucket_list
var/list/second_queue = SStimer.second_queue
// Attempt to get the head of the bucket
var/datum/timedevent/buckethead
if(bucketpos > 0)
buckethead = bucket_list[bucketpos]
// Decrement the number of timers in buckets if the timed event is
// the head of the bucket, or has a TTR less than TIMER_MAX implying it fits
// into an existing bucket, or is otherwise not present in the secondary queue
if(buckethead == src)
bucket_list[bucketpos] = next
SStimer.bucket_count--
else if(timeToRun < TIMER_MAX || next || prev)
else if(timeToRun < TIMER_MAX)
SStimer.bucket_count--
else
var/l = length(second_queue)
second_queue -= src
if(l == length(second_queue))
SStimer.bucket_count--
// Remove the timed event from the bucket, ensuring to maintain
// the integrity of the bucket's list if relevant
if(prev != next)
prev.next = next
next.prev = prev
@@ -415,32 +458,47 @@ SUBSYSTEM_DEF(timer)
next?.prev = null
prev = next = null
/**
* Attempts to add this timed event to a bucket, will enter the secondary queue
* if there are no appropriate buckets at this time.
*
* Secondary queueing of timed events will occur when the timespan covered by the existing
* buckets is exceeded by the time at which this timed event is scheduled to be invoked.
* If the timed event is tracking client time, it will be added to a special bucket.
*/
/datum/timedevent/proc/bucketJoin()
var/list/L
// Generate debug-friendly name for timer
var/static/list/bitfield_flags = list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP")
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], wait:[wait] Flags: [jointext(bitfield2list(flags, bitfield_flags), ", ")], \
callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), \
callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""]), source: [source]"
// Check if this timed event should be diverted to the client time bucket, or the secondary queue
var/list/L
if (flags & TIMER_CLIENT_TIME)
L = SStimer.clienttime_timers
else if (timeToRun >= TIMER_MAX)
L = SStimer.second_queue
if(L)
BINARY_INSERT(src, L, datum/timedevent, src, timeToRun, COMPARE_KEY)
BINARY_INSERT(src, L, /datum/timedevent, src, timeToRun, COMPARE_KEY)
return
//get the list of buckets
// Get a local reference to the bucket list, this is faster than referencing the datum
var/list/bucket_list = SStimer.bucket_list
//calculate our place in the bucket list
// Find the correct bucket for this timed event
var/bucket_pos = BUCKET_POS(src)
//get the bucket for our tick
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
SStimer.bucket_count++
//empty bucket, we will just add ourselves
// If there is no timed event at this position, then the bucket is 'empty'
// and we can just set this event to that position
if (!bucket_head)
bucket_list[bucket_pos] = src
return
//other wise, lets do a simplified linked list add.
// Otherwise, we merely add this timed event into the bucket, which is a
// circularly doubly-linked list
if (!bucket_head.prev)
bucket_head.prev = bucket_head
next = bucket_head
@@ -448,7 +506,9 @@ SUBSYSTEM_DEF(timer)
next.prev = src
prev.next = src
///Returns a string of the type of the callback for this timer
/**
* Returns a string of the type of the callback for this timer
*/
/datum/timedevent/proc/getcallingtype()
. = "ERROR"
if (callBack.object == GLOBAL_PROC)
@@ -457,14 +517,15 @@ SUBSYSTEM_DEF(timer)
. = "[callBack.object.type]"
/**
* Create a new timer and insert it in the queue
*
* Arguments:
* * callback the callback to call on timer finish
* * wait deciseconds to run the timer for
* * flags flags for this timer, see: code\__DEFINES\subsystems.dm
*/
/proc/addtimer(datum/callback/callback, wait = 0, flags = 0)
* Create a new timer and insert it in the queue.
* You should not call this directly, and should instead use the addtimer macro, which includes source information.
*
* Arguments:
* * callback the callback to call on timer finish
* * wait deciseconds to run the timer for
* * flags flags for this timer, see: code\__DEFINES\subsystems.dm
*/
/proc/_addtimer(datum/callback/callback, wait = 0, flags = 0, file, line)
if (!callback)
CRASH("addtimer called without a callback")
@@ -472,31 +533,30 @@ SUBSYSTEM_DEF(timer)
stack_trace("addtimer called with a negative wait. Converting to [world.tick_lag]")
if (callback.object != GLOBAL_PROC && QDELETED(callback.object) && !QDESTROYING(callback.object))
stack_trace("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not be supported and may refuse to run or run with a 0 wait")
stack_trace("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not \
be supported and may refuse to run or run with a 0 wait")
wait = max(CEILING(wait, world.tick_lag), world.tick_lag)
if(wait >= INFINITY)
CRASH("Attempted to create timer with INFINITY delay")
// Generate hash if relevant for timed events with the TIMER_UNIQUE flag
var/hash
if (flags & TIMER_UNIQUE)
var/list/hashlist
if(flags & TIMER_NO_HASH_WAIT)
hashlist = list(callback.object, "([REF(callback.object)])", callback.delegate, flags & TIMER_CLIENT_TIME)
else
hashlist = list(callback.object, "([REF(callback.object)])", callback.delegate, wait, flags & TIMER_CLIENT_TIME)
var/list/hashlist = list(callback.object, "([REF(callback.object)])", callback.delegate, flags & TIMER_CLIENT_TIME)
if(!(flags & TIMER_NO_HASH_WAIT))
hashlist += wait
hashlist += callback.arguments
hash = hashlist.Join("|||||||")
var/datum/timedevent/hash_timer = SStimer.hashes[hash]
if(hash_timer)
if (hash_timer.spent) //it's pending deletion, pretend it doesn't exist.
hash_timer.hash = null //but keep it from accidentally deleting us
if (hash_timer.spent) // it's pending deletion, pretend it doesn't exist.
hash_timer.hash = null // but keep it from accidentally deleting us
else
if (flags & TIMER_OVERRIDE)
hash_timer.hash = null //no need having it delete it's hash if we are going to replace it
hash_timer.hash = null // no need having it delete it's hash if we are going to replace it
qdel(hash_timer)
else
if (hash_timer.flags & TIMER_STOPPABLE)
@@ -505,24 +565,23 @@ SUBSYSTEM_DEF(timer)
else if(flags & TIMER_OVERRIDE)
stack_trace("TIMER_OVERRIDE used without TIMER_UNIQUE")
var/datum/timedevent/timer = new(callback, wait, flags, hash)
var/datum/timedevent/timer = new(callback, wait, flags, hash, file && "[file]:[line]")
return timer.id
/**
* Delete a timer
*
* Arguments:
* * id a timerid or a /datum/timedevent
*/
* Delete a timer
*
* Arguments:
* * id a timerid or a /datum/timedevent
*/
/proc/deltimer(id)
if (!id)
return FALSE
if (id == TIMER_ID_NULL)
CRASH("Tried to delete a null timerid. Use TIMER_STOPPABLE flag")
if (!istext(id))
if (istype(id, /datum/timedevent))
qdel(id)
return TRUE
if (istype(id, /datum/timedevent))
qdel(id)
return TRUE
//id is string
var/datum/timedevent/timer = SStimer.timer_id_dict[id]
if (timer && !timer.spent)
@@ -531,25 +590,22 @@ SUBSYSTEM_DEF(timer)
return FALSE
/**
* Get the remaining deciseconds on a timer
*
* Arguments:
* * id a timerid or a /datum/timedevent
*/
* Get the remaining deciseconds on a timer
*
* Arguments:
* * id a timerid or a /datum/timedevent
*/
/proc/timeleft(id)
if (!id)
return null
if (id == TIMER_ID_NULL)
CRASH("Tried to get timeleft of a null timerid. Use TIMER_STOPPABLE flag")
if (!istext(id))
if (istype(id, /datum/timedevent))
var/datum/timedevent/timer = id
return timer.timeToRun - world.time
if (istype(id, /datum/timedevent))
var/datum/timedevent/timer = id
return timer.timeToRun - world.time
//id is string
var/datum/timedevent/timer = SStimer.timer_id_dict[id]
if (timer && !timer.spent)
return timer.timeToRun - world.time
return null
return (timer && !timer.spent) ? timer.timeToRun - world.time : null
#undef BUCKET_LEN
#undef BUCKET_POS

View File

@@ -25,12 +25,12 @@ SUBSYSTEM_DEF(title)
SSmapping.HACK_LoadMapConfig()
for(var/S in provisional_title_screens)
var/list/L = splittext(S,"+")
if((L.len == 1 && L[1] != "blank.png")|| (L.len > 1 && ((use_rare_screens && lowertext(L[1]) == "rare") || (lowertext(L[1]) == lowertext(SSmapping.config.map_name)))))
if((L.len == 1 && (L[1] != "exclude" && L[1] != "blank.png"))|| (L.len > 1 && ((use_rare_screens && lowertext(L[1]) == "rare") || (lowertext(L[1]) == lowertext(SSmapping.config.map_name)))))
title_screens += S
if(length(title_screens))
file_path = "[global.config.directory]/title_screens/images/[pick(title_screens)]"
if(!file_path)
file_path = "icons/default_title.dmi"

View File

@@ -5,10 +5,12 @@ SUBSYSTEM_DEF(vis_overlays)
init_order = INIT_ORDER_VIS
var/list/vis_overlay_cache
var/list/unique_vis_overlays
var/list/currentrun
/datum/controller/subsystem/vis_overlays/Initialize()
vis_overlay_cache = list()
unique_vis_overlays = list()
return ..()
/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE)
@@ -29,31 +31,45 @@ SUBSYSTEM_DEF(vis_overlays)
return
//the "thing" var can be anything with vis_contents which includes images
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE)
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
var/obj/effect/overlay/vis/overlay = vis_overlay_cache[.]
if(!overlay)
overlay = new
overlay.icon = icon
overlay.icon_state = iconstate
overlay.layer = layer
overlay.plane = plane
overlay.dir = dir
overlay.alpha = alpha
overlay.appearance_flags |= add_appearance_flags
vis_overlay_cache[.] = overlay
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE, unique = FALSE)
var/obj/effect/overlay/vis/overlay
if(!unique)
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
overlay = vis_overlay_cache[.]
if(!overlay)
overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
vis_overlay_cache[.] = overlay
else
overlay.unused = 0
else
overlay.unused = 0
overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
overlay.cache_expiration = -1
var/cache_id = "\ref[overlay]@{[world.time]}"
unique_vis_overlays += overlay
vis_overlay_cache[cache_id] = overlay
. = overlay
thing.vis_contents += overlay
if(!isatom(thing)) // Automatic rotation is not supported on non atoms
return
return overlay
if(!thing.managed_vis_overlays)
thing.managed_vis_overlays = list(overlay)
RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_vis_overlay)
else
thing.managed_vis_overlays += overlay
return overlay
/datum/controller/subsystem/vis_overlays/proc/_create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
var/obj/effect/overlay/vis/overlay = new
overlay.icon = icon
overlay.icon_state = iconstate
overlay.layer = layer
overlay.plane = plane
overlay.dir = dir
overlay.alpha = alpha
overlay.appearance_flags |= add_appearance_flags
return overlay
/datum/controller/subsystem/vis_overlays/proc/remove_vis_overlay(atom/movable/thing, list/overlays)
thing.vis_contents -= overlays
@@ -62,15 +78,3 @@ SUBSYSTEM_DEF(vis_overlays)
thing.managed_vis_overlays -= overlays
if(!length(thing.managed_vis_overlays))
thing.managed_vis_overlays = null
UnregisterSignal(thing, COMSIG_ATOM_DIR_CHANGE)
/datum/controller/subsystem/vis_overlays/proc/rotate_vis_overlay(atom/thing, old_dir, new_dir)
if(old_dir == new_dir)
return
var/rotation = dir2angle(old_dir) - dir2angle(new_dir)
var/list/overlays_to_remove = list()
for(var/i in thing.managed_vis_overlays)
var/obj/effect/overlay/vis/overlay = i
add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation), overlay.alpha, overlay.appearance_flags)
overlays_to_remove += overlay
remove_vis_overlay(thing, overlays_to_remove)

Some files were not shown because too many files have changed in this diff Show More