diff --git a/.editorconfig b/.editorconfig
index 13dcd5e029..c44572fbf9 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,11 +1,14 @@
[*]
-insert_final_newline = true
indent_style = tab
indent_size = 4
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+#end_of_line = lf
[*.yml]
indent_style = space
indent_size = 2
-[*.txt]
-insert_final_newline = false
+[*.py]
+indent_style = space
diff --git a/.gitattributes b/.gitattributes
index a0a624af04..c447869d3e 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,9 +1,42 @@
-# merger hooks, run tools/hooks/install.bat or install.sh to set up
-*.dmm merge=dmm
-*.dmi merge=dmi
-
-# force changelog merging to use union
-html/changelog.html merge=union
-
-# force all files to be LF
* text=auto
+
+## Enforce text mode and LF line breaks
+## porter note: not yet LFing dm.
+# *.bat text eol=lf
+*.css text eol=lf
+# *.dm text eol=lf
+# *.dme text eol=lf
+# *.dmf text eol=lf
+*.htm text eol=lf
+*.html text eol=lf
+*.js text eol=lf
+*.json text eol=lf
+*.jsx text eol=lf
+# *.md text eol=lf
+*.py text eol=lf
+*.scss text eol=lf
+# *.sh text eol=lf
+# *.sql text eol=lf
+*.svg text eol=lf
+*.ts text eol=lf
+*.tsx text eol=lf
+# *.txt text eol=lf
+*.yaml text eol=lf
+*.yml text eol=lf
+
+## Enforce binary mode
+*.bmp binary
+*.dll binary
+*.dmb binary
+*.exe binary
+*.gif binary
+*.jpg binary
+*.png binary
+*.so binary
+
+## Merger hooks, run tools/hooks/install.bat or install.sh to set up
+*.dmm text eol=lf merge=dmm
+*.dmi binary merge=dmi
+
+## Force changelog merging to use union
+html/changelog.html text eol=lf merge=union
diff --git a/.github/workflows/autobuild_tgui.yml b/.github/workflows/autobuild_tgui.yml
deleted file mode 100644
index 226ea2b7ce..0000000000
--- a/.github/workflows/autobuild_tgui.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Autobuild TGUI
-
-on:
- push:
- branches:
- - 'master'
- paths:
- - 'tgui/**.js'
- - 'tgui/**.scss'
-
-jobs:
- build:
- name: Rebuild TGUI
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v1
- with:
- fetch-depth: 25
- - name: Setup Node
- uses: actions/setup-node@v1
- with:
- node-version: '>=12.13'
- - name: Build TGUI
- run: bin/tgui --ci
- working-directory: ./tgui
- - name: Commit Artifacts
- run: |
- git config --local user.email "action@github.com"
- git config --local user.name "TGUI"
- git pull origin master
- git commit -m "Automatic TGUI Rebuild [ci skip]" -a || true
- - name: Push Artifacts
- uses: ad-m/github-push-action@master
- with:
- github_token: ${{ secrets.GITHUB_MASTER_KEY }}
diff --git a/.github/workflows/compile_changelogs.yml b/.github/workflows/compile_changelogs.yml
index f8098df66e..4fd396f133 100644
--- a/.github/workflows/compile_changelogs.yml
+++ b/.github/workflows/compile_changelogs.yml
@@ -9,32 +9,47 @@ jobs:
name: "Compile changelogs"
runs-on: ubuntu-latest
steps:
+ - name: "Check for CHANGELOG_ENABLER secret and pass true to output if it exists to be checked by later steps"
+ id: value_holder
+ env:
+ CHANGELOG_ENABLER: ${{ secrets.CHANGELOG_ENABLER }}
+ run: |
+ unset SECRET_EXISTS
+ 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
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: "Install deps"
+ if: steps.value_holder.outputs.CL_ENABLED
run: |
python -m pip install --upgrade pip
python -m pip install pyyaml
sudo apt-get install dos2unix
- name: "Checkout"
+ if: steps.value_holder.outputs.CL_ENABLED
uses: actions/checkout@v1
with:
fetch-depth: 25
- name: "Compile"
+ if: steps.value_holder.outputs.CL_ENABLED
run: |
python tools/ss13_genchangelog.py html/changelog.html html/changelogs
- name: "Convert Lineendings"
+ if: steps.value_holder.outputs.CL_ENABLED
run: |
unix2dos html/changelogs/.all_changelog.yml
- name: Commit
+ if: steps.value_holder.outputs.CL_ENABLED
run: |
git config --local user.email "action@github.com"
git config --local user.name "Changelogs"
git pull origin master
git commit -m "Automatic changelog compile [ci skip]" -a || true
- name: "Push"
+ if: steps.value_holder.outputs.CL_ENABLED
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/round_id_linker.yml b/.github/workflows/round_id_linker.yml
new file mode 100644
index 0000000000..37998a93eb
--- /dev/null
+++ b/.github/workflows/round_id_linker.yml
@@ -0,0 +1,12 @@
+name: "Round ID Linker"
+on:
+ issues:
+ types: [opened]
+
+jobs:
+ link_rounds:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: Cidatel-Station-13/round_linker@master #notice: fork the round linkies from tg!!
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index f65245c021..e885761104 100644
--- a/.gitignore
+++ b/.gitignore
@@ -198,13 +198,36 @@ Temporary Items
!/.vscode/extensions.json
tools/MapAtmosFixer/MapAtmosFixer/obj/*
tools/MapAtmosFixer/MapAtmosFixer/bin/*
+tools/CreditsTool/bin/*
+tools/CreditsTool/obj/*
#GitHub Atom
.atom-build.json
-#Jukebox audio files
-/config/jukebox_music/**/*
+#KDevelop and Kate
+*.kdev4*
+*.kate-swp
#extra map stuff
/_maps/**/backup/
/_maps/templates.dm
+
+#dmdoc default folder
+/dmdoc
+
+# Ignore custom music and title screens (amend as appropriate)
+/config/jukebox_music/sounds/*
+!/config/jukebox_music/sounds/exclude
+/config/title_music/sounds/*
+!/config/title_music/sounds/exclude
+/config/title_screens/images/*
+!/config/title_screens/images/exclude
+
+#Linux docker
+tools/LinuxOneShot/SetupProgram/obj/*
+tools/LinuxOneShot/SetupProgram/bin/*
+tools/LinuxOneShot/SetupProgram/.vs
+tools/LinuxOneShot/Database
+tools/LinuxOneShot/TGS_Config
+tools/LinuxOneShot/TGS_Instances
+tools/LinuxOneShot/TGS_Logs
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000..11d27b55d3
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,11 @@
+build:
+ stage: build
+ rules:
+ - if: $CI_MERGE_REQUEST_IID || $CI_COMMIT_REF_NAME == "master"
+ changes:
+ - tgui/**/*.js
+ - tgui/**/*.scss
+ when: always
+ image: node:lts
+ script:
+ - tgui/bin/tgui --ci
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/.travis.yml b/.travis.yml
index 2214df3aee..83ef6fa8ff 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,13 @@
language: generic
+os: linux
dist: xenial
-sudo: false
branches:
except:
- ___TGS3TempBranch
- ___TGSTempBranch
-matrix:
+jobs:
include:
- name: "Run Linters"
addons:
@@ -16,9 +16,15 @@ matrix:
- python3
- python3-pip
- python3-setuptools
+ - pcregrep
+ - rustc
+ - cargo
+ cache:
+ directories:
+ - $HOME/SpacemanDMM
install:
- tools/travis/install_build_tools.sh
- - tools/travis/install_dreamchecker.sh
+ - tools/travis/install_spaceman_dmm.sh dreamchecker
script:
- tools/travis/check_filedirs.sh tgstation.dme
- tools/travis/check_changelogs.sh
@@ -76,3 +82,21 @@ matrix:
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
diff --git a/_maps/RandomRuins/SpaceRuins/skelter.dmm b/_maps/RandomRuins/SpaceRuins/skelter.dmm
index f6e6584f10..f6e56a6348 100644
--- a/_maps/RandomRuins/SpaceRuins/skelter.dmm
+++ b/_maps/RandomRuins/SpaceRuins/skelter.dmm
@@ -1529,6 +1529,7 @@
icon_state = "warningline";
dir = 1
},
+/obj/item/paper/fluff/ruins/skelter/cloner,
/turf/open/floor/plasteel,
/area/ruin/space/has_grav/skelter/med)
"dJ" = (
@@ -2485,10 +2486,13 @@
/turf/open/floor/plating,
/area/ruin/space/has_grav/skelter/engine/powerstorage)
"fR" = (
-/obj/structure/cable{
- icon_state = "2-8"
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 4
},
-/obj/item/ammo_casing/c45,
+/obj/structure/cable/yellow{
+ icon_state = "4-8"
+ },
+/obj/item/kitchen/knife/combat,
/turf/open/floor/plating,
/area/ruin/space/has_grav/skelter/engine/powerstorage)
"fS" = (
@@ -2826,10 +2830,12 @@
/turf/open/floor/plasteel/dark,
/area/ruin/space/has_grav/skelter/sec)
"gI" = (
-/obj/structure/rack,
-/obj/item/gun/ballistic/automatic/pistol/m1911,
-/turf/open/floor/plasteel/dark,
-/area/ruin/space/has_grav/skelter/sec)
+/obj/structure/cable{
+ icon_state = "2-8"
+ },
+/obj/item/ammo_casing/c10mm,
+/turf/open/floor/plating,
+/area/ruin/space/has_grav/skelter/engine/powerstorage)
"gJ" = (
/obj/machinery/power/terminal{
dir = 1
@@ -3285,17 +3291,10 @@
/turf/open/floor/plasteel/showroomfloor,
/area/ruin/space/has_grav/skelter/comms)
"hJ" = (
-/obj/effect/turf_decal/trimline/blue/line,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 4
- },
-/obj/structure/cable/yellow{
- icon_state = "1-2"
- },
-/obj/item/ammo_casing/c45,
-/turf/open/floor/plasteel/showroomfloor,
-/area/ruin/space/has_grav/skelter/comms)
+/obj/structure/rack,
+/obj/item/ammo_box/magazine/m10mm,
+/turf/open/floor/plasteel/dark,
+/area/ruin/space/has_grav/skelter/sec)
"hK" = (
/obj/effect/turf_decal/trimline/yellow/filled/line{
icon_state = "trimline_fill";
@@ -3843,19 +3842,10 @@
/turf/open/floor/plasteel/showroomfloor,
/area/ruin/space/has_grav/skelter/comms)
"iP" = (
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 1
- },
-/obj/item/gun/ballistic/automatic/pistol/m1911/no_mag,
-/turf/open/floor/plasteel/showroomfloor,
-/area/ruin/space/has_grav/skelter/comms)
+/obj/structure/rack,
+/obj/item/gun/ballistic/automatic/pistol,
+/turf/open/floor/plasteel/dark,
+/area/ruin/space/has_grav/skelter/sec)
"iQ" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/mineral/titanium,
@@ -3934,17 +3924,15 @@
/turf/open/floor/plasteel/showroomfloor,
/area/ruin/space/has_grav/skelter/comms)
"iX" = (
-/obj/effect/turf_decal/tile/blue,
-/obj/effect/turf_decal/tile/blue{
+/obj/effect/turf_decal/trimline/blue/line,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
-/obj/effect/turf_decal/tile/blue{
- dir = 8
+/obj/structure/cable/yellow{
+ icon_state = "1-2"
},
-/obj/effect/turf_decal/tile/blue{
- dir = 1
- },
-/obj/item/ammo_casing/c45,
+/obj/item/ammo_casing/c10mm,
/turf/open/floor/plasteel/showroomfloor,
/area/ruin/space/has_grav/skelter/comms)
"iY" = (
@@ -4149,16 +4137,39 @@
/turf/open/floor/carpet,
/area/ruin/space/has_grav/skelter/admin)
"jv" = (
-/obj/structure/rack,
-/obj/item/ammo_box/magazine/m45,
-/turf/open/floor/plasteel/dark,
-/area/ruin/space/has_grav/skelter/sec)
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/item/gun/ballistic/automatic/pistol/no_mag,
+/turf/open/floor/plasteel/showroomfloor,
+/area/ruin/space/has_grav/skelter/comms)
"jw" = (
/turf/open/space/basic,
/area/space/nearstation)
"jx" = (
/turf/open/space/basic,
/area/template_noop)
+"jy" = (
+/obj/effect/turf_decal/tile/blue,
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/obj/item/ammo_casing/c10mm,
+/turf/open/floor/plasteel/showroomfloor,
+/area/ruin/space/has_grav/skelter/comms)
(1,1,1) = {"
ah
@@ -4479,7 +4490,7 @@ eW
cF
fN
gj
-jv
+hJ
gl
hw
hU
@@ -4539,7 +4550,7 @@ eX
fx
fN
gj
-gI
+iP
gl
hx
hx
@@ -4657,7 +4668,7 @@ dI
bI
fc
fA
-fR
+gI
go
gL
iC
@@ -4715,7 +4726,7 @@ bI
bI
bI
eA
-fd
+fR
fA
fA
fA
@@ -4991,10 +5002,10 @@ ju
gw
dO
hk
-hJ
+iX
ij
iF
-iP
+jv
iW
jh
jl
@@ -5025,7 +5036,7 @@ hK
ii
jm
jn
-iX
+jy
ii
jl
ah
diff --git a/_maps/RandomZLevels/away_mission/SnowCabin.dmm b/_maps/RandomZLevels/away_mission/SnowCabin.dmm
index 249cb68b5d..844a134d27 100644
--- a/_maps/RandomZLevels/away_mission/SnowCabin.dmm
+++ b/_maps/RandomZLevels/away_mission/SnowCabin.dmm
@@ -428,7 +428,7 @@
/area/awaymission/cabin)
"bm" = (
/obj/machinery/door/airlock/wood{
- id_tag = "snowdinbutworse5";
+ id_tag = "snowdorm5";
name = "Cabin 5"
},
/obj/effect/mapping_helpers/network_builder/power_cable/yellow/auto,
@@ -3318,7 +3318,7 @@
/area/awaymission/cabin)
"iV" = (
/obj/machinery/door/airlock/wood{
- id_tag = "snowdinbutworse1";
+ id_tag = "snowdorm1";
name = "Cabin 1"
},
/obj/effect/mapping_helpers/network_builder/power_cable/yellow/auto,
@@ -3326,7 +3326,7 @@
/area/awaymission/cabin)
"iW" = (
/obj/machinery/door/airlock/wood{
- id_tag = "snowdinbutworse2";
+ id_tag = "snowdorm2";
name = "Cabin 2"
},
/obj/effect/mapping_helpers/network_builder/power_cable/yellow/auto,
@@ -3334,7 +3334,7 @@
/area/awaymission/cabin)
"iX" = (
/obj/machinery/door/airlock/wood{
- id_tag = "snowdinbutworse3";
+ id_tag = "snowdorm3";
name = "Cabin 3"
},
/obj/effect/mapping_helpers/network_builder/power_cable/yellow/auto,
@@ -3342,7 +3342,7 @@
/area/awaymission/cabin)
"iY" = (
/obj/machinery/door/airlock/wood{
- id_tag = "snowdinbutworse4";
+ id_tag = "snowdorm4";
name = "Cabin 4"
},
/obj/effect/mapping_helpers/network_builder/power_cable/yellow/auto,
@@ -3419,31 +3419,37 @@
/area/awaymission/cabin)
"jg" = (
/obj/machinery/button/door{
- id = "snowdinbutworse2";
- name = "airlock button";
- pixel_y = -27
+ id = "snowdorm2";
+ name = "Dorm Bolt Control";
+ normaldoorcontrol = 1;
+ pixel_y = -25;
+ specialfunctions = 4
},
/turf/open/floor/wood,
/area/awaymission/cabin)
"jh" = (
/obj/machinery/button/door{
- id = "snowdinbutworse1";
- name = "airlock button";
- pixel_y = -27
+ id = "snowdorm1";
+ name = "Dorm Bolt Control";
+ normaldoorcontrol = 1;
+ pixel_y = -25;
+ specialfunctions = 4
},
/turf/open/floor/wood,
/area/awaymission/cabin)
"ji" = (
/obj/machinery/button/door{
- id = "snowdinbutworse3";
- name = "airlock button";
- pixel_y = -27
+ id = "snowdorm3";
+ name = "Dorm Bolt Control";
+ normaldoorcontrol = 1;
+ pixel_y = -25;
+ specialfunctions = 4
},
/turf/open/floor/wood,
/area/awaymission/cabin)
"jj" = (
/obj/machinery/button/door{
- id = "snowdinbutworse4";
+ id = "snowdorm4";
name = "airlock button";
pixel_y = -27
},
@@ -3451,7 +3457,7 @@
/area/awaymission/cabin)
"jk" = (
/obj/machinery/button/door{
- id = "snowdinbutworse5";
+ id = "snowdorm5";
name = "airlock button";
pixel_y = -27
},
@@ -4024,8 +4030,8 @@
pixel_y = -2
},
/obj/item/clothing/head/christmashatg{
- pixel_y = 12;
- pixel_x = 3
+ pixel_x = 3;
+ pixel_y = 12
},
/turf/open/floor/plating/asteroid/snow,
/area/awaymission/cabin/caves)
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 17253e2665..943aa85efd 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -12556,15 +12556,11 @@
/area/engine/atmospherics_engine)
"aAb" = (
/turf/closed/wall,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aAc" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aAd" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/tile/neutral{
@@ -13138,9 +13134,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBh" = (
/obj/item/kirbyplants/random,
/obj/machinery/light/small{
@@ -13149,25 +13143,19 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBi" = (
/obj/structure/table,
/obj/item/clothing/suit/apron/overalls,
/obj/item/cultivator,
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBj" = (
/obj/machinery/biogenerator,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBk" = (
/obj/structure/table,
/obj/item/reagent_containers/food/snacks/grown/wheat,
@@ -13182,18 +13170,14 @@
pixel_y = 4
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBl" = (
/obj/machinery/hydroponics/soil,
/obj/item/seeds/tea,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBm" = (
/obj/item/kirbyplants/random,
/obj/machinery/status_display/evac{
@@ -13201,9 +13185,7 @@
},
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBn" = (
/obj/structure/table,
/obj/item/stack/packageWrap,
@@ -13213,9 +13195,7 @@
/obj/item/reagent_containers/food/snacks/grown/cherries,
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBo" = (
/obj/item/kirbyplants/random,
/obj/machinery/light/small{
@@ -13225,18 +13205,14 @@
/obj/effect/turf_decal/delivery,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBp" = (
/obj/machinery/hydroponics/soil,
/obj/item/seeds/poppy,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aBq" = (
/obj/structure/cable/white{
icon_state = "2-4"
@@ -13817,33 +13793,25 @@
/area/engine/atmospherics_engine)
"aCv" = (
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aCw" = (
/obj/effect/turf_decal/delivery,
/obj/machinery/hydroponics/soil,
/obj/item/seeds/watermelon,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aCx" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 4
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aCy" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 4
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aCz" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -14459,21 +14427,15 @@
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aDy" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aDz" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aDA" = (
/obj/structure/sink{
dir = 4;
@@ -14484,9 +14446,7 @@
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aDB" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
@@ -14968,34 +14928,26 @@
icon_state = "2-4"
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aEC" = (
/obj/structure/cable/white{
icon_state = "4-8"
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aED" = (
/obj/structure/cable/white{
icon_state = "4-8"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aEE" = (
/obj/structure/cable/white{
icon_state = "2-8"
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aEG" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/cable/white{
@@ -15628,18 +15580,14 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFK" = (
/obj/machinery/hydroponics/soil,
/obj/item/seeds/harebell,
/obj/machinery/light/small,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFL" = (
/obj/structure/table,
/obj/item/shovel/spade,
@@ -15658,9 +15606,7 @@
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFM" = (
/obj/machinery/status_display/evac{
pixel_y = -32
@@ -15669,34 +15615,26 @@
/obj/machinery/hydroponics/soil,
/obj/item/seeds/poppy/geranium,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFN" = (
/obj/structure/table,
/obj/item/plant_analyzer,
/obj/item/hatchet,
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFO" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFP" = (
/obj/structure/cable/white{
icon_state = "1-2"
},
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFQ" = (
/obj/structure/table,
/obj/item/crowbar,
@@ -15704,9 +15642,7 @@
/obj/item/reagent_containers/glass/bucket,
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFR" = (
/obj/machinery/hydroponics/soil,
/obj/item/seeds/tower,
@@ -15715,9 +15651,7 @@
/obj/effect/turf_decal/delivery,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aFS" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -16707,9 +16641,7 @@
"aHl" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aHm" = (
/obj/machinery/door/airlock/maintenance_hatch{
name = "Maintenance Hatch";
@@ -16721,9 +16653,7 @@
dir = 1
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aHn" = (
/obj/machinery/door/airlock/maintenance_hatch{
name = "Maintenance Hatch";
@@ -16737,16 +16667,12 @@
dir = 1
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aHo" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"aHp" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/cable/white{
@@ -125347,9 +125273,7 @@
/obj/item/reagent_containers/glass/bucket,
/obj/effect/turf_decal/delivery,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"etO" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -125474,9 +125398,7 @@
/obj/machinery/hydroponics/soil,
/obj/item/seeds/grape,
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"faI" = (
/obj/structure/cable/white{
icon_state = "1-2"
@@ -126395,9 +126317,7 @@
pixel_x = 6
},
/turf/open/floor/plasteel,
-/area/hydroponics/garden/abandoned{
- name = "Maintenance Garden"
- })
+/area/hydroponics/garden/abandoned)
"loH" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm
index f426ad8e97..51bfe5038e 100644
--- a/_maps/map_files/KiloStation/KiloStation.dmm
+++ b/_maps/map_files/KiloStation/KiloStation.dmm
@@ -75352,9 +75352,7 @@
/obj/machinery/atmospherics/pipe/simple/orange/visible{
dir = 4
},
-/obj/machinery/airalarm{
- pixel_z = 24
- },
+/obj/machinery/airalarm,
/obj/machinery/light/small,
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating{
diff --git a/_maps/map_files/LambdaStation/dorms.dmm b/_maps/map_files/LambdaStation/dorms.dmm
index e5003965ed..a38d2b9e1d 100644
--- a/_maps/map_files/LambdaStation/dorms.dmm
+++ b/_maps/map_files/LambdaStation/dorms.dmm
@@ -25,6 +25,9 @@
/obj/structure/closet,
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
+"ae" = (
+/turf/open/floor/wood,
+/area/hydroponics/garden/monastery)
"af" = (
/obj/effect/landmark/carpspawn,
/turf/open/space/basic,
@@ -216,9 +219,6 @@
},
/turf/open/floor/plasteel,
/area/gateway)
-"ay" = (
-/turf/closed/wall/r_wall,
-/area/construction/mining/aux_base)
"az" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3,
@@ -386,16 +386,6 @@
"aT" = (
/turf/closed/wall/r_wall,
/area/chapel/main)
-"aU" = (
-/obj/effect/turf_decal/trimline/neutral/filled/line,
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"aV" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -577,6 +567,13 @@
},
/turf/open/floor/plating,
/area/hydroponics/garden/abandoned)
+"br" = (
+/obj/structure/table,
+/obj/item/stack/sheet/metal/fifty,
+/obj/item/stack/sheet/metal/fifty,
+/obj/item/stack/sheet/glass/fifty,
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"bu" = (
/obj/effect/turf_decal/tile/neutral,
/obj/effect/turf_decal/tile/neutral{
@@ -600,6 +597,10 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
+"bv" = (
+/obj/structure/railing,
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"bw" = (
/obj/structure/cable{
icon_state = "2-8"
@@ -775,6 +776,15 @@
/obj/effect/spawner/lootdrop/maintenance,
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
+"bN" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/turf/open/floor/plating,
+/turf/open/floor/plating{
+ icon_state = "platingdmg2"
+ },
+/area/maintenance/central)
"bO" = (
/obj/effect/turf_decal/trimline/neutral/filled/line{
dir = 4
@@ -804,6 +814,15 @@
/obj/machinery/light,
/turf/open/floor/carpet,
/area/chapel/main)
+"bT" = (
+/obj/effect/turf_decal/trimline/neutral/filled/line{
+ dir = 8
+ },
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/hydroponics/garden/monastery)
"bU" = (
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -926,6 +945,21 @@
/obj/item/clothing/mask/horsehead,
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
+"cp" = (
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral{
+ dir = 1
+ },
+/obj/machinery/holopad,
+/obj/effect/turf_decal/bot,
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness/recreation)
"cq" = (
/turf/open/space,
/area/space)
@@ -1006,6 +1040,7 @@
dir = 4
},
/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/public/glass,
/turf/open/floor/plasteel,
/area/hallway/secondary/service)
"cC" = (
@@ -1090,14 +1125,14 @@
icon_state = "L6";
layer = 2.04
},
-/mob/living/simple_animal/bot/medbot{
- auto_patrol = 1;
- name = "Dr. Heals"
- },
/obj/machinery/navbeacon{
codes_txt = "patrol;next_patrol=dorms9";
location = "dorms8"
},
+/mob/living/simple_animal/bot/medbot{
+ auto_patrol = 1;
+ name = "Dr. Heals"
+ },
/turf/open/floor/plasteel,
/area/hallway/primary/central)
"cN" = (
@@ -1116,6 +1151,14 @@
/obj/machinery/door/firedoor,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
+"cO" = (
+/turf/closed/mineral{
+ baseturfs = /turf/open/floor/plating/asteroid;
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15";
+ name = "asteroid";
+ turf_type = /turf/open/floor/plating/asteroid
+ },
+/area/space)
"cP" = (
/obj/item/kirbyplants/random,
/turf/open/floor/plasteel,
@@ -1197,6 +1240,14 @@
},
/turf/open/floor/wood,
/area/crew_quarters/dorms)
+"db" = (
+/obj/effect/turf_decal/trimline/neutral/filled/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/bot,
+/obj/machinery/holopad,
+/turf/open/floor/plasteel,
+/area/crew_quarters/fitness/pool)
"dc" = (
/obj/effect/landmark/blobstart,
/turf/open/floor/plating,
@@ -1226,10 +1277,6 @@
},
/turf/open/floor/plating/airless,
/area/space/nearstation)
-"di" = (
-/obj/docking_port/stationary/public_mining_dock,
-/turf/open/floor/plating,
-/area/construction/mining/aux_base)
"dk" = (
/obj/machinery/door/airlock/public/glass{
name = "Public Minning Access"
@@ -1303,6 +1350,12 @@
},
/turf/open/floor/plasteel/freezer,
/area/crew_quarters/toilet)
+"ds" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"dt" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -1362,6 +1415,10 @@
},
/turf/open/floor/wood,
/area/crew_quarters/dorms)
+"dB" = (
+/obj/structure/railing,
+/turf/open/floor/plating,
+/area/maintenance/central)
"dC" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/public/glass{
@@ -1426,13 +1483,6 @@
},
/turf/open/floor/wood,
/area/maintenance/bar)
-"dK" = (
-/obj/machinery/door/airlock/external{
- name = "Construction Zone"
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper,
-/turf/open/floor/plating,
-/area/construction/mining/aux_base)
"dM" = (
/obj/machinery/vending/autodrobe,
/turf/open/floor/wood,
@@ -1522,6 +1572,10 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer3,
/turf/open/floor/plasteel,
/area/hallway/secondary/service)
+"ea" = (
+/obj/machinery/light/floor,
+/turf/open/floor/wood,
+/area/hydroponics/garden/monastery)
"eb" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -1954,12 +2008,6 @@
/obj/machinery/airalarm/directional/west,
/turf/open/floor/carpet,
/area/chapel/office)
-"fn" = (
-/obj/machinery/computer/camera_advanced/base_construction{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"fo" = (
/obj/effect/turf_decal/vg_decals/department/sec,
/obj/effect/turf_decal/tile/neutral,
@@ -2178,10 +2226,6 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
-"fR" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on/layer1,
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"fS" = (
/obj/structure/reagent_dispensers/fueltank,
/turf/open/floor/plating,
@@ -2378,6 +2422,14 @@
},
/turf/open/floor/plasteel/cafeteria,
/area/crew_quarters/kitchen)
+"go" = (
+/obj/machinery/camera/autoname,
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 8
+ },
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"gp" = (
/obj/effect/turf_decal/vg_decals/department/sci,
/obj/effect/turf_decal/tile/neutral,
@@ -2427,6 +2479,9 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer1{
dir = 4
},
+/obj/machinery/light{
+ dir = 8
+ },
/turf/open/floor/plasteel,
/area/hydroponics/garden/monastery)
"gw" = (
@@ -2486,6 +2541,11 @@
"gI" = (
/turf/open/floor/plating,
/area/maintenance/bar)
+"gJ" = (
+/obj/structure/closet,
+/obj/structure/railing/corner,
+/turf/open/floor/plating,
+/area/maintenance/central)
"gK" = (
/obj/structure/table,
/obj/machinery/camera{
@@ -2509,6 +2569,14 @@
},
/turf/open/floor/wood,
/area/maintenance/bar)
+"gO" = (
+/obj/machinery/space_heater,
+/obj/structure/railing/corner{
+ icon_state = "railing_corner";
+ dir = 8
+ },
+/turf/open/floor/plating,
+/area/maintenance/central)
"gP" = (
/obj/machinery/light/small{
dir = 8;
@@ -2560,14 +2628,6 @@
/obj/effect/spawner/structure/window,
/turf/open/floor/plating,
/area/crew_quarters/bar)
-"gV" = (
-/obj/structure/table,
-/obj/item/stack/sheet/metal/fifty,
-/obj/item/stack/sheet/metal/fifty,
-/obj/item/stack/sheet/glass/fifty,
-/obj/item/pipe_dispenser,
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"gX" = (
/obj/structure/lattice/catwalk,
/obj/structure/cable{
@@ -2754,6 +2814,16 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
+"hv" = (
+/obj/machinery/door/airlock/maintenance{
+ name = "Aux Base Maintenance";
+ req_access_txt = "48"
+ },
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/turf/open/floor/plating,
+/area/maintenance/central)
"hw" = (
/obj/structure/chair/stool,
/obj/structure/cable{
@@ -2937,13 +3007,6 @@
icon_state = "wood-broken6"
},
/area/maintenance/bar)
-"hW" = (
-/obj/machinery/computer/shuttle/mining{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/corner,
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"hX" = (
/obj/structure/closet/firecloset,
/obj/effect/turf_decal/bot,
@@ -2976,13 +3039,6 @@
/obj/effect/spawner/lootdrop/glowstick,
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
-"ic" = (
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer3{
- dir = 4
- },
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"id" = (
/obj/structure/chair/sofa/corp/corner{
dir = 4
@@ -2996,35 +3052,6 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/cafeteria)
-"if" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
- dir = 4
- },
-/obj/machinery/button/door{
- id = "aux_base_shutters";
- name = "Public Shutters Control";
- pixel_y = -24;
- req_one_access_txt = "32;47;48"
- },
-/obj/machinery/camera{
- c_tag = "Auxillary Base Construction";
- dir = 10
- },
-/obj/effect/turf_decal/stripes/corner{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
-"ig" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
- dir = 10
- },
-/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
-/obj/structure/cable{
- icon_state = "2-4"
- },
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"ih" = (
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/obj/machinery/door/airlock/external{
@@ -3091,30 +3118,10 @@
},
/turf/open/floor/plasteel/grimy,
/area/chapel/office)
-"iq" = (
-/obj/machinery/computer/security/telescreen{
- desc = "Used for the Auxillary Mining Base.";
- dir = 1;
- name = "Auxillary Base Monitor";
- network = list("auxbase");
- pixel_y = -28
- },
-/obj/structure/cable{
- icon_state = "4-8"
- },
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"ir" = (
/obj/item/coin/silver,
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
-"is" = (
-/obj/machinery/light,
-/obj/structure/cable{
- icon_state = "4-8"
- },
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"it" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
/obj/structure/cable{
@@ -3218,17 +3225,6 @@
},
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
-"iH" = (
-/obj/machinery/power/apc{
- areastring = "/area/construction/mining/aux_base";
- name = "Auxillary Base Construction APC";
- pixel_y = -24
- },
-/obj/structure/cable{
- icon_state = "0-8"
- },
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"iI" = (
/obj/structure/table,
/obj/item/stack/sheet/plasteel{
@@ -3733,6 +3729,13 @@
},
/turf/open/floor/carpet,
/area/chapel/office)
+"jO" = (
+/obj/machinery/light/small{
+ dir = 8;
+ pixel_x = 5
+ },
+/turf/open/floor/plating,
+/area/maintenance/central)
"jP" = (
/obj/item/storage/bag/plants/portaseeder,
/obj/item/storage/bag/plants/portaseeder,
@@ -3860,14 +3863,6 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
-"kc" = (
-/obj/machinery/door/poddoor/shutters{
- id = "aux_base_shutters";
- name = "Auxillary Base Shutters"
- },
-/obj/effect/turf_decal/delivery,
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"kd" = (
/obj/structure/cable{
icon_state = "0-2"
@@ -3982,21 +3977,6 @@
/obj/item/organ/heart,
/turf/open/floor/carpet,
/area/chapel/office)
-"kp" = (
-/obj/machinery/door/airlock/engineering{
- name = "Auxillary Base Construction";
- req_one_access_txt = "32;47;48"
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 1
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
-/obj/structure/cable{
- icon_state = "1-2"
- },
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"kq" = (
/obj/effect/turf_decal/bot_white/left,
/obj/effect/turf_decal/tile/neutral{
@@ -4099,24 +4079,6 @@
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plating,
/area/maintenance/central)
-"kC" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/machinery/button/door{
- id = "aux_base_shutters";
- name = "Public Shutters Control";
- pixel_y = 24;
- req_one_access_txt = "32;47;48"
- },
-/obj/effect/turf_decal/trimline/neutral/filled/line{
- dir = 6
- },
-/obj/effect/turf_decal/stripes/corner{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"kD" = (
/obj/effect/turf_decal/tile/green{
dir = 8
@@ -4141,24 +4103,6 @@
/obj/machinery/vending/snack/random,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
-"kK" = (
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
-/obj/structure/cable{
- icon_state = "1-2"
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"kL" = (
/obj/structure/table,
/obj/item/extinguisher/mini,
@@ -4444,27 +4388,6 @@
},
/turf/open/floor/plasteel,
/area/hydroponics/garden/monastery)
-"lu" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer1,
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer3,
-/obj/structure/cable{
- icon_state = "1-8"
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 4
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 1
- },
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/obj/structure/cable{
- icon_state = "4-8"
- },
-/turf/open/floor/plasteel,
-/area/hallway/primary/central)
"lv" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3,
@@ -4558,6 +4481,14 @@
icon_state = "wood-broken3"
},
/area/maintenance/bar)
+"lJ" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
+ },
+/area/maintenance/central)
"lK" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
dir = 4
@@ -4843,6 +4774,12 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
+"ms" = (
+/turf/open/floor/plating,
+/turf/open/floor/plating{
+ icon_state = "platingdmg2"
+ },
+/area/maintenance/central)
"mt" = (
/obj/structure/sign/poster/contraband/random{
pixel_x = -32
@@ -4858,6 +4795,13 @@
},
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
+"mv" = (
+/obj/machinery/computer/shuttle/mining,
+/obj/machinery/light{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"mw" = (
/obj/structure/lattice/catwalk,
/obj/item/stack/cable_coil,
@@ -4925,6 +4869,10 @@
/obj/item/toy/cards/deck,
/turf/open/floor/wood,
/area/maintenance/bar)
+"mI" = (
+/obj/machinery/light/small,
+/turf/open/floor/plating,
+/area/maintenance/central)
"mK" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/public/glass{
@@ -5349,10 +5297,6 @@
},
/turf/open/floor/carpet,
/area/chapel/office)
-"nH" = (
-/obj/machinery/camera/autoname,
-/turf/open/floor/plasteel,
-/area/hydroponics/garden/monastery)
"nI" = (
/obj/machinery/door/airlock/maintenance{
req_one_access_txt = "12;5;39;6"
@@ -5648,6 +5592,13 @@
},
/turf/open/floor/plating,
/area/maintenance/solars/starboard)
+"oy" = (
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/central)
"oA" = (
/obj/structure/bodycontainer/morgue{
dir = 1
@@ -6183,6 +6134,13 @@
/obj/effect/turf_decal/tile/green,
/turf/open/floor/plasteel,
/area/hallway/primary/central)
+"pS" = (
+/obj/effect/spawner/lootdrop/glowstick,
+/turf/open/floor/plating,
+/turf/open/floor/plating{
+ icon_state = "platingdmg2"
+ },
+/area/maintenance/central)
"pT" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -6579,6 +6537,9 @@
},
/turf/open/floor/plasteel/cafeteria,
/area/crew_quarters/kitchen)
+"qO" = (
+/turf/open/transparent/openspace,
+/area/maintenance/central)
"qP" = (
/obj/effect/spawner/lootdrop/glowstick,
/turf/open/floor/plating,
@@ -6786,6 +6747,10 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
/turf/open/floor/plasteel/white,
/area/medical/medbay/zone2)
+"rC" = (
+/obj/machinery/biogenerator,
+/turf/open/floor/wood,
+/area/hydroponics/garden/monastery)
"rD" = (
/obj/structure/lattice,
/turf/open/space/basic,
@@ -6815,6 +6780,9 @@
dir = 4;
layer = 3.2
},
+/obj/structure/curtain{
+ icon_state = "closed"
+ },
/turf/open/floor/mineral/titanium/blue,
/area/crew_quarters/dorms)
"rH" = (
@@ -7088,6 +7056,13 @@
},
/turf/open/floor/plasteel,
/area/hydroponics)
+"sn" = (
+/obj/structure/railing/corner{
+ icon_state = "railing_corner";
+ dir = 8
+ },
+/turf/open/floor/plating,
+/area/maintenance/central)
"so" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -7103,6 +7078,16 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/cafeteria)
+"sq" = (
+/turf/closed/wall,
+/area/asteroid/nearstation)
+"sr" = (
+/obj/structure/railing/corner{
+ icon_state = "railing_corner";
+ dir = 4
+ },
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"ss" = (
/obj/effect/turf_decal/trimline/green/filled/line{
dir = 1
@@ -7556,6 +7541,14 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/bar)
+"tw" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
+ },
+/area/maintenance/central)
"tx" = (
/obj/effect/turf_decal/plaque{
icon_state = "L13";
@@ -7807,13 +7800,6 @@
/obj/structure/pool/Lboard,
/turf/open/pool,
/area/crew_quarters/fitness/pool)
-"ui" = (
-/obj/machinery/light/floor,
-/obj/effect/turf_decal/trimline/neutral/filled/line{
- dir = 4
- },
-/turf/open/floor/plasteel,
-/area/hydroponics/garden/monastery)
"uj" = (
/turf/open/floor/plasteel,
/area/crew_quarters/locker)
@@ -7974,6 +7960,10 @@
icon_state = "panelscorched"
},
/area/maintenance/department/crew_quarters/dorms)
+"uH" = (
+/obj/structure/railing/corner,
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"uI" = (
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/plating,
@@ -7985,6 +7975,9 @@
/obj/effect/turf_decal/trimline/neutral/filled/line{
dir = 4
},
+/obj/machinery/light{
+ dir = 8
+ },
/turf/open/floor/plasteel,
/area/hydroponics/garden/monastery)
"uK" = (
@@ -8680,6 +8673,9 @@
},
/turf/open/floor/plasteel/white,
/area/medical/medbay/zone2)
+"ww" = (
+/turf/closed/wall,
+/area/construction/mining/aux_base)
"wx" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/sink{
@@ -9100,6 +9096,10 @@
},
/turf/open/floor/plasteel/dark,
/area/chapel/main)
+"xN" = (
+/obj/machinery/seed_extractor,
+/turf/open/floor/wood,
+/area/hydroponics/garden/monastery)
"xO" = (
/obj/machinery/door/airlock/external{
name = "Solar Maintenance";
@@ -9862,9 +9862,6 @@
},
/turf/open/floor/plating,
/area/maintenance/central)
-"zG" = (
-/turf/closed/wall/r_wall,
-/area/asteroid/nearstation)
"zH" = (
/obj/machinery/vending/wallmed{
pixel_x = -28
@@ -10126,6 +10123,14 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
+"An" = (
+/obj/machinery/light{
+ dir = 4;
+ light_color = "#c1caff"
+ },
+/obj/structure/railing/corner,
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"Ao" = (
/turf/closed/wall,
/area/tcommsat/chamber)
@@ -10172,6 +10177,13 @@
/obj/machinery/door/firedoor,
/turf/open/floor/plasteel,
/area/hallway/secondary/service)
+"Ax" = (
+/obj/machinery/light{
+ dir = 1;
+ light_color = "#cee5d2"
+ },
+/turf/open/floor/wood,
+/area/hydroponics/garden/monastery)
"Ay" = (
/obj/machinery/vending/wardrobe/bar_wardrobe,
/turf/open/floor/wood,
@@ -10406,10 +10418,6 @@
"Be" = (
/turf/closed/wall,
/area/storage/tools)
-"Bf" = (
-/obj/effect/spawner/structure/window,
-/turf/open/floor/plating,
-/area/hydroponics/garden/monastery)
"Bg" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -10593,9 +10601,6 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
-"BB" = (
-/turf/closed/wall/r_wall,
-/area/crew_quarters/dorms)
"BC" = (
/obj/structure/chair{
dir = 4
@@ -10606,6 +10611,9 @@
/obj/structure/dresser,
/turf/open/floor/wood,
/area/crew_quarters/dorms)
+"BE" = (
+/turf/open/transparent/openspace,
+/area/construction/mining/aux_base)
"BF" = (
/obj/effect/turf_decal/loading_area,
/turf/open/floor/plasteel,
@@ -10798,6 +10806,14 @@
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
+"Ci" = (
+/obj/structure/closet/toolcloset,
+/obj/machinery/light/small{
+ dir = 8;
+ pixel_x = 5
+ },
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"Ck" = (
/obj/effect/turf_decal/tile/neutral,
/obj/effect/turf_decal/trimline/blue/filled/line{
@@ -11099,15 +11115,15 @@
/area/crew_quarters/kitchen)
"Da" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/lizard{
- name = "Wags-His-Tail";
- real_name = "Wags-His-Tail"
- },
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/disposal/bin,
/obj/structure/disposalpipe/trunk,
+/mob/living/simple_animal/hostile/lizard{
+ name = "Wags-His-Tail";
+ real_name = "Wags-His-Tail"
+ },
/turf/open/floor/plating,
/area/janitor)
"Dc" = (
@@ -11256,6 +11272,10 @@
/obj/machinery/light,
/turf/open/floor/plasteel/cafeteria,
/area/crew_quarters/cafeteria)
+"Dz" = (
+/obj/structure/railing/corner,
+/turf/open/floor/plating,
+/area/maintenance/central)
"DB" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -12018,6 +12038,14 @@
},
/turf/open/floor/plasteel/dark,
/area/chapel/main)
+"Fi" = (
+/obj/machinery/light{
+ dir = 4;
+ light_color = "#c1caff"
+ },
+/obj/structure/flora/grass/jungle,
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"Fk" = (
/obj/effect/turf_decal/tile/neutral,
/obj/effect/turf_decal/tile/neutral{
@@ -12100,6 +12128,13 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/service)
+"Fw" = (
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 8
+ },
+/turf/open/floor/plating,
+/area/maintenance/central)
"Fx" = (
/obj/structure/girder,
/obj/structure/grille,
@@ -12236,6 +12271,10 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
+"FP" = (
+/obj/machinery/computer/camera_advanced/base_construction,
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"FQ" = (
/obj/item/storage/box/bodybags{
pixel_y = 5
@@ -13156,6 +13195,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/machinery/door/airlock/public/glass,
/turf/open/floor/plasteel,
/area/hallway/secondary/service)
"Il" = (
@@ -13614,6 +13654,16 @@
},
/turf/open/floor/plasteel,
/area/janitor)
+"IY" = (
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 8
+ },
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"IZ" = (
/obj/machinery/light{
dir = 4;
@@ -13705,6 +13755,11 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/bar)
+"Jn" = (
+/obj/structure/flora/tree/jungle/small,
+/obj/structure/railing,
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"Jo" = (
/obj/effect/turf_decal/trimline/neutral/filled/corner{
dir = 4
@@ -13764,7 +13819,6 @@
/turf/open/floor/carpet,
/area/chapel/main)
"Jz" = (
-/obj/structure/curtain,
/turf/open/floor/mineral/titanium/blue,
/area/crew_quarters/dorms)
"JA" = (
@@ -13947,6 +14001,13 @@
/obj/item/hand_labeler,
/turf/open/floor/plasteel,
/area/vacant_room/commissary)
+"JT" = (
+/obj/docking_port/stationary/public_mining_dock{
+ icon_state = "pinonfar";
+ dir = 2
+ },
+/turf/open/floor/plating,
+/area/construction/mining/aux_base)
"JU" = (
/obj/structure/chair/office/dark,
/turf/open/floor/carpet/blue,
@@ -14136,6 +14197,12 @@
},
/turf/open/floor/plating,
/area/maintenance/central)
+"Ky" = (
+/obj/machinery/door/airlock/external{
+ name = "Construction Zone"
+ },
+/turf/open/floor/plating,
+/area/construction/mining/aux_base)
"KB" = (
/obj/machinery/door/airlock/maintenance{
name = "Janitor Maintenance";
@@ -14353,6 +14420,13 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3,
/turf/open/floor/plasteel/white,
/area/crew_quarters/kitchen)
+"KX" = (
+/obj/structure/railing/corner{
+ icon_state = "railing_corner";
+ dir = 1
+ },
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"KZ" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -14392,6 +14466,13 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/service)
+"Le" = (
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 5
+ },
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"Lf" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer3{
dir = 8
@@ -14409,6 +14490,25 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
+"Lg" = (
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 8
+ },
+/obj/machinery/power/apc{
+ areastring = "/area/hallway/secondary/construction";
+ dir = 1;
+ name = "Auxiliary Construction Zone APC";
+ pixel_y = 24
+ },
+/obj/structure/cable{
+ icon_state = "0-2"
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"Lh" = (
/obj/machinery/airalarm/directional/west,
/obj/machinery/seed_extractor,
@@ -14775,6 +14875,10 @@
},
/turf/open/floor/plasteel/dark,
/area/chapel/office)
+"Mb" = (
+/obj/structure/flora/grass/jungle,
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"Mc" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1{
dir = 4
@@ -15371,6 +15475,17 @@
},
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
+"NG" = (
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 9
+ },
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
+"NH" = (
+/obj/effect/landmark/event_spawn,
+/turf/open/floor/plating,
+/area/maintenance/solars/starboard/fore)
"NI" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer3{
dir = 4
@@ -15937,6 +16052,11 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
/turf/open/floor/plasteel/chapel,
/area/chapel/main)
+"Pl" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/public/glass,
+/turf/open/floor/plasteel,
+/area/hallway/secondary/service)
"Pm" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1{
dir = 6
@@ -16238,6 +16358,9 @@
dir = 8;
layer = 3.2
},
+/obj/structure/curtain{
+ icon_state = "closed"
+ },
/turf/open/floor/mineral/titanium/blue,
/area/crew_quarters/dorms)
"PY" = (
@@ -16328,6 +16451,15 @@
},
/turf/open/floor/plasteel/dark,
/area/gateway)
+"Qj" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
+/turf/open/floor/plating,
+/area/maintenance/central)
"Ql" = (
/obj/machinery/light/small/built,
/turf/open/floor/plating,
@@ -16389,11 +16521,6 @@
/obj/machinery/camera/autoname,
/turf/open/floor/plasteel/dark,
/area/chapel/main)
-"Qw" = (
-/obj/effect/decal/cleanable/dirt,
-/obj/effect/landmark/event_spawn,
-/turf/open/floor/plating,
-/area/hallway/secondary/construction)
"Qx" = (
/obj/structure/table,
/obj/item/reagent_containers/food/condiment/peppermill{
@@ -16457,9 +16584,6 @@
},
/turf/open/floor/carpet,
/area/crew_quarters/theatre)
-"QE" = (
-/turf/closed/wall/r_wall,
-/area/hydroponics/garden/monastery)
"QH" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3,
/obj/effect/turf_decal/tile/neutral,
@@ -16596,6 +16720,13 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
+"QT" = (
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 8
+ },
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"QU" = (
/turf/open/floor/wood,
/area/crew_quarters/bar)
@@ -16754,10 +16885,21 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/kitchen)
+"Rv" = (
+/obj/structure/flora/grass/jungle/b,
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"Rw" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/gateway)
+"Rx" = (
+/obj/structure/railing/corner{
+ icon_state = "railing_corner";
+ dir = 8
+ },
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"Ry" = (
/obj/effect/turf_decal/trimline/neutral/filled/line{
dir = 4
@@ -16784,6 +16926,13 @@
},
/turf/open/floor/plasteel,
/area/gateway)
+"RA" = (
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 4
+ },
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
"RB" = (
/obj/machinery/atmospherics/pipe/layer_manifold{
dir = 4
@@ -17002,6 +17151,12 @@
/obj/machinery/camera/autoname,
/turf/open/floor/plasteel,
/area/hallway/secondary/service)
+"Sa" = (
+/obj/structure/cable{
+ icon_state = "1-8"
+ },
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"Sc" = (
/obj/machinery/cryopod{
dir = 8
@@ -17367,6 +17522,11 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plasteel,
/area/crew_quarters/bar)
+"Tc" = (
+/obj/effect/turf_decal/bot,
+/obj/machinery/holopad,
+/turf/open/floor/plasteel,
+/area/hydroponics/garden/monastery)
"Td" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -17825,7 +17985,6 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/effect/turf_decal/vg_decals/numbers/two,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
"Ui" = (
@@ -17900,6 +18059,14 @@
},
/turf/open/floor/plasteel/freezer,
/area/crew_quarters/toilet)
+"Up" = (
+/obj/structure/table,
+/obj/item/pipe_dispenser,
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/construction/mining/aux_base)
"Ur" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3,
/obj/effect/turf_decal/tile/neutral,
@@ -18195,6 +18362,17 @@
/obj/structure/kitchenspike,
/turf/open/floor/plasteel/freezer,
/area/crew_quarters/kitchen)
+"Vd" = (
+/obj/machinery/hydroponics/soil,
+/turf/open/floor/grass,
+/area/hydroponics/garden/monastery)
+"Vf" = (
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
+/obj/machinery/light/small,
+/turf/open/floor/plating,
+/area/maintenance/central)
"Vg" = (
/mob/living/simple_animal/hostile/retaliate/goat{
name = "Pete"
@@ -18408,6 +18586,15 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/bar)
+"VA" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/turf/open/floor/plating{
+ icon_state = "platingdmg2"
+ },
+/area/maintenance/central)
"VB" = (
/obj/structure/window/reinforced{
dir = 4
@@ -18458,8 +18645,8 @@
/turf/open/floor/plating,
/area/maintenance/department/crew_quarters/dorms)
"VH" = (
-/mob/living/simple_animal/crab/Coffee,
/obj/machinery/camera/autoname,
+/mob/living/simple_animal/crab/Coffee,
/turf/open/floor/plating/beach/sand,
/area/crew_quarters/fitness/pool)
"VI" = (
@@ -18521,6 +18708,7 @@
pixel_y = 32
},
/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/public/glass,
/turf/open/floor/plasteel,
/area/hallway/secondary/service)
"VR" = (
@@ -18608,10 +18796,6 @@
},
/turf/open/floor/wood,
/area/crew_quarters/dorms)
-"Wa" = (
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plasteel,
-/area/construction/mining/aux_base)
"Wb" = (
/obj/effect/landmark/start/mime,
/turf/open/floor/carpet,
@@ -19007,9 +19191,6 @@
},
/turf/open/floor/plating,
/area/maintenance/solars/starboard)
-"Xc" = (
-/turf/open/floor/plating/airless,
-/area/asteroid/nearstation)
"Xd" = (
/obj/effect/landmark/xeno_spawn,
/turf/open/floor/wood,
@@ -45997,7 +46178,7 @@ qo
qo
qo
qo
-qo
+sq
qo
qo
qo
@@ -46797,7 +46978,7 @@ Xh
qo
qo
qo
-qo
+sq
qo
qo
qo
@@ -47577,7 +47758,7 @@ qo
qo
qo
qo
-qo
+sq
UX
UX
UX
@@ -47817,7 +47998,7 @@ Xh
Xh
Xh
Xh
-qo
+sq
qo
qo
qo
@@ -48066,7 +48247,7 @@ qo
qo
qo
qo
-qo
+sq
qo
qo
qo
@@ -48609,7 +48790,7 @@ qo
qo
qo
qo
-qo
+sq
Xh
Xh
Xh
@@ -50186,7 +50367,7 @@ lO
Fo
Fo
pW
-qo
+sq
Xh
Xh
Xh
@@ -51709,7 +51890,7 @@ qo
FN
FN
qo
-qo
+sq
UX
UX
UX
@@ -53186,7 +53367,7 @@ fl
fl
fl
fl
-KN
+fl
Xx
Xx
Xx
@@ -53256,7 +53437,7 @@ qo
qo
qo
Xh
-Xc
+sq
qo
qo
qo
@@ -53443,7 +53624,7 @@ Gy
BU
gk
aM
-KN
+fl
Xx
Xx
Xx
@@ -53513,7 +53694,7 @@ qo
qo
qo
qo
-gx
+qo
qo
qo
qo
@@ -53700,7 +53881,7 @@ qS
ZG
Bs
Bs
-KN
+fl
Xx
Xx
Xx
@@ -53957,7 +54138,7 @@ ln
SA
Bs
Bs
-KN
+fl
Xx
Xx
Xx
@@ -54214,42 +54395,42 @@ PO
PO
PO
Bs
-KN
+fl
Xx
Xx
Xx
+cn
JV
JV
JV
JV
+cn
JV
JV
JV
JV
+cn
+JV
+JV
+JV
+cn
+JV
+JV
+cn
+JV
+JV
+JV
+cn
JV
JV
JV
JV
+cn
JV
JV
JV
JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
-JV
+cn
Xx
Xx
Xx
@@ -54471,11 +54652,11 @@ fl
fl
fl
rl
-KN
-KN
-KN
-KN
-QE
+fl
+fl
+fl
+fl
+cn
Iz
Iz
OR
@@ -54504,7 +54685,7 @@ Iz
Iz
OR
Iz
-Iz
+Rv
Iz
JV
Xx
@@ -54734,11 +54915,11 @@ Bs
PW
cn
Iz
+Mb
Iz
-Iz
-Iz
-Iz
-Iz
+Vd
+ae
+Vd
Iz
Iz
Iz
@@ -54748,6 +54929,7 @@ uM
Iz
Iz
Iz
+Mb
Iz
Iz
Iz
@@ -54755,11 +54937,10 @@ Iz
Iz
Iz
Iz
+uM
Iz
-Iz
-Iz
-Iz
-Iz
+Mb
+Rv
Iz
Iz
Iz
@@ -54989,20 +55170,20 @@ pK
pK
pK
Bs
-cn
+fN
PE
uM
Iz
+Vd
+ae
+Vd
+Iz
+Sd
Iz
Iz
Iz
Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
+Mb
Iz
Iz
Iz
@@ -55016,7 +55197,7 @@ Iz
Iz
Iz
Iz
-Iz
+Mb
Iz
uM
Yz
@@ -55250,12 +55431,9 @@ cn
Iz
Iz
Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Sd
+Vd
+ae
+Vd
Iz
Iz
Iz
@@ -55271,6 +55449,9 @@ Iz
Iz
Iz
Iz
+Rv
+Iz
+Iz
Iz
Iz
Sd
@@ -55282,9 +55463,9 @@ Xx
Xx
Xx
Xx
-BB
-BB
-BB
+Sz
+Sz
+Sz
sC
sC
AE
@@ -55504,25 +55685,26 @@ Bh
pK
Bs
cn
+rC
+ae
Iz
+Vd
+ae
+Vd
Iz
-Iz
-Iz
-Iz
-Iz
+cn
qn
Iz
Iz
Iz
Iz
Iz
-Iz
-Iz
Sd
Iz
Iz
Iz
Iz
+Mb
Iz
Iz
Iz
@@ -55533,13 +55715,12 @@ Iz
Iz
Iz
Iz
-Iz
-JV
+cn
Xx
Xx
Xx
Xx
-BB
+Sz
jf
rG
WM
@@ -55761,16 +55942,16 @@ lG
pK
Bs
cn
+xN
+ae
Iz
-Iz
-Iz
-Sd
-Iz
-Iz
+Vd
+ae
+Vd
Iz
pq
Iz
-Iz
+uM
Iz
Iz
pq
@@ -55796,7 +55977,7 @@ Xx
Xx
Xx
Xx
-BB
+Sz
KS
Jz
WM
@@ -55806,7 +55987,7 @@ eJ
qM
FA
FA
-FA
+db
FA
FA
FA
@@ -56018,14 +56199,11 @@ lZ
pK
Bs
cn
-PE
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
+Ax
+ae
+Iz
+Iz
+ae
Iz
Iz
Iz
@@ -56033,6 +56211,9 @@ Iz
Iz
Iz
Iz
+ae
+ae
+ae
Iz
Iz
uM
@@ -56051,9 +56232,9 @@ Sd
JV
Xx
Xx
-BB
-BB
-BB
+Sz
+Sz
+Sz
ke
Sz
WM
@@ -56275,40 +56456,40 @@ FC
pK
Bs
cn
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-uM
-Iz
-Iz
-Iz
-Iz
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
Sd
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
+ae
aE
JV
Xx
Xx
-BB
+Sz
IQ
zj
zj
@@ -56544,13 +56725,13 @@ Iz
Iz
Iz
Iz
+ae
+ae
+ae
Iz
Iz
-Iz
-Iz
-Iz
-Iz
-Iz
+ae
+ae
Iz
Iz
Iz
@@ -56562,10 +56743,10 @@ Iz
Iz
Iz
Iz
-JV
+cn
Xx
Xx
-BB
+Sz
fP
FM
yg
@@ -56798,6 +56979,7 @@ Iz
Iz
Iz
Iz
+Mb
Iz
Iz
Iz
@@ -56805,11 +56987,10 @@ Iz
Iz
Iz
Iz
-Iz
-Iz
-Iz
+ae
+ae
Sd
-Iz
+Rv
Iz
Iz
Iz
@@ -56822,7 +57003,7 @@ Yz
JV
Xx
Xx
-BB
+Sz
SX
zj
lo
@@ -57053,7 +57234,7 @@ Iz
Iz
Iz
Iz
-Iz
+Mb
Iz
Iz
Iz
@@ -57063,8 +57244,8 @@ uM
Iz
Iz
Iz
-pq
-Iz
+ea
+ae
Iz
Iz
Iz
@@ -57074,12 +57255,12 @@ Iz
Iz
Iz
Iz
-Iz
-Iz
+Mb
+Rv
JV
Xx
Xx
-BB
+Sz
kh
zj
lo
@@ -57318,13 +57499,13 @@ uM
Iz
Iz
Iz
+Mb
Iz
+ae
+ae
Iz
-Iz
-Iz
-Iz
-Iz
-Iz
+Mb
+Rv
Iz
Iz
Iz
@@ -57336,7 +57517,7 @@ Iz
JV
Xx
Xx
-BB
+Sz
zj
JZ
DJ
@@ -57562,12 +57743,23 @@ ZX
cn
Iz
Iz
-DN
+Fi
Iz
Iz
Iz
Iz
-DN
+An
+RA
+sr
+Iz
+Iz
+ga
+Iz
+Iz
+Iz
+Iz
+ae
+ae
Iz
Iz
Iz
@@ -57576,24 +57768,13 @@ ga
Iz
Iz
Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-ga
-Iz
-Iz
-Iz
-Iz
+Mb
Iz
Iz
JV
Xx
Xx
-BB
+Sz
BD
lc
Kt
@@ -57816,41 +57997,41 @@ pK
ra
OA
OA
-Vh
-Vh
-Vh
-Vh
-Vh
-Vh
+OA
+Tl
+Tl
+Tl
+Tl
+Tl
OA
OA
OA
dV
-Iz
-Iz
-Iz
-Bf
+Le
+RA
+RA
+cn
Iz
Iz
Iz
Iz
+ae
+ae
Iz
Iz
Iz
Iz
-Iz
-Iz
-Bf
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-JV
+cn
+RA
+RA
+RA
+RA
+RA
+RA
+cn
wq
wq
-BB
+Sz
Sz
Sz
nt
@@ -58083,25 +58264,25 @@ vf
PH
mK
wf
-ui
+mj
mj
mj
uJ
mj
lt
-ui
+mj
mj
CY
mj
mj
-ui
+mj
mj
mj
gv
mj
mj
mj
-ui
+mj
mj
iy
eB
@@ -58349,9 +58530,9 @@ gT
eE
eE
Ud
-Yh
-iV
eE
+iV
+Yh
eE
eE
gT
@@ -58600,18 +58781,18 @@ zB
zB
zB
hL
-zB
+bT
zB
zB
zB
zB
kN
-oe
+zB
hL
+oe
zB
zB
-zB
-zB
+bT
zB
zB
zB
@@ -58853,32 +59034,32 @@ PD
Ej
aA
OA
-qn
+go
+QT
+QT
+QT
+cn
Iz
Iz
Iz
Iz
Iz
-Iz
-Iz
-Yd
pq
+Yd
fK
Iz
Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-JV
+cn
+QT
+QT
+QT
+QT
+QT
+QT
+cn
wq
wq
-BB
+Sz
Sz
Sz
te
@@ -59114,6 +59295,8 @@ Iz
Iz
Iz
Iz
+OR
+Iz
Iz
Iz
Iz
@@ -59123,9 +59306,7 @@ Yd
fK
Iz
Iz
-Iz
-Iz
-Iz
+OR
Iz
Iz
Iz
@@ -59135,7 +59316,7 @@ Iz
JV
Xx
Xx
-BB
+Sz
BD
JB
Ab
@@ -59374,14 +59555,14 @@ Iz
pq
Iz
Iz
+Sd
+Rv
Iz
Yd
Yd
fK
Iz
Iz
-Iz
-Iz
pq
Iz
Sd
@@ -59392,7 +59573,7 @@ Iz
JV
Xx
Xx
-BB
+Sz
zj
FM
Lb
@@ -59630,26 +59811,26 @@ Iz
Iz
Iz
Iz
-Sd
+Iz
+Iz
+Iz
Iz
Yd
OX
jJ
Iz
-Iz
-Iz
Sd
Iz
Iz
Iz
Iz
-Iz
-Iz
+Rv
+Mb
Iz
JV
Xx
Xx
-BB
+Sz
SX
zj
DP
@@ -59885,10 +60066,12 @@ Iz
Iz
Iz
Iz
-Iz
-Iz
-Iz
-Iz
+Rv
+uH
+RA
+RA
+RA
+sr
Yd
Yd
Yd
@@ -59900,13 +60083,11 @@ Iz
Iz
Iz
Iz
-Iz
-Iz
Yz
JV
Xx
Xx
-BB
+Sz
kh
JZ
oC
@@ -60140,15 +60321,17 @@ vP
Tl
Iz
Iz
+Mb
Iz
Iz
-Iz
-Iz
-Iz
-Iz
-Yd
+bv
+aZ
+aZ
+aZ
+Le
pq
Yd
+Yd
Iz
Iz
Iz
@@ -60158,12 +60341,10 @@ Iz
Iz
Iz
Iz
-Iz
-Iz
-JV
+cn
Xx
Xx
-BB
+Sz
fP
zj
zj
@@ -60397,22 +60578,22 @@ vP
Tl
Iz
Iz
-Iz
+Mb
Iz
pq
-Iz
-Iz
-Bf
-Yd
+bv
+aZ
+aZ
+aZ
aZ
Yd
-Iz
-Iz
+Yd
+Yd
Iz
Iz
oF
Iz
-Iz
+Mb
Iz
Iz
uM
@@ -60420,7 +60601,7 @@ Iz
JV
Xx
Xx
-BB
+Sz
IQ
zj
zj
@@ -60657,14 +60838,14 @@ Iz
Iz
Iz
Iz
-Iz
-Yz
-Bf
-nH
+bv
+aZ
+aZ
+aZ
aZ
Yd
-Iz
-Iz
+Tc
+Yd
Iz
Iz
Sd
@@ -60677,8 +60858,8 @@ aE
JV
Xx
Xx
-BB
-BB
+Sz
+Sz
ke
Sz
Sz
@@ -60700,7 +60881,7 @@ Dk
VI
VI
VI
-VI
+cp
uC
VI
VI
@@ -60896,7 +61077,7 @@ KG
RN
YL
Rf
-oQ
+CA
yo
yo
Rk
@@ -60914,14 +61095,14 @@ Iz
Iz
Iz
Iz
-uM
-Iz
-Bf
-Yd
+Jn
+aZ
+aZ
+aZ
aZ
Yd
-Iz
-Iz
+Yd
+Yd
Iz
Iz
Iz
@@ -60935,7 +61116,7 @@ JV
Xx
Xx
Xx
-BB
+Sz
KS
Jz
Sz
@@ -61171,14 +61352,14 @@ Iz
Iz
Sd
Iz
-Iz
-Iz
-Iz
-Yd
+bv
+aZ
+aZ
+aZ
+NG
pq
Yd
-Iz
-Iz
+Yd
Iz
Iz
Iz
@@ -61188,11 +61369,11 @@ Iz
Iz
Iz
Iz
-JV
+cn
Xx
Xx
Xx
-BB
+Sz
yv
PX
Sz
@@ -61428,33 +61609,33 @@ Iz
Iz
Iz
Iz
+Rx
+QT
+QT
+QT
+KX
+Iz
+Iz
+Iz
+Rv
Iz
Iz
Iz
Iz
Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
-Iz
+Mb
Iz
Yz
JV
Xx
Xx
Xx
-BB
-BB
-BB
-BB
-zG
-BB
+Sz
+Sz
+Sz
+Sz
+sq
+Sz
Sz
Sz
kY
@@ -61693,7 +61874,7 @@ Sd
Iz
Iz
Iz
-Iz
+Rv
Iz
Iz
Iz
@@ -61709,9 +61890,9 @@ Xx
qo
qo
qo
-zG
+sq
uX
-BB
+Sz
yL
lE
lE
@@ -61966,7 +62147,7 @@ pW
pW
pW
qo
-zG
+sq
uX
Vi
fp
@@ -62197,7 +62378,7 @@ OA
Iz
Iz
Iz
-Iz
+Mb
DN
Pa
Iz
@@ -62223,7 +62404,7 @@ iT
xe
pW
qo
-zG
+sq
uX
Vi
It
@@ -62453,34 +62634,34 @@ vP
OA
fN
cn
-QE
-JV
-JV
-JV
-JV
+cn
JV
JV
JV
JV
+cn
JV
JV
JV
JV
+cn
JV
JV
JV
JV
+cn
JV
JV
JV
JV
+cn
Xx
pW
ir
po
pW
pW
-dw
+pW
uX
Vi
YC
@@ -62710,7 +62891,7 @@ Wj
OA
Pu
Bs
-KN
+fl
Xx
Xx
Xx
@@ -62737,9 +62918,9 @@ pY
Fo
YP
Fo
-dw
+pW
uX
-BB
+Sz
Sc
Sc
Sc
@@ -62966,10 +63147,10 @@ mg
bD
Go
TJ
-Bs
-KN
-Xx
-Xx
+gJ
+fl
+fl
+fl
Xx
Xx
Xx
@@ -62994,9 +63175,9 @@ pW
pW
pW
Fo
-dw
-dw
-BB
+pW
+pW
+Sz
Sz
Sz
Sz
@@ -63185,7 +63366,7 @@ qo
qo
qo
qo
-qo
+fl
fl
Bs
OA
@@ -63223,10 +63404,10 @@ hd
vP
OA
Yt
-ZX
-KN
-Xx
-Xx
+dB
+qO
+ms
+fl
Xx
Xx
Xx
@@ -63442,10 +63623,10 @@ qo
qo
qo
qo
-qo
fl
Bs
Bs
+mI
OA
oR
lk
@@ -63479,11 +63660,11 @@ He
hd
vP
OA
-Yt
+tw
+sn
+Fw
Bs
-KN
-Xx
-Xx
+fl
Xx
Xx
Xx
@@ -63696,12 +63877,12 @@ qo
FN
qo
qo
-qo
fl
fl
fl
fl
Bs
+Bs
tP
OA
PD
@@ -63737,10 +63918,10 @@ uc
vP
OA
Yt
-nN
-KN
-Xx
-Xx
+Dz
+oy
+Bs
+fl
Xx
Xx
Xx
@@ -63953,12 +64134,12 @@ qo
FN
FN
qo
-qo
fl
CH
JX
fl
Bs
+fl
OA
OA
Qr
@@ -63994,10 +64175,10 @@ hd
Fa
OA
Yt
-Bs
-KN
-Xx
-Xx
+dB
+qO
+fl
+fl
Xx
Xx
Xx
@@ -64210,13 +64391,13 @@ qo
FN
FN
qo
-qo
fl
fv
Li
rl
BW
-OA
+dB
+Wq
Wq
gp
jx
@@ -64251,9 +64432,9 @@ jH
vP
OA
Yt
-Bs
-KN
-Xx
+dB
+qO
+fl
Xx
Xx
Xx
@@ -64281,7 +64462,7 @@ qo
qo
qo
qo
-dw
+pW
Uk
rV
pW
@@ -64467,13 +64648,13 @@ qo
qo
FN
qo
-qo
fl
kL
DQ
fl
Bs
-OA
+dB
+Wq
Wq
fo
RR
@@ -64508,10 +64689,10 @@ MO
vP
OA
Yt
-cx
-KN
-KN
-KN
+gO
+fl
+fl
+fl
qo
qo
qo
@@ -64724,13 +64905,13 @@ FN
qo
FN
qo
-qo
fl
fl
fl
fl
Bs
-OA
+dB
+Wq
Wq
OG
mA
@@ -64981,12 +65162,12 @@ qo
FN
FN
qo
-qo
fl
um
um
fl
Bs
+fl
OA
OA
Bu
@@ -65027,7 +65208,7 @@ PI
PI
PI
PI
-PI
+lJ
PI
Of
oP
@@ -65238,13 +65419,13 @@ FN
FN
FN
qo
-qo
fl
Bs
kA
rl
BW
Bs
+Bs
OA
PD
lk
@@ -65495,12 +65676,12 @@ qo
qo
qo
qo
-qo
fl
fl
fl
fl
PW
+PW
Bs
OA
PD
@@ -65755,7 +65936,7 @@ qo
qo
qo
qo
-qo
+fl
fl
ZX
kA
@@ -66012,7 +66193,7 @@ qo
qo
qo
qo
-qo
+fl
fl
PW
Bs
@@ -66058,7 +66239,7 @@ Um
Rz
yr
gf
-Yt
+bN
fl
qo
qo
@@ -66260,19 +66441,19 @@ FN
qo
qo
qo
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
+FN
+qo
+qo
+qo
+qo
+FN
+qo
+qo
+qo
+fl
+Bs
+Bs
+fl
OA
oR
lk
@@ -66517,19 +66698,19 @@ FN
qo
qo
qo
-ay
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-dt
-fn
-hW
+FN
+qo
+qo
+qo
+qo
+FN
+qo
+qo
+qo
+fl
+Bs
+Bs
+fl
OA
cJ
ij
@@ -66773,21 +66954,21 @@ FN
qo
qo
qo
+FN
qo
-ay
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-dt
-fO
-Wa
-kc
+qo
+qo
+qo
+qo
+FN
+qo
+qo
+qo
+fl
+Bs
+Bs
+fl
+OA
PG
MJ
pg
@@ -67031,21 +67212,21 @@ qo
qo
qo
qo
-ay
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-dt
-fO
-ic
-kc
-aU
+qo
+FN
+FN
+qo
+FN
+qo
+qo
+qo
+qo
+fl
+Bs
+Bs
+fl
+OA
+PD
lk
pg
Gx
@@ -67287,22 +67468,22 @@ FN
qo
qo
qo
+FN
+FN
qo
-ay
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-dt
-LK
-if
+FN
+FN
+qo
+qo
+qo
+qo
+qo
+fl
+PW
+Bs
+fl
OA
-kC
+PD
lk
pg
rN
@@ -67544,23 +67725,23 @@ FN
qo
qo
qo
+FN
qo
-ay
-bb
-bb
-bb
-bb
-bF
-bb
-bb
-bb
-di
-dK
-fR
-ig
-kp
-kK
-lu
+qo
+qo
+qo
+FN
+qo
+qo
+qo
+qo
+fl
+Bs
+Bs
+fl
+OA
+PD
+Fd
pg
ID
OA
@@ -67801,22 +67982,22 @@ FN
FN
qo
qo
+FN
+FN
qo
-ay
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-dt
-fO
-iq
+qo
+qo
+FN
+qo
+qo
+qo
+qo
+fl
+fl
+Bs
+fl
OA
-mq
+PD
Fd
pg
ew
@@ -68058,20 +68239,20 @@ FN
qo
qo
qo
+FN
qo
-ay
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-dt
-gi
-is
+qo
+qo
+qo
+qo
+qo
+qo
+qo
+qo
+fl
+Bs
+mI
+fl
OA
ml
Fd
@@ -68105,7 +68286,7 @@ PD
MW
vP
OA
-qP
+pS
Bs
Bs
Bs
@@ -68314,21 +68495,21 @@ qo
qo
FN
qo
+FN
qo
qo
-ay
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-dt
-gj
-iH
+qo
+FN
+qo
+qo
+qo
+qo
+qo
+qo
+fl
+Bs
+PW
+fl
OA
PD
wh
@@ -68573,19 +68754,19 @@ FN
qo
qo
qo
-ay
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-bb
-dt
-gV
-iI
+qo
+qo
+FN
+FN
+qo
+FN
+qo
+qo
+qo
+fl
+Bs
+Bs
+fl
OA
TW
XN
@@ -68604,7 +68785,7 @@ Je
YX
uw
Tl
-Av
+Pl
Ik
OA
OA
@@ -68830,19 +69011,19 @@ qo
qo
qo
qo
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
-ay
+qo
+ct
+ct
+ct
+ct
+ct
+ct
+ct
+ct
+ct
+Bs
+Bs
+fl
OA
PD
Fd
@@ -68881,7 +69062,7 @@ fl
er
JX
rl
-BW
+VA
fl
qo
qo
@@ -69096,7 +69277,7 @@ fD
mh
Cu
bA
-fl
+ct
oE
tT
fq
@@ -69610,7 +69791,7 @@ Ew
du
vl
lA
-fl
+ct
Yt
fl
qo
@@ -69864,10 +70045,10 @@ hX
HB
HB
wc
-Qw
+HB
vl
YT
-fl
+ct
Yt
fl
qo
@@ -70381,7 +70562,7 @@ CO
FJ
ur
fg
-fl
+ct
Yt
fl
qo
@@ -70887,7 +71068,7 @@ YV
IB
PI
Fr
-oP
+Vf
fl
jS
fl
@@ -71153,8 +71334,8 @@ fl
fl
fl
fl
-fl
-fl
+Bs
+Bs
Yt
gw
gw
@@ -71394,7 +71575,7 @@ yM
zh
Dv
GQ
-Jg
+NH
Sx
UV
PI
@@ -71409,9 +71590,9 @@ gH
fl
qo
qo
-qo
-qo
fl
+fl
+Bs
jk
PI
oP
@@ -71667,13 +71848,13 @@ fl
qo
qo
qo
-qo
+fl
fl
Fz
-fl
+Bs
Yt
fl
-qo
+fl
fl
Yt
fl
@@ -71929,9 +72110,9 @@ fl
fl
fl
Yt
-fl
-fl
-fl
+Bs
+jO
+Bs
Yt
fl
fl
@@ -72188,7 +72369,7 @@ fl
fC
PI
PI
-PI
+Qj
gH
fl
qo
@@ -72445,7 +72626,7 @@ fl
fl
fl
fl
-fl
+Yt
fl
fl
qo
@@ -72700,10 +72881,10 @@ qo
qo
qo
qo
-qo
-qo
-qo
-qo
+fl
+Bs
+Yt
+fl
qo
qo
qo
@@ -72957,10 +73138,10 @@ qo
qo
qo
qo
-qo
-qo
-qo
-qo
+fl
+Bs
+Yt
+fl
qo
qo
qo
@@ -73214,9 +73395,9 @@ FN
qo
qo
qo
-qo
-qo
-qo
+fl
+Bs
+Yt
qo
qo
qo
@@ -73472,9 +73653,9 @@ FN
qo
FN
qo
-qo
-FN
-FN
+Bs
+Yt
+fl
qo
qo
qo
@@ -73729,9 +73910,9 @@ FN
FN
qo
FN
-qo
-FN
-FN
+Bs
+Yt
+fl
FN
qo
qo
@@ -73985,10 +74166,10 @@ qo
FN
qo
qo
-FN
qo
-FN
-FN
+Bs
+Yt
+fl
FN
qo
qo
@@ -74242,10 +74423,10 @@ FN
FN
qo
FN
-FN
-FN
-FN
qo
+Bs
+Yt
+fl
qo
qo
qo
@@ -74500,9 +74681,9 @@ qo
qo
qo
qo
-qo
-FN
-qo
+Bs
+Yt
+fl
qo
qo
qo
@@ -74756,9 +74937,9 @@ qo
FN
qo
FN
-qo
-qo
-qo
+fl
+Bs
+Yt
qo
FN
qo
@@ -75013,10 +75194,10 @@ qo
qo
qo
qo
-FN
-qo
-FN
-qo
+fl
+Bs
+Yt
+fl
FN
qo
FN
@@ -75270,10 +75451,10 @@ qo
FN
qo
qo
-FN
-qo
-qo
-qo
+fl
+Bs
+Yt
+fl
qo
qo
qo
@@ -75284,7 +75465,7 @@ qo
FN
qo
qo
-Xh
+cO
KN
DZ
KN
@@ -75525,23 +75706,23 @@ FN
qo
FN
qo
-qo
-qo
-FN
-FN
-FN
-qo
-FN
-qo
-qo
-qo
-qo
-FN
-qo
-FN
-qo
-qo
-Xh
+ww
+ww
+ww
+ww
+hv
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
UX
LU
UX
@@ -75782,23 +75963,23 @@ qo
FN
qo
FN
-FN
-qo
-qo
-qo
-FN
-FN
-FN
-qo
-qo
-qo
-qo
-qo
-qo
-FN
-qo
-Xh
-Xh
+ww
+BE
+BE
+BE
+ds
+Ci
+dt
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+ww
Xh
LU
Xh
@@ -76039,25 +76220,25 @@ qo
qo
FN
FN
-qo
-qo
-qo
-FN
-qo
-qo
-qo
-qo
-qo
-FN
-qo
-qo
-FN
-qo
-qo
-Xh
-Xh
-Xh
+ww
+Lg
+IY
+IY
+Sa
+LK
+dt
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+ww
Xh
+LU
Xh
Xh
qo
@@ -76296,25 +76477,25 @@ FN
qo
qo
qo
-qo
-qo
-qo
-qo
-qo
-qo
-FN
-qo
-qo
-qo
-qo
-FN
-qo
-qo
-qo
-Xh
-Xh
-Xh
+ww
+ww
+ww
+gj
+fO
+fO
+dt
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+ww
Xh
+LU
Xh
Xh
qo
@@ -76555,23 +76736,23 @@ FN
qo
FN
qo
-FN
-qo
-qo
-qo
-qo
-qo
-FN
-qo
-qo
-qo
-FN
-qo
-qo
-Xh
-Xh
-Xh
+ww
+FP
+fO
+fO
+dt
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+ww
Xh
+LU
Xh
Xh
qo
@@ -76812,23 +76993,23 @@ qo
qo
qo
FN
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-Xh
-Xh
-Xh
+ww
+mv
+fO
+fO
+Ky
+JT
+bb
+bb
+bb
+bF
+bb
+bb
+bb
+bb
+ww
Xh
+LU
Xh
Xh
qo
@@ -77069,23 +77250,23 @@ qo
qo
qo
FN
-FN
-qo
-FN
-qo
-FN
-qo
-qo
-qo
-FN
-FN
-qo
-qo
-qo
-Xh
-Xh
-Xh
+ww
+gi
+fO
+fO
+dt
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+ww
Xh
+LU
Xh
Xh
qo
@@ -77326,26 +77507,26 @@ qo
qo
FN
qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-Xh
-Xh
-Xh
-Xh
-Xh
-Xh
-qo
+ww
+fO
+fO
+fO
+dt
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+ww
+UX
+LU
+UX
+UX
+ww
qo
qo
qo
@@ -77583,23 +77764,23 @@ qo
qo
qo
qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-Xh
-Xh
-Xh
+ww
+br
+Up
+iI
+dt
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+ww
Xh
+LU
Xh
Xh
qo
@@ -77840,21 +78021,21 @@ Xh
qo
qo
qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-qo
-Xh
-Xh
+ww
+ww
+ww
+ww
+ww
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+bb
+ww
Xh
Xh
Xh
@@ -78101,17 +78282,17 @@ Xh
Xh
Xh
Xh
-Xh
-Xh
-Xh
-Xh
-Xh
-Xh
-Xh
-Xh
-Xh
-Xh
-Xh
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
+ww
Xh
Xh
Xh
diff --git a/_maps/map_files/LambdaStation/lambda.dmm b/_maps/map_files/LambdaStation/lambda.dmm
index fdcc0fa7c1..a0d54edb91 100644
--- a/_maps/map_files/LambdaStation/lambda.dmm
+++ b/_maps/map_files/LambdaStation/lambda.dmm
@@ -11825,8 +11825,8 @@
dir = 8
},
/obj/effect/turf_decal/tile/neutral,
-/mob/living/simple_animal/hostile/retaliate/bat/secbat,
/obj/effect/turf_decal/loading_area/red,
+/mob/living/simple_animal/hostile/retaliate/bat/secbat,
/turf/open/floor/plasteel/dark,
/area/security/brig)
"avX" = (
@@ -21222,9 +21222,6 @@
},
/turf/open/floor/plasteel,
/area/quartermaster/miningoffice)
-"aMg" = (
-/turf/closed/wall/r_wall,
-/area/quartermaster/miningoffice)
"aMh" = (
/turf/closed/wall/r_wall,
/area/crew_quarters/heads/captain/private)
@@ -23448,11 +23445,14 @@
/turf/open/floor/plasteel,
/area/quartermaster/storage)
"aQy" = (
-/obj/machinery/door/airlock/maintenance{
- name = "Mining Maintenance";
- req_access_txt = "48"
+/obj/machinery/door/airlock/engineering{
+ name = "Auxillary Base Construction";
+ req_one_access_txt = "32;47;48"
},
-/turf/open/floor/plating,
+/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
/area/quartermaster/miningoffice)
"aQz" = (
/turf/closed/wall,
@@ -23735,12 +23735,6 @@
"aRj" = (
/turf/open/floor/plating,
/area/maintenance/department/cargo)
-"aRk" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plating,
-/area/maintenance/department/cargo)
"aRl" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -23752,10 +23746,6 @@
},
/turf/open/floor/plating,
/area/maintenance/fore)
-"aRm" = (
-/obj/structure/sign/warning/vacuum/external,
-/turf/closed/wall/r_wall,
-/area/maintenance/department/cargo)
"aRn" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -24108,12 +24098,6 @@
},
/turf/open/floor/plasteel,
/area/quartermaster/storage)
-"aSm" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/turf/open/floor/plating,
-/area/maintenance/department/cargo)
"aSn" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -24128,15 +24112,6 @@
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/plating,
/area/maintenance/fore)
-"aSo" = (
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 4
- },
-/obj/machinery/door/airlock/external{
- req_access_txt = "13"
- },
-/turf/open/floor/plating,
-/area/maintenance/department/cargo)
"aSp" = (
/obj/structure/lattice/catwalk,
/turf/open/space,
@@ -27268,6 +27243,9 @@
name = "Bridge";
req_access_txt = "19"
},
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 4
+ },
/turf/open/floor/plasteel/dark,
/area/hallway/secondary/command)
"baa" = (
@@ -37337,6 +37315,9 @@
req_access_txt = "19"
},
/obj/machinery/door/firedoor,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
/turf/open/floor/plasteel,
/area/hallway/secondary/command)
"bAH" = (
@@ -37882,6 +37863,9 @@
dir = 4
},
/obj/effect/turf_decal/tile/neutral,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 4
+ },
/turf/open/floor/plasteel/dark,
/area/hallway/secondary/command)
"bCA" = (
@@ -37896,6 +37880,9 @@
name = "Command Hallway";
req_access_txt = "19"
},
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
/turf/open/floor/plasteel,
/area/hallway/secondary/command)
"bCB" = (
@@ -46902,10 +46889,6 @@
},
/turf/open/floor/plating,
/area/maintenance/disposal)
-"cat" = (
-/obj/item/storage/toolbox/mechanical,
-/turf/open/floor/plating,
-/area/maintenance/department/cargo)
"cau" = (
/obj/effect/turf_decal/tile/neutral{
dir = 4
@@ -49432,15 +49415,6 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/starboard)
-"chE" = (
-/obj/structure/closet/crate,
-/obj/effect/spawner/lootdrop/maintenance{
- lootcount = 3;
- name = "3maintenance loot spawner"
- },
-/obj/item/storage/toolbox/emergency,
-/turf/open/floor/plating,
-/area/maintenance/department/cargo)
"chG" = (
/obj/effect/turf_decal/tile/neutral{
dir = 1
@@ -55016,8 +54990,9 @@
"cxw" = (
/obj/machinery/power/apc{
areastring = "/area/construction";
+ dir = 1;
name = "Construction Area APC";
- pixel_y = -24
+ pixel_y = 24
},
/obj/structure/cable{
icon_state = "0-4"
@@ -59865,6 +59840,9 @@
/area/medical/abandoned)
"cMq" = (
/obj/machinery/door/airlock/external,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 4
+ },
/turf/open/floor/plating,
/area/maintenance/central/secondary)
"cMr" = (
@@ -63507,13 +63485,6 @@
},
/turf/open/floor/plating/airless,
/area/engine/engineering)
-"dRD" = (
-/obj/machinery/status_display/ai{
- pixel_y = 32
- },
-/obj/machinery/vending/cigarette,
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
"dRM" = (
/obj/structure/cable{
icon_state = "1-4"
@@ -64284,6 +64255,9 @@
},
/turf/open/floor/plasteel,
/area/engine/break_room)
+"eYV" = (
+/turf/open/floor/plasteel,
+/area/maintenance/department/cargo)
"eZq" = (
/obj/machinery/gravity_generator/main/station,
/obj/effect/turf_decal/bot_white,
@@ -64413,10 +64387,6 @@
/obj/structure/chair,
/turf/open/floor/plasteel,
/area/hallway/secondary/exit/departure_lounge)
-"fqq" = (
-/obj/machinery/door/firedoor,
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
"fqL" = (
/obj/effect/turf_decal/tile/red,
/obj/effect/turf_decal/tile/red{
@@ -64948,6 +64918,10 @@
},
/turf/open/floor/plasteel/grimy,
/area/tcommsat/computer)
+"gbW" = (
+/obj/structure/stairs/south,
+/turf/open/floor/plasteel,
+/area/maintenance/department/cargo)
"gcM" = (
/obj/effect/turf_decal/tile/red{
dir = 8
@@ -65849,11 +65823,9 @@
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
"hDs" = (
-/obj/structure/chair/comfy/brown{
- dir = 8
- },
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
+/obj/structure/reagent_dispensers/watertank,
+/turf/open/floor/plating,
+/area/maintenance/department/medical)
"hEj" = (
/obj/effect/turf_decal/stripes/line{
dir = 5
@@ -65961,12 +65933,6 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
-"hTm" = (
-/obj/structure/chair/comfy/brown{
- dir = 4
- },
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
"hVb" = (
/obj/machinery/atmospherics/pipe/manifold/general/visible{
dir = 1
@@ -66553,6 +66519,10 @@
},
/turf/open/space/basic,
/area/space/nearstation)
+"jjQ" = (
+/obj/effect/spawner/lootdrop/crate_spawner,
+/turf/open/floor/plating,
+/area/maintenance/department/medical)
"jld" = (
/obj/structure/lattice/catwalk,
/obj/structure/cable{
@@ -67036,12 +67006,16 @@
/turf/open/floor/plating/airless,
/area/engine/atmos)
"kgv" = (
-/obj/structure/table,
-/obj/item/flashlight/lamp/green{
- pixel_y = 3
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 4
},
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 8
+ },
+/turf/open/floor/plasteel/stairs/old,
+/area/maintenance/department/medical)
"khi" = (
/obj/machinery/light{
dir = 4;
@@ -67431,10 +67405,6 @@
},
/turf/open/floor/plating,
/area/maintenance/port)
-"leD" = (
-/obj/effect/landmark/event_spawn,
-/turf/open/floor/carpet,
-/area/hallway/primary/aft)
"lfg" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 6
@@ -68436,15 +68406,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3,
/turf/closed/wall,
/area/maintenance/disposal/incinerator)
-"nab" = (
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 8
- },
-/obj/machinery/door/airlock/external{
- req_access_txt = "13"
- },
-/turf/open/floor/plating,
-/area/maintenance/department/cargo)
"nek" = (
/obj/docking_port/stationary{
dir = 8;
@@ -69505,6 +69466,12 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
/turf/open/floor/plating,
/area/maintenance/aft)
+"peD" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/maintenance/department/cargo)
"pgc" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
@@ -69944,13 +69911,6 @@
/obj/machinery/door/firedoor,
/turf/open/floor/plasteel/white,
/area/medical/medbay/lobby)
-"pXR" = (
-/obj/machinery/status_display/evac{
- pixel_y = 32
- },
-/obj/machinery/vending/coffee,
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
"pXT" = (
/obj/machinery/light{
dir = 4
@@ -70170,8 +70130,11 @@
},
/area/maintenance/department/electrical)
"qIN" = (
-/turf/open/floor/carpet,
-/area/hallway/primary/aft)
+/turf/open/floor/plating,
+/turf/open/floor/plating{
+ icon_state = "platingdmg2"
+ },
+/area/maintenance/department/medical)
"qLB" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
/turf/closed/wall/r_wall,
@@ -70312,6 +70275,17 @@
},
/turf/open/floor/plasteel,
/area/hallway/secondary/entry)
+"rcP" = (
+/obj/structure/cable{
+ icon_state = "4-8"
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/turf/open/floor/plating{
+ icon_state = "platingdmg1"
+ },
+/area/maintenance/department/medical)
"rcU" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1{
dir = 4
@@ -70668,6 +70642,13 @@
},
/turf/open/floor/plasteel/dark,
/area/ai_monitored/turret_protected/aisat/foyer)
+"rMw" = (
+/obj/machinery/door/airlock/external,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
+/turf/open/floor/plating,
+/area/maintenance/central/secondary)
"rNH" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/atmospherics/pipe/simple/general/visible{
@@ -70949,10 +70930,12 @@
/turf/closed/wall,
/area/maintenance/starboard/aft)
"sHs" = (
-/obj/machinery/vending/snack/random,
-/obj/machinery/camera/autoname,
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
+/obj/effect/spawner/lootdrop/maintenance{
+ lootcount = 2;
+ name = "2maintenance loot spawner"
+ },
+/turf/open/floor/plating,
+/area/maintenance/department/medical)
"sJs" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -71043,14 +71026,6 @@
},
/turf/open/space,
/area/solar/starboard/aft)
-"sYf" = (
-/obj/item/kirbyplants/random,
-/obj/machinery/light{
- dir = 4;
- light_color = "#e8eaff"
- },
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
"sYO" = (
/obj/structure/window/reinforced/spawner/north,
/obj/machinery/atmospherics/components/trinary/filter/atmos/n2o{
@@ -71125,12 +71100,17 @@
/turf/open/floor/carpet,
/area/hallway/secondary/entry)
"tcW" = (
-/obj/item/kirbyplants/random,
-/obj/machinery/light{
+/obj/structure/stairs/west,
+/obj/structure/railing{
+ icon_state = "railing";
+ dir = 4
+ },
+/obj/structure/railing{
+ icon_state = "railing";
dir = 8
},
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
+/turf/open/floor/plating,
+/area/maintenance/department/medical)
"tdt" = (
/obj/machinery/power/port_gen/pacman,
/turf/open/floor/plating,
@@ -71621,11 +71601,6 @@
},
/turf/open/floor/plasteel,
/area/security/prison)
-"uaS" = (
-/obj/structure/table,
-/obj/item/reagent_containers/food/snacks/chips,
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
"ubl" = (
/obj/structure/lattice/catwalk,
/obj/structure/cable{
@@ -71756,10 +71731,6 @@
/obj/item/flashlight/lamp,
/turf/open/floor/carpet/orange,
/area/crew_quarters/heads/chief/private)
-"uqr" = (
-/obj/machinery/holopad,
-/turf/open/floor/carpet,
-/area/hallway/primary/aft)
"urx" = (
/obj/structure/flora/ausbushes/fullgrass,
/obj/structure/flora/rock/jungle,
@@ -71781,9 +71752,6 @@
/obj/machinery/door/firedoor,
/turf/open/floor/plasteel,
/area/hallway/primary/aft)
-"usZ" = (
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
"utp" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer3{
@@ -71826,6 +71794,13 @@
},
/turf/open/floor/plasteel,
/area/engine/break_room)
+"uyX" = (
+/obj/machinery/door/airlock/maintenance{
+ name = "Aux Base Maintenance";
+ req_access_txt = "48"
+ },
+/turf/open/floor/plating,
+/area/maintenance/department/cargo)
"uBL" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -73132,6 +73107,9 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/fore)
+"xbr" = (
+/turf/closed/wall/r_wall,
+/area/space/nearstation)
"xfQ" = (
/obj/machinery/atmospherics/pipe/manifold/green/visible{
dir = 4
@@ -73527,10 +73505,6 @@
"ycq" = (
/turf/open/floor/engine/plasma,
/area/engine/atmos)
-"yeB" = (
-/obj/structure/table,
-/turf/open/floor/plasteel/grimy,
-/area/hallway/primary/aft)
"yfq" = (
/obj/effect/turf_decal/tile/red{
dir = 1
@@ -105141,7 +105115,7 @@ bpg
cDz
aSt
biL
-cMq
+rMw
biL
biL
biL
@@ -115949,7 +115923,7 @@ cVr
cVr
cVr
cVr
-cVt
+rcP
bDx
bDx
bDx
@@ -116464,12 +116438,12 @@ ctY
cxq
cza
cBF
-boU
-boU
-boU
-boU
-boU
-boU
+bDx
+bDx
+aaA
+bDx
+aaA
+aaA
boU
bZM
ccx
@@ -116721,13 +116695,13 @@ cuc
cxC
cVr
cBI
-boU
+bpw
+kgv
kgv
-hTm
tcW
-hTm
-yeB
-bIL
+bDx
+aaA
+boU
bZT
ccB
cgC
@@ -116978,13 +116952,13 @@ cud
cxD
cVr
cVt
+bqa
+bpw
+bpw
+bRI
+bDx
+aaA
boU
-pXR
-qIN
-qIN
-qIN
-usZ
-bIL
luG
cdM
hST
@@ -117235,13 +117209,13 @@ cue
cxE
cVr
cVt
-boU
+bpw
sHs
qIN
-uqr
-leD
-usZ
-fqq
+aaA
+aaA
+aaA
+boU
cgY
cWO
cAj
@@ -117492,13 +117466,13 @@ cVr
cVr
cVr
cVt
+bpw
+bpw
+bpw
+jjQ
+aaA
+aaA
boU
-dRD
-qIN
-qIN
-qIN
-usZ
-fqq
cgY
cWO
sNh
@@ -117749,13 +117723,13 @@ cuS
cxS
cVr
cBK
+bhg
+biZ
+hDs
+bDx
+aaA
+aaA
boU
-yeB
-hDs
-sYf
-hDs
-uaS
-bIL
mdh
cWO
cgK
@@ -118006,12 +117980,12 @@ cud
cxT
cVr
cVt
-boU
-boU
-boU
-boU
-boU
-boU
+bpw
+bDx
+bDx
+aaA
+aaA
+aaA
boU
bZX
cWO
@@ -118263,7 +118237,7 @@ cuc
cxC
cVr
cVt
-aaA
+bpw
aaA
aaA
aaA
@@ -118520,7 +118494,7 @@ ctY
cxU
cza
cBF
-aaA
+bpw
aaA
aaA
aaA
@@ -118779,7 +118753,7 @@ cVr
cVt
bDx
aaA
-aco
+aaA
aaA
aaA
boU
@@ -128253,7 +128227,7 @@ aOD
aPv
aPF
aMe
-cat
+aRj
aRj
aRj
aRj
@@ -128510,7 +128484,7 @@ aNX
aNa
aPG
aMe
-cQS
+aRj
aRj
aQz
aQz
@@ -128767,23 +128741,23 @@ aOa
aNa
aPH
aMe
-aRj
aQz
+uyX
aQz
aaA
-aaR
-aaR
-aaR
-aaR
-aaA
-aaA
-aaA
-aaA
-aaA
-aco
aaA
aaA
aaA
+aac
+aaa
+aaa
+aaa
+aaa
+aac
+aaa
+aaa
+aaa
+aaa
aab
bjw
bkJ
@@ -129024,25 +128998,25 @@ aNZ
aNa
cLS
aMe
-aRj
-lQP
+eYV
+eYV
+aQz
+aQz
+aQz
aQz
-aaR
-aaR
-aaR
-aaR
-aaR
aaA
-aaA
-aco
-aaA
-aaA
-aaA
-aaA
-cce
-aaA
-aaa
-aaa
+xbr
+aac
+aac
+aac
+aac
+xbr
+aac
+aac
+aac
+aac
+xbr
+aac
aac
aaa
aab
@@ -129281,24 +129255,24 @@ aNZ
aOO
aQp
aQy
-aRk
-aRj
+eYV
+eYV
+peD
+eYV
+gbW
aQz
-aaR
-aaR
-aaR
aaA
-aaR
-aaA
-aaA
-aaA
-aaA
-aab
-aab
-aab
aac
+aaa
+aaa
+aaa
+aab
+aab
+aab
+aab
aab
aaa
+aac
aaa
aac
aaa
@@ -129538,24 +129512,24 @@ aPy
aNa
aQq
aMe
-bIH
-aRj
aQz
-aaR
+aQz
+aQz
+aQz
+aQz
+aQz
aaA
-aaA
-aaA
-aaA
-aaA
-aaA
-aab
-aab
-aaa
-aaa
-aaa
aac
-aaa
-aaa
+aab
+aab
+aab
+aab
+aab
+aab
+aab
+aab
+aab
+aac
aaa
aac
aaa
@@ -129795,25 +129769,25 @@ aOb
aNa
aQq
aMe
-bIH
-aRj
-aQz
-aaR
-aaA
-aco
aaA
aaA
aaA
aaA
-aaa
-aaa
-aaa
-aaa
-aaa
+aaA
+aaA
+aaA
aac
aaa
aaa
aaa
+aab
+aab
+aab
+aab
+aab
+aaa
+aac
+aaa
aac
aaa
aab
@@ -130046,31 +130020,31 @@ aMd
aMd
aMd
aMd
-aMg
+aMe
aLo
aOE
aPw
aQr
aMe
-aRj
-cQS
-aQz
-aaR
aaA
aaA
aaA
aaA
+aaA
+aaA
+aaA
+aac
+aaa
+aaa
+aaa
+aaa
+aaa
+aaa
+aaa
+aaa
+aaa
+aac
aab
-aab
-aaa
-aaa
-aaa
-aab
-aaa
-aac
-aac
-aac
-aac
aac
aac
aav
@@ -130303,31 +130277,31 @@ aav
aab
aab
aab
-aMg
-aMg
-aMg
-aMg
-aMg
-aMg
-aRj
-aRj
-aQA
-aaR
+aMe
+aMe
+aMe
+aMe
+aMe
+aMe
aaA
aaA
aaA
aaA
+aaA
+aaA
+aaA
+xbr
aaa
aaa
aaa
-aab
-aab
-aab
-aab
-aab
-aab
-aab
-aab
+aaa
+aaa
+aaa
+aaa
+aaa
+aaa
+xbr
+aac
aac
aab
aab
@@ -130565,15 +130539,15 @@ aaA
aaA
aaA
aaA
-aQA
-chE
-aSm
-aQA
+aaA
+aaA
+aaA
+aaA
aaA
aaA
aab
aab
-aab
+aac
aaa
aaa
aaa
@@ -130582,8 +130556,8 @@ aab
aab
aab
aab
-aab
-aab
+aaa
+aac
aaa
aac
aaa
@@ -130822,25 +130796,25 @@ aab
aaA
aaA
aaA
-aQA
-aRm
-aSo
-aQA
+aaA
+aaA
+aaA
+aaA
aaA
aab
aaa
aaa
+aac
aaa
aaa
aaa
+aab
+aab
+aab
+aab
+aab
aaa
-aab
-aab
-aab
-aab
-aab
-aab
-aab
+aac
aaa
aac
aaa
@@ -131080,24 +131054,24 @@ aab
aab
aaA
aaA
-aQA
-aRj
-aQA
+aaA
+aaA
+aaA
aaA
aaa
aaa
aaa
+aac
aaa
aaa
aaa
aaa
-aab
-aab
-aab
-aab
-aab
-aab
-aab
+aaa
+aaa
+aaa
+aaa
+aaa
+aac
aaa
aac
aaa
@@ -131335,12 +131309,16 @@ aaa
aaa
aaa
aaa
+aaa
+aaa
+aaa
+aaa
+aaa
aab
-aab
-aQA
-aRj
-aQA
-aab
+aaa
+aaa
+aaa
+aac
aaa
aaa
aaa
@@ -131348,13 +131326,9 @@ aaa
aaa
aaa
aaa
-aab
-aab
-aab
-aab
-aab
-aab
-aab
+aaa
+aaa
+aac
aaa
aac
aac
@@ -131593,10 +131567,6 @@ aaa
aaa
aaa
aaa
-aab
-aQA
-nab
-aQA
aaa
aaa
aaa
@@ -131605,14 +131575,18 @@ aaa
aaa
aaa
aaa
-aab
-aab
-aab
-aab
-aab
-aaa
-aaa
-aaa
+xbr
+aac
+aac
+aac
+aac
+xbr
+aac
+aac
+aac
+aac
+xbr
+aac
aac
aaa
aaa
@@ -131847,13 +131821,13 @@ aaa
aaa
aaa
aab
-aab
-aab
-aab
aaa
-aav
-acv
-aac
+aaa
+aaa
+aaa
+aab
+aab
+aab
aaa
aaa
aaa
@@ -132109,7 +132083,7 @@ aab
aab
aab
aaa
-aSp
+aaa
aaa
aab
aab
diff --git a/_maps/map_files/PubbyStation/job_changes.dm b/_maps/map_files/PubbyStation/job_changes.dm
deleted file mode 100644
index 726601725b..0000000000
--- a/_maps/map_files/PubbyStation/job_changes.dm
+++ /dev/null
@@ -1,20 +0,0 @@
-#define JOB_MODIFICATION_MAP_NAME "PubbyStation"
-
-/datum/job/hos/New()
- ..()
- MAP_JOB_CHECK
- access += ACCESS_CREMATORIUM
- minimal_access += ACCESS_CREMATORIUM
-
-/datum/job/warden/New()
- ..()
- MAP_JOB_CHECK
- access += ACCESS_CREMATORIUM
- minimal_access += ACCESS_CREMATORIUM
-
-/datum/job/officer/New()
- ..()
- MAP_JOB_CHECK
- access += ACCESS_CREMATORIUM
- minimal_access += ACCESS_CREMATORIUM
-
diff --git a/_maps/pubbystation.json b/_maps/pubbystation.json
index f99cca57c5..acf49b773b 100644
--- a/_maps/pubbystation.json
+++ b/_maps/pubbystation.json
@@ -7,5 +7,10 @@
"whiteship": "whiteship_pubby",
"ferry": "ferry_fancy",
"cargo": "cargo_box"
- }
+ },
+ "job_access_add": {
+ "/datum/job/hos": [27],
+ "/datum/job/officer": [27],
+ "/datum/job/detective": [27]
+ }
}
diff --git a/_maps/shuttles/emergency_nature.dmm b/_maps/shuttles/emergency_nature.dmm
new file mode 100644
index 0000000000..9639e37852
--- /dev/null
+++ b/_maps/shuttles/emergency_nature.dmm
@@ -0,0 +1,2040 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"as" = (
+/obj/structure/flora/ausbushes/lavendergrass,
+/obj/structure/flora/ausbushes/sparsegrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"au" = (
+/obj/structure/sink/puddle,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"ay" = (
+/obj/structure/flora/ausbushes/leafybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"aA" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 6
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"aJ" = (
+/obj/structure/flora/ausbushes/stalkybush,
+/obj/structure/flora/ausbushes/fullgrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"bd" = (
+/obj/structure/flora/rock/pile/largejungle,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"bg" = (
+/obj/structure/table/reinforced,
+/obj/item/storage/toolbox/mechanical{
+ pixel_y = 8;
+ pixel_x = -2
+ },
+/obj/item/storage/toolbox/electrical,
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"bS" = (
+/obj/structure/table/reinforced,
+/obj/item/storage/box/lights/mixed{
+ pixel_y = 9;
+ pixel_x = -5
+ },
+/obj/item/storage/box/matches{
+ pixel_y = 5
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 10
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"cm" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/machinery/portable_atmospherics/canister/oxygen,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"cL" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 3
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"cR" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 5
+ },
+/obj/structure/sign/warning/nosmoking{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"cZ" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 1
+ },
+/obj/machinery/computer/emergency_shuttle,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"dj" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 3
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/obj/item/radio/intercom{
+ name = "Station Intercom (General)";
+ pixel_y = -31
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"dP" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/extinguisher_cabinet{
+ pixel_y = 30
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"dT" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plating{
+ icon_state = "platingdmg3"
+ },
+/area/shuttle/escape)
+"eq" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plating{
+ icon_state = "platingdmg1"
+ },
+/area/shuttle/escape)
+"ev" = (
+/obj/effect/turf_decal/trimline/green/filled/corner,
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"ex" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/obj/structure/flora/ausbushes/leafybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"eB" = (
+/obj/item/rack_parts,
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/corner{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"eS" = (
+/obj/effect/turf_decal/trimline/red/filled/end{
+ dir = 1
+ },
+/obj/structure/table/reinforced,
+/obj/machinery/recharger,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"eY" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 9
+ },
+/obj/structure/table/reinforced,
+/obj/item/storage/toolbox/emergency{
+ pixel_y = 3
+ },
+/obj/machinery/light{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"fD" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 1
+ },
+/obj/machinery/computer/security,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"fG" = (
+/obj/structure/flora/ausbushes/fullgrass,
+/obj/structure/flora/ausbushes/genericbush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"fJ" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 1
+ },
+/obj/machinery/computer/communications,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"fT" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 10
+ },
+/obj/machinery/door/window/westleft{
+ name = "Infirmary"
+ },
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"gg" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 1
+ },
+/obj/structure/chair/comfy/shuttle,
+/obj/item/radio/intercom{
+ dir = 4;
+ name = "Station Intercom (General)";
+ pixel_y = 27
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"gj" = (
+/obj/machinery/door/airlock/maintenance_hatch,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"gl" = (
+/obj/structure/flora/junglebush/large,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"gu" = (
+/obj/structure/shuttle/engine/propulsion,
+/turf/open/floor/plating/airless,
+/area/shuttle/escape)
+"gx" = (
+/turf/open/floor/plating/airless,
+/area/shuttle/escape)
+"gI" = (
+/obj/item/shovel,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"gM" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 5
+ },
+/obj/structure/table/reinforced,
+/obj/item/storage/fancy/donut_box,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"gR" = (
+/obj/effect/turf_decal/weather/dirt,
+/obj/machinery/hydroponics/soil,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"ht" = (
+/obj/effect/turf_decal/trimline/red/filled/line{
+ dir = 9
+ },
+/obj/structure/chair/comfy/shuttle,
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/structure/reagent_dispensers/peppertank{
+ pixel_y = 28
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"hC" = (
+/obj/effect/turf_decal/trimline/red/filled/corner{
+ dir = 1
+ },
+/obj/effect/turf_decal/trimline/red/filled/line{
+ dir = 4
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"hJ" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 8
+ },
+/obj/structure/table/reinforced,
+/obj/item/storage/box/monkeycubes{
+ pixel_x = 6;
+ pixel_y = 5
+ },
+/obj/item/storage/box/monkeycubes{
+ pixel_x = -6;
+ pixel_y = 2
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"ib" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/obj/structure/flora/ausbushes/fullgrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"it" = (
+/mob/living/carbon/monkey,
+/obj/structure/flora/grass/jungle/b{
+ icon_state = "bushb3"
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"iD" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 5
+ },
+/obj/structure/table/reinforced,
+/obj/item/restraints/handcuffs{
+ pixel_y = 3
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"iF" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/obj/structure/flora/ausbushes/brflowers,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"iO" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/machinery/space_heater,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"iV" = (
+/obj/effect/decal/cleanable/robot_debris,
+/obj/effect/turf_decal/stripes/corner{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"jO" = (
+/obj/structure/table/reinforced,
+/obj/item/storage/box/stockparts{
+ pixel_y = 7
+ },
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"jX" = (
+/obj/effect/turf_decal/trimline/red/filled/line{
+ dir = 9
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"jZ" = (
+/obj/effect/turf_decal/trimline/red/filled/corner{
+ dir = 1
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"ke" = (
+/obj/item/shovel/spade,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"ku" = (
+/obj/effect/turf_decal/trimline/blue/filled/corner{
+ dir = 4
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"lo" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/obj/structure/flora/ausbushes/leafybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"lH" = (
+/obj/structure/reagent_dispensers/fueltank,
+/obj/effect/turf_decal/stripes/end{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"lN" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/structure/grille/broken,
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
+ },
+/area/shuttle/escape)
+"lS" = (
+/obj/effect/turf_decal/trimline/red/filled/line{
+ dir = 4
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"lT" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 8
+ },
+/obj/structure/table/reinforced,
+/obj/item/cigbutt{
+ pixel_x = 8
+ },
+/obj/machinery/recharger,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"lV" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 5
+ },
+/obj/structure/table/glass,
+/obj/item/reagent_containers/food/snacks/soup/monkeysdelight{
+ pixel_y = 4
+ },
+/obj/item/reagent_containers/food/drinks/soda_cans/monkey_energy{
+ pixel_y = 5;
+ pixel_x = 6
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"me" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 9
+ },
+/obj/structure/sign/warning/nosmoking{
+ pixel_y = 32
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"mq" = (
+/mob/living/carbon/monkey,
+/obj/machinery/light/floor,
+/obj/structure/flora/ausbushes/sparsegrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"mw" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 10
+ },
+/obj/item/reagent_containers/food/snacks/grown/banana,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"nA" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 9
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"nD" = (
+/obj/structure/flora/ausbushes/fernybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"nQ" = (
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 8
+ },
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"og" = (
+/obj/effect/turf_decal/trimline/blue/filled/corner{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"os" = (
+/obj/effect/turf_decal/trimline/green/filled/end{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/machinery/door/window/westleft{
+ name = "Nature pen"
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"oE" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 5
+ },
+/obj/structure/table/reinforced,
+/obj/item/storage/firstaid/regular,
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"qD" = (
+/obj/structure/flora/ausbushes/sparsegrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"rg" = (
+/obj/item/clothing/glasses/welding{
+ pixel_y = 8;
+ pixel_x = 3
+ },
+/obj/item/weldingtool/largetank{
+ pixel_x = -3
+ },
+/obj/structure/rack,
+/obj/effect/turf_decal/stripes/line{
+ dir = 5
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"rI" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 8
+ },
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"sm" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/reagent_dispensers/watertank,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"su" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 6
+ },
+/obj/structure/table/optable,
+/obj/effect/decal/cleanable/blood/old,
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"sF" = (
+/obj/effect/turf_decal/trimline/blue/filled/line,
+/obj/item/storage/backpack/duffelbag/med/surgery{
+ pixel_y = 5
+ },
+/obj/structure/rack,
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"sN" = (
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 8
+ },
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"sV" = (
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 1
+ },
+/obj/effect/turf_decal/trimline/green/filled/corner,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"tL" = (
+/obj/effect/turf_decal/trimline/red/filled/line{
+ dir = 8
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"uc" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 10
+ },
+/obj/structure/flora/ausbushes/fullgrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"ui" = (
+/obj/structure/extinguisher_cabinet,
+/turf/closed/wall/mineral/titanium/nodiagonal,
+/area/shuttle/escape)
+"ur" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 8
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 8
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"uI" = (
+/obj/structure/flora/rock/jungle{
+ icon_state = "rock3"
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"vt" = (
+/obj/effect/turf_decal/trimline/red/filled/line{
+ dir = 10
+ },
+/obj/structure/table/reinforced,
+/obj/item/restraints/handcuffs{
+ pixel_y = 7
+ },
+/obj/item/storage/fancy/donut_box,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"vx" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 6
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"vP" = (
+/obj/effect/turf_decal/trimline/red/filled/line,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"vW" = (
+/obj/effect/turf_decal/trimline/red/filled/line{
+ dir = 6
+ },
+/obj/structure/table/reinforced,
+/obj/item/storage/box/handcuffs{
+ pixel_y = 5
+ },
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"wg" = (
+/obj/effect/turf_decal/trimline/green/filled/end{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/machinery/door/window/northleft,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"wX" = (
+/obj/effect/turf_decal/trimline/blue/filled/line,
+/obj/machinery/light,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"xA" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/obj/structure/flora/ausbushes/fernybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"xZ" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 10
+ },
+/obj/structure/tank_dispenser/oxygen{
+ layer = 2.7;
+ pixel_x = -1;
+ pixel_y = 2
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"yt" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"yI" = (
+/obj/item/reagent_containers/food/snacks/grown/banana,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"yR" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 6
+ },
+/obj/machinery/suit_storage_unit/standard_unit,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"yZ" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 6
+ },
+/obj/structure/sign/poster/official/pda_ad{
+ pixel_y = -32
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"zf" = (
+/obj/structure/flora/ausbushes/pointybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"zr" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 10
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"zs" = (
+/obj/machinery/light/floor,
+/obj/structure/flora/ausbushes/sparsegrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"zD" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 5
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"zE" = (
+/obj/machinery/door/airlock/security{
+ name = "Brig";
+ req_access_txt = "63; 42"
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"Ai" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Aw" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 4
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 8
+ },
+/obj/machinery/status_display/evac{
+ dir = 8;
+ pixel_x = 32
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"AM" = (
+/obj/structure/flora/ausbushes/ywflowers,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Bm" = (
+/obj/machinery/door/airlock/command/glass{
+ name = "Cockpit";
+ req_access_txt = "19"
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"Bo" = (
+/obj/structure/flora/ausbushes/sunnybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Bt" = (
+/obj/structure/flora/ausbushes/fullgrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Bv" = (
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"BA" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 9
+ },
+/obj/structure/table/glass,
+/obj/item/defibrillator/loaded{
+ pixel_y = 5
+ },
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"BG" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 10
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"BM" = (
+/obj/structure/flora/ausbushes/ppflowers,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Cb" = (
+/obj/structure/flora/rock/jungle{
+ icon_state = "bushc2"
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Co" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 1
+ },
+/obj/structure/chair/comfy/shuttle,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"CA" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 9
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/structure/chair/comfy/shuttle,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"CE" = (
+/obj/structure/flora/tree/jungle/small,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"CQ" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 1
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/machinery/vending/cola/space_up,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Db" = (
+/obj/structure/sign/poster/official/help_others,
+/turf/closed/wall/mineral/titanium/nodiagonal,
+/area/shuttle/escape)
+"DD" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 9
+ },
+/obj/structure/window/reinforced{
+ dir = 8
+ },
+/mob/living/simple_animal/bot/medbot{
+ name = "\improper emergency medibot";
+ pixel_x = -3;
+ pixel_y = 2
+ },
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"DQ" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"EI" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 1
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/machinery/vending/snack/green,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Fo" = (
+/obj/item/cultivator,
+/mob/living/simple_animal/hostile/lizard,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Fp" = (
+/obj/structure/flora/ausbushes/grassybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Gf" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"GO" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 8
+ },
+/obj/structure/table/glass,
+/obj/item/storage/box/monkeycubes{
+ pixel_y = 10;
+ pixel_x = 5
+ },
+/obj/item/reagent_containers/food/snacks/cube/monkey{
+ pixel_x = 5
+ },
+/obj/item/paicard{
+ pixel_x = -6;
+ pixel_y = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"GV" = (
+/obj/structure/shuttle/engine/huge,
+/turf/open/floor/plating/airless,
+/area/shuttle/escape)
+"He" = (
+/obj/effect/turf_decal/trimline/blue/filled/corner{
+ dir = 1
+ },
+/turf/open/floor/plasteel{
+ icon_state = "floorscorched1"
+ },
+/area/shuttle/escape)
+"Hi" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plating{
+ icon_state = "platingdmg1"
+ },
+/area/shuttle/escape)
+"Hq" = (
+/obj/structure/flora/rock/pile,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"HV" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Ia" = (
+/mob/living/carbon/monkey,
+/obj/structure/flora/ausbushes/sparsegrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Io" = (
+/obj/effect/turf_decal/trimline/green/filled/corner,
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Iw" = (
+/obj/item/reagent_containers/glass/bucket,
+/mob/living/simple_animal/hostile/retaliate/frog,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Iz" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 4
+ },
+/obj/effect/decal/cleanable/vomit,
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"IB" = (
+/obj/effect/decal/cleanable/oil,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"Jw" = (
+/obj/structure/shuttle/engine/heater,
+/obj/structure/window/reinforced{
+ dir = 1
+ },
+/turf/open/floor/plating/airless,
+/area/shuttle/escape)
+"JD" = (
+/obj/effect/turf_decal/trimline/blue/filled/end{
+ dir = 1
+ },
+/obj/structure/table/glass,
+/obj/item/storage/firstaid/brute{
+ pixel_x = 4;
+ pixel_y = 2
+ },
+/obj/item/storage/firstaid/regular{
+ pixel_x = -3
+ },
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"JR" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 4
+ },
+/obj/machinery/suit_storage_unit/standard_unit,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"Ka" = (
+/obj/effect/turf_decal/weather/dirt,
+/obj/structure/flora/ausbushes/sparsegrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Kv" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/sign/poster/contraband/tools{
+ pixel_y = 32
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"Kx" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 3
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"KT" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 5
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Lm" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 1
+ },
+/obj/structure/flora/ausbushes/pointybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"LG" = (
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 8
+ },
+/obj/effect/turf_decal/trimline/green/filled/corner,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"LO" = (
+/obj/structure/flora/rock/jungle{
+ icon_state = "grassa4"
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"LW" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"LY" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"MJ" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/obj/structure/flora/ausbushes/leafybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"MS" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 6
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Nu" = (
+/obj/effect/turf_decal/weather/dirt,
+/obj/item/hatchet,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Ob" = (
+/obj/effect/turf_decal/trimline/green/filled/end,
+/obj/effect/turf_decal/stripes/line,
+/obj/machinery/door/window/southleft{
+ name = "Nature pen"
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"OS" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 3
+ },
+/obj/machinery/vending/coffee,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Ps" = (
+/obj/structure/flora/ausbushes/brflowers,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"PG" = (
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/green/filled/corner{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"PP" = (
+/obj/structure/flora/ausbushes/genericbush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"QC" = (
+/obj/structure/flora/ausbushes/lavendergrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"QM" = (
+/obj/item/bodypart,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
+ },
+/area/shuttle/escape)
+"QO" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"QZ" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/blue/filled/corner{
+ dir = 1
+ },
+/obj/structure/chair,
+/obj/structure/sign/poster/contraband/busty_backdoor_xeno_babes_6{
+ pixel_x = 30
+ },
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"Ru" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/obj/machinery/vending/hydroseeds,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Sl" = (
+/obj/effect/turf_decal/trimline/blue/filled/line,
+/obj/machinery/computer/operating{
+ dir = 1
+ },
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"Sr" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 6
+ },
+/obj/structure/table/glass,
+/obj/item/clothing/suit/monkeysuit{
+ pixel_y = 4;
+ pixel_x = -2
+ },
+/obj/item/clothing/mask/gas/monkeymask{
+ pixel_x = 5;
+ pixel_y = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"SS" = (
+/obj/machinery/door/airlock/titanium{
+ name = "Emergency Shuttle Airlock"
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"ST" = (
+/obj/effect/turf_decal/weather/dirt,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Ti" = (
+/obj/structure/flora/rock/jungle{
+ icon_state = "busha3"
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Ts" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 1
+ },
+/obj/machinery/hydroponics/soil,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"TH" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 5
+ },
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/structure/chair/comfy/shuttle,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"TK" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 5
+ },
+/obj/item/hatchet,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"TT" = (
+/obj/effect/turf_decal/weather/dirt,
+/obj/structure/flora/ausbushes/fullgrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Um" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"Uy" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 1
+ },
+/obj/item/reagent_containers/food/snacks/grown/banana,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"UE" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 5
+ },
+/obj/machinery/vending/hydronutrients,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"UO" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 8
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Vu" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 1
+ },
+/mob/living/carbon/monkey,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Vv" = (
+/mob/living/carbon/monkey,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"VI" = (
+/obj/effect/spawner/structure/window/shuttle,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"VM" = (
+/obj/structure/flora/tree/jungle,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"VU" = (
+/turf/closed/wall/mineral/titanium,
+/area/shuttle/escape)
+"Wa" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Wr" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/obj/structure/flora/ausbushes/reedbush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Wz" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/recharge_station,
+/turf/open/floor/plating,
+/area/shuttle/escape)
+"WE" = (
+/turf/template_noop,
+/area/template_noop)
+"WH" = (
+/obj/structure/flora/ausbushes/fullgrass,
+/obj/structure/flora/ausbushes/sunnybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"WL" = (
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"Xm" = (
+/obj/structure/flora/rock,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"XK" = (
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"XY" = (
+/obj/effect/turf_decal/trimline/blue/filled/line{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel{
+ dir = 1
+ },
+/area/shuttle/escape)
+"Ym" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 1
+ },
+/obj/structure/flora/rock/pile,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Yp" = (
+/obj/machinery/door/airlock/titanium{
+ name = "Emergency Shuttle Airlock"
+ },
+/obj/docking_port/mobile/emergency,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Yu" = (
+/turf/closed/wall/mineral/titanium/nodiagonal,
+/area/shuttle/escape)
+"YH" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/obj/structure/flora/ausbushes/fullgrass,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"YP" = (
+/obj/effect/turf_decal/trimline/green/filled/end{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/machinery/door/window/eastleft{
+ name = "Nature pen"
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"YW" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 3
+ },
+/obj/machinery/vending/wardrobe/hydro_wardrobe,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Zd" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 3
+ },
+/obj/machinery/light,
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"Zg" = (
+/obj/effect/turf_decal/trimline/blue/filled/line,
+/turf/open/floor/plasteel/dark,
+/area/shuttle/escape)
+"Zl" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 5
+ },
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Zm" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 10
+ },
+/obj/structure/flora/ausbushes/fernybush,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"Zt" = (
+/obj/effect/turf_decal/trimline/green/filled/line,
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"ZD" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 8
+ },
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+"ZL" = (
+/obj/machinery/hydroponics/soil,
+/obj/item/seeds/banana,
+/turf/open/floor/grass,
+/area/shuttle/escape)
+"ZT" = (
+/obj/effect/turf_decal/trimline/green/filled/line{
+ dir = 8
+ },
+/obj/structure/chair/comfy/shuttle{
+ dir = 4
+ },
+/obj/machinery/light{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/shuttle/escape)
+
+(1,1,1) = {"
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+VU
+SS
+Yu
+Yp
+Yu
+Yu
+Yu
+Yu
+Yu
+SS
+Yu
+SS
+Yu
+Yu
+Yu
+Yu
+Yu
+Yu
+VU
+WE
+WE
+WE
+"}
+(2,1,1) = {"
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+VU
+Yu
+nA
+UO
+yt
+ZT
+UO
+GO
+UO
+ZT
+yt
+UO
+zr
+Yu
+Yu
+lH
+eB
+lN
+bS
+Yu
+VU
+WE
+WE
+"}
+(3,1,1) = {"
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+VU
+Yu
+me
+Io
+Wa
+Wa
+Wa
+Wa
+ev
+Wa
+Wa
+Wa
+Wa
+Bv
+zr
+Yu
+Yu
+rg
+iV
+jO
+Jw
+gx
+gx
+GV
+"}
+(4,1,1) = {"
+WE
+WE
+VU
+VI
+VI
+VI
+VU
+Yu
+nA
+Io
+MS
+VI
+VI
+VI
+VI
+YP
+VI
+VI
+VI
+VI
+KT
+Bv
+zr
+Yu
+Yu
+eq
+bg
+Jw
+gx
+gx
+gx
+"}
+(5,1,1) = {"
+WE
+VU
+Yu
+jX
+tL
+vt
+Yu
+CA
+Io
+MS
+VI
+VI
+YH
+iF
+xA
+Gf
+lo
+Gf
+Zm
+VI
+VI
+KT
+Bv
+BG
+Yu
+Kv
+DQ
+Jw
+gx
+gx
+gx
+"}
+(6,1,1) = {"
+VU
+Yu
+ht
+jZ
+WL
+vP
+zE
+HV
+Zt
+VI
+VI
+Wr
+Vv
+Ti
+Fo
+PP
+Xm
+ZL
+LO
+mw
+VI
+VI
+HV
+Zd
+Yu
+IB
+iO
+Jw
+gu
+WE
+WE
+"}
+(7,1,1) = {"
+VI
+eS
+hC
+lS
+lS
+vW
+Yu
+Co
+Zt
+VI
+Ru
+zs
+Bt
+qD
+Bo
+aJ
+fG
+CE
+Vv
+zs
+uc
+VI
+HV
+Kx
+Yu
+dP
+dT
+Jw
+gu
+WE
+WE
+"}
+(8,1,1) = {"
+Yu
+Yu
+VI
+VI
+ui
+Yu
+Db
+Co
+Zt
+VI
+Ym
+XK
+au
+XK
+VM
+Hq
+QC
+XK
+BM
+Bt
+Ka
+VI
+HV
+YW
+Yu
+LY
+sm
+Jw
+gu
+WE
+WE
+"}
+(9,1,1) = {"
+VI
+eY
+hJ
+lT
+ur
+xZ
+Yu
+CQ
+Zt
+VI
+Ts
+WH
+XK
+XK
+Ps
+gl
+Bt
+it
+AM
+gI
+TT
+VI
+HV
+Zd
+Yu
+Um
+DQ
+Jw
+gx
+gx
+GV
+"}
+(10,1,1) = {"
+VI
+fD
+LW
+WL
+WL
+Zg
+Bm
+HV
+LG
+Ob
+Uy
+Xm
+Vv
+Fp
+qD
+zs
+XK
+XK
+PP
+Bt
+ST
+wg
+PG
+cL
+gj
+Um
+cm
+Jw
+gx
+gx
+gx
+"}
+(11,1,1) = {"
+VI
+cZ
+LW
+WL
+WL
+Zg
+VI
+EI
+Zt
+VI
+Lm
+as
+XK
+VM
+Iw
+au
+XK
+bd
+Bt
+XK
+Nu
+VI
+HV
+Zd
+Yu
+Um
+Hi
+Jw
+gx
+gx
+gx
+"}
+(12,1,1) = {"
+VI
+fJ
+LW
+WL
+WL
+Zg
+VI
+Co
+Zt
+VI
+Vu
+nD
+qD
+PP
+Bt
+yI
+QC
+Bt
+XK
+uI
+gR
+VI
+HV
+OS
+Yu
+Um
+Wz
+Jw
+gu
+WE
+WE
+"}
+(13,1,1) = {"
+VI
+gM
+ku
+WL
+WL
+wX
+Yu
+gg
+Zt
+VI
+UE
+zs
+zf
+ke
+zf
+ay
+XK
+ay
+AM
+mq
+ex
+VI
+HV
+dj
+Yu
+QM
+DQ
+Jw
+gu
+WE
+WE
+"}
+(14,1,1) = {"
+VU
+Yu
+iD
+og
+WL
+Zg
+ui
+Co
+Zt
+VI
+VI
+TK
+Cb
+Bt
+qD
+BM
+Bo
+Ia
+XK
+Ai
+VI
+VI
+HV
+Zd
+Yu
+zD
+vx
+Jw
+gu
+WE
+WE
+"}
+(15,1,1) = {"
+WE
+VU
+Yu
+oE
+JR
+yR
+Yu
+TH
+sN
+zr
+VI
+VI
+Zl
+QO
+MJ
+QO
+ib
+MJ
+Ai
+VI
+VI
+nA
+sV
+aA
+Yu
+DD
+fT
+Jw
+gx
+gx
+GV
+"}
+(16,1,1) = {"
+WE
+WE
+VU
+Yu
+Yu
+Yu
+VU
+Yu
+KT
+sN
+zr
+VI
+VI
+VI
+VI
+os
+VI
+VI
+VI
+VI
+nA
+sV
+MS
+Yu
+Yu
+XY
+sF
+Jw
+gx
+gx
+gx
+"}
+(17,1,1) = {"
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+VU
+Yu
+cR
+sN
+yt
+yt
+yt
+yt
+nQ
+yt
+yt
+yt
+yt
+sV
+yZ
+Yu
+Yu
+BA
+He
+Sl
+Jw
+gx
+gx
+gx
+"}
+(18,1,1) = {"
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+VU
+Yu
+lV
+rI
+ZD
+rI
+rI
+Aw
+rI
+rI
+ZD
+rI
+Sr
+Yu
+Yu
+JD
+QZ
+Iz
+su
+Yu
+VU
+WE
+WE
+"}
+(19,1,1) = {"
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+WE
+VU
+Yu
+VI
+VI
+VI
+VI
+Yu
+VI
+VI
+VI
+VI
+Yu
+Yu
+Yu
+Yu
+Yu
+Yu
+Yu
+VU
+WE
+WE
+WE
+"}
diff --git a/_maps/templates/hilbertshotel.dmm b/_maps/templates/hilbertshotel.dmm
index 4e4d8f8267..da5d13d93e 100644
--- a/_maps/templates/hilbertshotel.dmm
+++ b/_maps/templates/hilbertshotel.dmm
@@ -7,7 +7,7 @@
/area/hilbertshotel)
"c" = (
/obj/machinery/jukebox{
- req_access = null
+ req_one_access = null
},
/turf/open/indestructible/hotelwood,
/area/hilbertshotel)
diff --git a/code/__DEFINES/_flags/item_flags.dm b/code/__DEFINES/_flags/item_flags.dm
index 26e764c45b..7da71e22cb 100644
--- a/code/__DEFINES/_flags/item_flags.dm
+++ b/code/__DEFINES/_flags/item_flags.dm
@@ -22,12 +22,10 @@
#define SURGICAL_TOOL (1<<10)
///Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
#define NO_UNIFORM_REQUIRED (1<<11)
-///Damage when attacking people is not affected by combat mode.
-#define NO_COMBAT_MODE_FORCE_MODIFIER (1<<12)
/// This item can be used to parry. Only a basic check used to determine if we should proceed with parry chain at all.
-#define ITEM_CAN_PARRY (1<<13)
+#define ITEM_CAN_PARRY (1<<12)
/// This item can be used in the directional blocking system. Only a basic check used to determine if we should proceed with directional block handling at all.
-#define ITEM_CAN_BLOCK (1<<14)
+#define ITEM_CAN_BLOCK (1<<13)
// Flags for the clothing_flags var on /obj/item/clothing
diff --git a/code/__DEFINES/_flags/obj_flags.dm b/code/__DEFINES/_flags/obj_flags.dm
index a936a5cef5..ce1e126f12 100644
--- a/code/__DEFINES/_flags/obj_flags.dm
+++ b/code/__DEFINES/_flags/obj_flags.dm
@@ -9,8 +9,11 @@
#define UNIQUE_RENAME (1<<6) //can you customize the description/name of the thing?
#define USES_TGUI (1<<7) //put on things that use tgui on ui_interact instead of custom/old UI.
#define FROZEN (1<<8)
-#define SHOVABLE_ONTO (1<<9) //called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check.
-#define BLOCK_Z_FALL (1<<10)
+#define BLOCK_Z_OUT_DOWN (1<<9) // Should this object block z falling from loc?
+#define BLOCK_Z_OUT_UP (1<<10) // Should this object block z uprise from loc?
+#define BLOCK_Z_IN_DOWN (1<<11) // Should this object block z falling from above?
+#define BLOCK_Z_IN_UP (1<<12) // Should this object block z uprise from below?
+#define SHOVABLE_ONTO (1<<13) //called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check.
/// Integrity defines for clothing (not flags but close enough)
#define CLOTHING_PRISTINE 0 // We have no damage on the clothing
@@ -18,3 +21,6 @@
#define CLOTHING_SHREDDED 2 // The clothing is useless and cannot be equipped unless repaired first
// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
+
+/// Flags for the pod_flags var on /obj/structure/closet/supplypod
+#define FIRST_SOUNDS (1<<0) // If it shouldn't play sounds the first time it lands, used for reverse mode
diff --git a/code/__DEFINES/actionspeed_modifiers.dm b/code/__DEFINES/actionspeed_modifiers.dm
new file mode 100644
index 0000000000..40fbd3fe26
--- /dev/null
+++ b/code/__DEFINES/actionspeed_modifiers.dm
@@ -0,0 +1,2 @@
+//ids
+#define ACTIONSPEED_ID_SANITY "sanity_component"
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index a3e5423753..1d47549685 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -63,6 +63,10 @@
#define CONTRACT_UPLINK_PAGE_CONTRACTS "CONTRACTS"
#define CONTRACT_UPLINK_PAGE_HUB "HUB"
+//Lingblood stuff
+#define LINGBLOOD_DETECTION_THRESHOLD 1
+#define LINGBLOOD_EXPLOSION_MULT 2
+#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 --
#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
diff --git a/code/__DEFINES/cargo.dm b/code/__DEFINES/cargo.dm
index bba5b5c5ed..ac5272057a 100644
--- a/code/__DEFINES/cargo.dm
+++ b/code/__DEFINES/cargo.dm
@@ -13,27 +13,43 @@
#define STYLE_GONDOLA 13
#define STYLE_SEETHROUGH 14
-#define POD_ICON_STATE 1
-#define POD_NAME 2
-#define POD_DESC 3
+#define POD_SHAPE 1
+#define POD_BASE 2
+#define POD_DOOR 3
+#define POD_DECAL 4
+#define POD_GLOW 5
+#define POD_RUBBLE_TYPE 6
+#define POD_NAME 7
+#define POD_DESC 8
-#define POD_STYLES list(\
- list("supplypod", "supply pod", "A Nanotrasen supply drop pod."),\
- list("bluespacepod", "bluespace supply pod" , "A Nanotrasen Bluespace supply pod. Teleports back to CentCom after delivery."),\
- list("centcompod", "\improper Centcom supply pod", "A Nanotrasen supply pod, this one has been marked with Central Command's designations. Teleports back to Centcom after delivery."),\
- list("syndiepod", "blood-red supply pod", "A dark, intimidating supply pod, covered in the blood-red markings of the Syndicate. It's probably best to stand back from this."),\
- list("squadpod", "\improper MK. II supply pod", "A Nanotrasen supply pod. This one has been marked the markings of some sort of elite strike team."),\
- list("cultpod", "bloody supply pod", "A Nanotrasen supply pod covered in scratch-marks, blood, and strange runes."),\
- list("missilepod", "cruise missile", "A big ass missile that didn't seem to fully detonate. It was likely launched from some far-off deep space missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."),\
- list("smissilepod", "\improper Syndicate cruise missile", "A big ass, blood-red missile that didn't seem to fully detonate. It was likely launched from some deep space Syndicate missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."),\
- list("boxpod", "\improper Aussec supply crate", "An incredibly sturdy supply crate, designed to withstand orbital re-entry. Has 'Aussec Armory - 2532' engraved on the side."),\
- list("honkpod", "\improper HONK pod", "A brightly-colored supply pod. It likely originated from the Clown Federation."),\
- list("fruitpod", "\improper Orange", "An angry orange."),\
- list("", "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\
- list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency."),\
- list("", "", "")\
-)
+#define RUBBLE_NONE 1
+#define RUBBLE_NORMAL 2
+#define RUBBLE_WIDE 3
+#define RUBBLE_THIN 4
+#define POD_SHAPE_NORML 1
+#define POD_SHAPE_OTHER 2
+
+#define SUPPLYPOD_X_OFFSET -16
+
+GLOBAL_LIST_EMPTY(supplypod_loading_bays)
+
+GLOBAL_LIST_INIT(podstyles, list(\
+ list(POD_SHAPE_NORML, "pod", TRUE, "default", "yellow", RUBBLE_NORMAL, "supply pod", "A Nanotrasen supply drop pod."),\
+ list(POD_SHAPE_NORML, "advpod", TRUE, "bluespace", "blue", RUBBLE_NORMAL, "bluespace supply pod" , "A Nanotrasen Bluespace supply pod. Teleports back to CentCom after delivery."),\
+ list(POD_SHAPE_NORML, "advpod", TRUE, "centcom", "blue", RUBBLE_NORMAL, "\improper CentCom supply pod", "A Nanotrasen supply pod, this one has been marked with Central Command's designations. Teleports back to CentCom after delivery."),\
+ list(POD_SHAPE_NORML, "darkpod", TRUE, "syndicate", "red", RUBBLE_NORMAL, "blood-red supply pod", "An intimidating supply pod, covered in the blood-red markings of the Syndicate. It's probably best to stand back from this."),\
+ list(POD_SHAPE_NORML, "darkpod", TRUE, "deathsquad", "blue", RUBBLE_NORMAL, "\improper Deathsquad drop pod", "A Nanotrasen drop pod. This one has been marked the markings of Nanotrasen's elite strike team."),\
+ list(POD_SHAPE_NORML, "pod", TRUE, "cultist", "red", RUBBLE_NORMAL, "bloody supply pod", "A Nanotrasen supply pod covered in scratch-marks, blood, and strange runes."),\
+ list(POD_SHAPE_OTHER, "missile", FALSE, FALSE, FALSE, RUBBLE_THIN, "cruise missile", "A big ass missile that didn't seem to fully detonate. It was likely launched from some far-off deep space missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."),\
+ list(POD_SHAPE_OTHER, "smissile", FALSE, FALSE, FALSE, RUBBLE_THIN, "\improper Syndicate cruise missile", "A big ass, blood-red missile that didn't seem to fully detonate. It was likely launched from some deep space Syndicate missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."),\
+ list(POD_SHAPE_OTHER, "box", TRUE, FALSE, FALSE, RUBBLE_WIDE, "\improper Aussec supply crate", "An incredibly sturdy supply crate, designed to withstand orbital re-entry. Has 'Aussec Armory - 2532' engraved on the side."),\
+ list(POD_SHAPE_NORML, "clownpod", TRUE, "clown", "green", RUBBLE_NORMAL, "\improper HONK pod", "A brightly-colored supply pod. It likely originated from the Clown Federation."),\
+ list(POD_SHAPE_OTHER, "orange", TRUE, FALSE, FALSE, RUBBLE_NONE, "\improper Orange", "An angry orange."),\
+ list(POD_SHAPE_OTHER, FALSE, FALSE, FALSE, FALSE, RUBBLE_NONE, "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\
+ list(POD_SHAPE_OTHER, "gondola", FALSE, FALSE, FALSE, RUBBLE_NONE, "gondola", "The silent walker. This one seems to be part of a delivery agency."),\
+ list(POD_SHAPE_OTHER, FALSE, FALSE, FALSE, FALSE, RUBBLE_NONE, FALSE, FALSE, "rl_click", "give_po")\
+))
#define PACK_GOODY_NONE 0
#define PACK_GOODY_PUBLIC 1 //can be bought by both privates and cargo
-#define PACK_GOODY_PRIVATE 2 //can be bought only by privates
\ No newline at end of file
+#define PACK_GOODY_PRIVATE 2 //can be bought only by privates
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index 58125b5497..923355b340 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -105,3 +105,12 @@
//belly sound pref things
#define NORMIE_HEARCHECK 4
+
+//icon states for the default eyes and for a state for no eye
+#define DEFAULT_EYES_TYPE "normal"
+#define DEFAULT_LEFT_EYE_STATE "normal_left_eye"
+#define DEFAULT_RIGHT_EYE_STATE "normal_right_eye"
+#define DEFAULT_NO_EYE_STATE "no_eye"
+
+//special species definitions
+#define MINIMUM_MUTANT_COLOR "#202020" //this is how dark players mutant parts and skin can be
diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm
index 2273d34c82..fb461acfa4 100644
--- a/code/__DEFINES/colors.dm
+++ b/code/__DEFINES/colors.dm
@@ -1,54 +1,54 @@
// This is eventually for wjohn to add more color standardization stuff like I keep asking him >:(
-#define COLOR_INPUT_DISABLED "#F0F0F0"
-#define COLOR_INPUT_ENABLED "#D3B5B5"
-#define COLOR_FLOORTILE_GRAY "#8D8B8B"
-#define COLOR_ALMOST_BLACK "#333333"
-#define COLOR_BLACK "#000000"
-#define COLOR_RED "#FF0000"
-#define COLOR_RED_LIGHT "#FF3333"
-#define COLOR_MAROON "#800000"
-#define COLOR_YELLOW "#FFFF00"
-#define COLOR_OLIVE "#808000"
-#define COLOR_LIME "#32CD32"
-#define COLOR_GREEN "#008000"
-#define COLOR_CYAN "#00FFFF"
-#define COLOR_TEAL "#008080"
-#define COLOR_BLUE "#0000FF"
-#define COLOR_BLUE_LIGHT "#33CCFF"
-#define COLOR_NAVY "#000080"
-#define COLOR_PINK "#FFC0CB"
-#define COLOR_MAGENTA "#FF00FF"
-#define COLOR_PURPLE "#800080"
-#define COLOR_ORANGE "#FF9900"
-#define COLOR_BEIGE "#CEB689"
-#define COLOR_BLUE_GRAY "#75A2BB"
-#define COLOR_BROWN "#BA9F6D"
-#define COLOR_DARK_BROWN "#997C4F"
-#define COLOR_DARK_ORANGE "#C3630C"
-#define COLOR_GREEN_GRAY "#99BB76"
-#define COLOR_RED_GRAY "#B4696A"
-#define COLOR_PALE_BLUE_GRAY "#98C5DF"
-#define COLOR_PALE_GREEN_GRAY "#B7D993"
-#define COLOR_PALE_ORANGE "#FFC066"
-#define COLOR_PALE_RED_GRAY "#D59998"
-#define COLOR_PALE_PURPLE_GRAY "#CBB1CA"
-#define COLOR_PURPLE_GRAY "#AE8CA8"
+#define COLOR_INPUT_DISABLED "#F0F0F0"
+#define COLOR_INPUT_ENABLED "#D3B5B5"
+#define COLOR_FLOORTILE_GRAY "#8D8B8B"
+#define COLOR_ALMOST_BLACK "#333333"
+#define COLOR_BLACK "#000000"
+#define COLOR_RED "#FF0000"
+#define COLOR_RED_LIGHT "#FF3333"
+#define COLOR_MAROON "#800000"
+#define COLOR_YELLOW "#FFFF00"
+#define COLOR_OLIVE "#808000"
+#define COLOR_LIME "#32CD32"
+#define COLOR_GREEN "#008000"
+#define COLOR_CYAN "#00FFFF"
+#define COLOR_TEAL "#008080"
+#define COLOR_BLUE "#0000FF"
+#define COLOR_BLUE_LIGHT "#33CCFF"
+#define COLOR_NAVY "#000080"
+#define COLOR_PINK "#FFC0CB"
+#define COLOR_MAGENTA "#FF00FF"
+#define COLOR_PURPLE "#800080"
+#define COLOR_ORANGE "#FF9900"
+#define COLOR_BEIGE "#CEB689"
+#define COLOR_BLUE_GRAY "#75A2BB"
+#define COLOR_BROWN "#BA9F6D"
+#define COLOR_DARK_BROWN "#997C4F"
+#define COLOR_DARK_ORANGE "#C3630C"
+#define COLOR_GREEN_GRAY "#99BB76"
+#define COLOR_RED_GRAY "#B4696A"
+#define COLOR_PALE_BLUE_GRAY "#98C5DF"
+#define COLOR_PALE_GREEN_GRAY "#B7D993"
+#define COLOR_PALE_ORANGE "#FFC066"
+#define COLOR_PALE_RED_GRAY "#D59998"
+#define COLOR_PALE_PURPLE_GRAY "#CBB1CA"
+#define COLOR_PURPLE_GRAY "#AE8CA8"
-//Color defines used by the assembly detailer.
-#define COLOR_ASSEMBLY_BLACK "#545454"
-#define COLOR_ASSEMBLY_BGRAY "#9497AB"
-#define COLOR_ASSEMBLY_WHITE "#E2E2E2"
-#define COLOR_ASSEMBLY_RED "#CC4242"
-#define COLOR_ASSEMBLY_ORANGE "#E39751"
-#define COLOR_ASSEMBLY_BEIGE "#AF9366"
-#define COLOR_ASSEMBLY_BROWN "#97670E"
-#define COLOR_ASSEMBLY_GOLD "#AA9100"
-#define COLOR_ASSEMBLY_YELLOW "#CECA2B"
-#define COLOR_ASSEMBLY_GURKHA "#999875"
-#define COLOR_ASSEMBLY_LGREEN "#789876"
-#define COLOR_ASSEMBLY_GREEN "#44843C"
-#define COLOR_ASSEMBLY_LBLUE "#5D99BE"
-#define COLOR_ASSEMBLY_BLUE "#38559E"
-#define COLOR_ASSEMBLY_PURPLE "#6F6192"
-#define COLOR_ASSEMBLY_PINK "#ff4adc"
+// Color defines used by the assembly detailer.
+#define COLOR_ASSEMBLY_BLACK "#545454"
+#define COLOR_ASSEMBLY_BGRAY "#9497AB"
+#define COLOR_ASSEMBLY_WHITE "#E2E2E2"
+#define COLOR_ASSEMBLY_RED "#CC4242"
+#define COLOR_ASSEMBLY_ORANGE "#E39751"
+#define COLOR_ASSEMBLY_BEIGE "#AF9366"
+#define COLOR_ASSEMBLY_BROWN "#97670E"
+#define COLOR_ASSEMBLY_GOLD "#AA9100"
+#define COLOR_ASSEMBLY_YELLOW "#CECA2B"
+#define COLOR_ASSEMBLY_GURKHA "#999875"
+#define COLOR_ASSEMBLY_LGREEN "#789876"
+#define COLOR_ASSEMBLY_GREEN "#44843C"
+#define COLOR_ASSEMBLY_LBLUE "#5D99BE"
+#define COLOR_ASSEMBLY_BLUE "#38559E"
+#define COLOR_ASSEMBLY_PURPLE "#6F6192"
+#define COLOR_ASSEMBLY_PINK "#ff4adc"
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index eff5d9eca9..5f5a76b58d 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -34,6 +34,8 @@
#define COMBAT_FLAGS_DEFAULT (COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE)
/// Default combat flags for everyone else (so literally everyone but humans).
#define COMBAT_FLAGS_SPRINT_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_SPRINT_FORCED | COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE)
+/// Default combat flags for those in stamina combat system
+#define COMBAT_FLAGS_STAMINA_COMBAT (COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE | COMBAT_FLAG_STAMINA_BUFFER)
/// The user wants sprint mode on
#define COMBAT_FLAG_SPRINT_TOGGLED (1<<0)
@@ -47,8 +49,8 @@
#define COMBAT_FLAG_RESISTING_REST (1<<4)
/// Intentionally resting
#define COMBAT_FLAG_INTENTIONALLY_RESTING (1<<5)
-/// Currently stamcritted but not as violently
-#define COMBAT_FLAG_SOFT_STAMCRIT (1<<6)
+/// This mob requires stamina buffer to do things that require stamina buffer. Not having this exempts the mob from stamina combat.
+#define COMBAT_FLAG_STAMINA_BUFFER (1<<6)
/// Force sprint mode on at all times, overrides everything including sprint disable traits.
#define COMBAT_FLAG_SPRINT_FORCED (1<<7)
/// This mob is capable of using the active parrying system.
@@ -64,26 +66,17 @@
// Helpers for getting someone's stamcrit state. Cast to living.
#define NOT_STAMCRIT 0
-#define SOFT_STAMCRIT 1
-#define HARD_STAMCRIT 2
+#define HARD_STAMCRIT 1
// Stamcrit check helpers
#define IS_STAMCRIT(mob) (CHECK_STAMCRIT(mob) != NOT_STAMCRIT)
-#define CHECK_STAMCRIT(mob) ((mob.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)? HARD_STAMCRIT : ((mob.combat_flags & COMBAT_FLAG_SOFT_STAMCRIT)? SOFT_STAMCRIT : NOT_STAMCRIT))
+#define CHECK_STAMCRIT(mob) (mob.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)
//stamina stuff
-///Threshold over which attacks start being hindered.
-#define STAMINA_NEAR_SOFTCRIT 90
-///softcrit for stamina damage. prevents standing up, some actions that cost stamina, etc, but doesn't force a rest or stop movement
-#define STAMINA_SOFTCRIT 100
-///sanity cap to prevent stamina actions (that are still performable) from sending you into crit.
-#define STAMINA_NEAR_CRIT 130
-///crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit
+/// crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit
#define STAMINA_CRIT 140
-///same as STAMINA_SOFTCRIT except for the more traditional health calculations
-#define STAMINA_SOFTCRIT_TRADITIONAL 0
-///ditto, but for STAMINA_CRIT
-#define STAMINA_CRIT_TRADITIONAL -40
+/// Threshold under for which you are unable to draw from stamina health to replace stamina buffer
+#define STAMINA_NO_OVERDRAW_THRESHOLD 100
#define CRAWLUNDER_DELAY 30 //Delay for crawling under a standing mob
@@ -252,36 +245,6 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
//We will round to this value in damage calculations.
#define DAMAGE_PRECISION 0.01
-//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25)
-#define TOTAL_MASS_TINY_ITEM 1.25
-#define TOTAL_MASS_SMALL_ITEM 2.5
-#define TOTAL_MASS_NORMAL_ITEM 3.75
-#define TOTAL_MASS_BULKY_ITEM 5
-#define TOTAL_MASS_HUGE_ITEM 6.25
-#define TOTAL_MASS_GIGANTIC_ITEM 7.5
-
-#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway.
-#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds.
-#define TOTAL_MASS_TOY_SWORD 1.5
-
-//stamina cost defines.
-#define STAM_COST_ATTACK_OBJ_MULT 1.2
-#define STAM_COST_ATTACK_MOB_MULT 1
-#define STAM_COST_BATON_MOB_MULT 1
-#define STAM_COST_NO_COMBAT_MULT 1.25
-#define STAM_COST_W_CLASS_MULT 1.25
-#define STAM_COST_THROW_MULT 2
-#define STAM_COST_THROW_MOB 2.5 //multiplied by (mob size + 1)^2.
-
-///Multiplier of the (STAMINA_NEAR_CRIT - user current stamina loss) : (STAMINA_NEAR_CRIT - STAMINA_SOFTCRIT) ratio used in damage penalties when stam soft-critted.
-#define STAM_CRIT_ITEM_ATTACK_PENALTY 0.66
-/// changeNext_move penalty multiplier of the above.
-#define STAM_CRIT_ITEM_ATTACK_DELAY 1.75
-/// Damage penalty when fighting prone.
-#define LYING_DAMAGE_PENALTY 0.7
-/// Added delay when firing guns stam-softcritted. Summed with a hardset CLICK_CD_RANGE delay, similar to STAM_CRIT_DAMAGE_DELAY otherwise.
-#define STAM_CRIT_GUN_DELAY 2.75
-
//stamina recovery defines. Blocked if combat mode is on.
#define STAM_RECOVERY_STAM_CRIT -7.5
#define STAM_RECOVERY_RESTING -6
diff --git a/code/__DEFINES/combat/stamina_combat.dm b/code/__DEFINES/combat/stamina_combat.dm
new file mode 100644
index 0000000000..1f781ca3e0
--- /dev/null
+++ b/code/__DEFINES/combat/stamina_combat.dm
@@ -0,0 +1,35 @@
+// Stamina Buffer
+
+// Standard amounts for stamina usage
+
+// Multipliers
+/// Base stamina cost for an item of a certain w_class without total_mass set.
+#define STAM_COST_W_CLASS_MULT 1.25
+
+// Flat amounts
+/// Usage for eyestabbing with a screwdriver
+#define STAMINA_COST_ITEM_EYESTAB 7.5
+/// Usage for shoving yourself off the ground instantly
+#define STAMINA_COST_SHOVE_UP 10
+
+//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25)
+#define TOTAL_MASS_TINY_ITEM 1.25
+#define TOTAL_MASS_SMALL_ITEM 2.5
+#define TOTAL_MASS_NORMAL_ITEM 3.75
+#define TOTAL_MASS_BULKY_ITEM 5
+#define TOTAL_MASS_HUGE_ITEM 6.25
+#define TOTAL_MASS_GIGANTIC_ITEM 7.5
+
+#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway.
+#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds.
+#define TOTAL_MASS_TOY_SWORD 1.5
+
+//stamina cost defines.
+#define STAM_COST_ATTACK_OBJ_MULT 0.75
+#define STAM_COST_ATTACK_MOB_MULT 1
+#define STAM_COST_BATON_MOB_MULT 0.85
+#define STAM_COST_THROW_MULT 0.75
+#define STAM_COST_THROW_MOB 1.25 //multiplied by (mob size + 1)^2.
+
+/// Damage penalty when fighting prone.
+#define LYING_DAMAGE_PENALTY 0.7
diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm
index 20c1df2ec7..0428a16828 100644
--- a/code/__DEFINES/configuration.dm
+++ b/code/__DEFINES/configuration.dm
@@ -3,6 +3,8 @@
#define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y)
/// Gets the datum of the object, for when editing a const define.
#define CONFIG_GET_ENTRY(X) global.config.GetEntryDatum(/datum/config_entry/##X)
+/// Caches an entry in the proc
+#define CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(X, varname) var/static/datum/config_entry/##X/entrycache_##varname;if(!entrycache_##varname){entrycache_##varname=CONFIG_GET_ENTRY(##X);};var/##varname=entrycache_##varname.config_entry_value
#define CONFIG_MAPS_FILE "maps.txt"
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 02e3fe6f3d..7b214df421 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -5,9 +5,21 @@
// global signals
// These are signals which can be listened to by any component on any parent
// start global signals with "!", this used to be necessary but now it's just a formatting choice
-#define COMSIG_GLOB_NEW_Z "!new_z" //from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args)
-#define COMSIG_GLOB_VAR_EDIT "!var_edit" //called after a successful var edit somewhere in the world: (list/args)
-#define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special" //global living say plug - use sparingly: (mob/speaker , message)
+/// from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args)
+#define COMSIG_GLOB_NEW_Z "!new_z"
+/// called after a successful var edit somewhere in the world: (list/args)
+#define COMSIG_GLOB_VAR_EDIT "!var_edit"
+/// called after an explosion happened : (epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
+#define COMSIG_GLOB_EXPLOSION "!explosion"
+/// mob was created somewhere : (mob)
+#define COMSIG_GLOB_MOB_CREATED "!mob_created"
+/// mob died somewhere : (mob , gibbed)
+#define COMSIG_GLOB_MOB_DEATH "!mob_death"
+/// global living say plug - use sparingly: (mob/speaker , message)
+#define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special"
+/// called by datum/cinematic/play() : (datum/cinematic/new_cinematic)
+#define COMSIG_GLOB_PLAY_CINEMATIC "!play_cinematic"
+ #define COMPONENT_GLOB_BLOCK_CINEMATIC 1
// signals from globally accessible objects
/// from SSsun when the sun changes position : (azimuth)
@@ -73,7 +85,7 @@
#define COMSIG_ATOM_EMP_ACT "atom_emp_act"
///from base of atom/fire_act(): (exposed_temperature, exposed_volume)
#define COMSIG_ATOM_FIRE_ACT "atom_fire_act"
-///from base of atom/bullet_act(): (/obj/projectile, def_zone)
+///from base of atom/bullet_act(): (/obj/item/projectile, def_zone)
#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act"
///from base of atom/blob_act(): (/obj/structure/blob)
#define COMSIG_ATOM_BLOB_ACT "atom_blob_act"
@@ -369,6 +381,8 @@
#define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/effect/mine/proc/triggermine]:
// Uncovered information
#define COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION 1
+///from [/obj/structure/closet/supplypod/proc/endlaunch]:
+#define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom"
// /obj/item/grenade signals
#define COMSIG_GRENADE_PRIME "grenade_prime" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 508bb64a62..3407b3342b 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -44,7 +44,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isplatingturf(A) (istype(A, /turf/open/floor/plating))
-#define istransparentturf(A) (istype(A, /turf/open/transparent))
+#define istransparentturf(A) (istype(A, /turf/open/transparent)||istype(A, /turf/open/space/transparent))
//Mobs
#define isliving(A) (istype(A, /mob/living))
@@ -236,3 +236,5 @@ GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list(
#define isblobmonster(O) (istype(O, /mob/living/simple_animal/hostile/blob))
#define isshuttleturf(T) (length(T.baseturfs) && (/turf/baseturf_skipover/shuttle in T.baseturfs))
+
+#define isProbablyWallMounted(O) (O.pixel_x > 20 || O.pixel_x < -20 || O.pixel_y > 20 || O.pixel_y < -20)
diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm
index 9188efacfd..8ab33689d3 100644
--- a/code/__DEFINES/layers_planes.dm
+++ b/code/__DEFINES/layers_planes.dm
@@ -37,7 +37,9 @@
#define FIELD_OF_VISION_VISUAL_RENDER_TARGET "FIELD_OF_VISION_VISUAL_PLANE"
#define CHAT_PLANE -1 //We don't want heard messages to be hidden by FoV.
-#define CHAT_LAYER 12.1 //Legacy, it doesn't matter that much because we are displayed above the game plane anyway.
+
+#define CHAT_LAYER 12.0001 // Do not insert layers between these two values
+#define CHAT_LAYER_MAX 12.9999
#define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals
#define BLACKNESS_PLANE_RENDER_TARGET "BLACKNESS_PLANE"
diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm
index c5c2dd58c2..854b6c9dcf 100644
--- a/code/__DEFINES/maps.dm
+++ b/code/__DEFINES/maps.dm
@@ -20,11 +20,6 @@ Multi-Z stations are supported and multi-Z mining and away missions would
require only minor tweaks.
*/
-// helpers for modifying jobs, used in various job_changes.dm files
-#define MAP_JOB_CHECK if(SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) { return; }
-#define MAP_JOB_CHECK_BASE if(SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) { return ..(); }
-#define MAP_REMOVE_JOB(jobpath) /datum/job/##jobpath/map_check() { return (SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) && ..() }
-
#define SPACERUIN_MAP_EDGE_PAD 15
// traits
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 586fce3e0c..d39b8641ba 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -1,17 +1,17 @@
/*ALL MOB-RELATED DEFINES THAT DON'T BELONG IN ANOTHER FILE GO HERE*/
-//Misc mob defines
+// Misc mob defines
-//Ready states at roundstart for mob/dead/new_player
+// Ready states at roundstart for mob/dead/new_player
#define PLAYER_NOT_READY 0
#define PLAYER_READY_TO_PLAY 1
#define PLAYER_READY_TO_OBSERVE 2
-//movement intent defines for the m_intent var
+// movement intent defines for the m_intent var
#define MOVE_INTENT_WALK "walk"
#define MOVE_INTENT_RUN "run"
-//Blood levels
+// Blood levels
#define BLOOD_VOLUME_MAX_LETHAL 2150
#define BLOOD_VOLUME_EXCESS 2100
#define BLOOD_VOLUME_MAXIMUM 2000
@@ -22,34 +22,34 @@
#define BLOOD_VOLUME_BAD 224
#define BLOOD_VOLUME_SURVIVE 122
-//Sizes of mobs, used by mob/living/var/mob_size
+// Sizes of mobs, used by mob/living/var/mob_size
#define MOB_SIZE_TINY 0
#define MOB_SIZE_SMALL 1
#define MOB_SIZE_HUMAN 2
#define MOB_SIZE_LARGE 3
-//Ventcrawling defines
+// Ventcrawling defines
#define VENTCRAWLER_NONE 0
#define VENTCRAWLER_NUDE 1
#define VENTCRAWLER_ALWAYS 2
-//Bloodcrawling defines
+// Bloodcrawling defines
#define BLOODCRAWL 1
#define BLOODCRAWL_EAT 2
-//Mob bio-types flags
-#define MOB_ORGANIC (1 << 0)
+// Mob bio-types flags
+#define MOB_ORGANIC (1 << 0)
#define MOB_MINERAL (1 << 1)
-#define MOB_ROBOTIC (1 << 2)
+#define MOB_ROBOTIC (1 << 2)
#define MOB_UNDEAD (1 << 3)
-#define MOB_HUMANOID (1 << 4)
-#define MOB_BUG (1 << 5)
+#define MOB_HUMANOID (1 << 4)
+#define MOB_BUG (1 << 5)
#define MOB_BEAST (1 << 6)
-#define MOB_EPIC (1 << 7) //megafauna
+#define MOB_EPIC (1 << 7) // Megafauna
#define MOB_REPTILE (1 << 8)
#define MOB_SPIRIT (1 << 9)
-//Organ defines for carbon mobs
+// Organ defines for carbon mobs
#define ORGAN_ORGANIC 1
#define ORGAN_ROBOTIC 2
@@ -66,194 +66,194 @@
#define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi'
#define MONKEY_BODYPART "monkey"
-#define ALIEN_BODYPART "alien"
-#define LARVA_BODYPART "larva"
-#define DEVIL_BODYPART "devil"
+#define ALIEN_BODYPART "alien"
+#define LARVA_BODYPART "larva"
+#define DEVIL_BODYPART "devil"
/*see __DEFINES/inventory.dm for bodypart bitflag defines*/
// Health/damage defines for carbon mobs
#define HUMAN_MAX_OXYLOSS 3
#define HUMAN_CRIT_MAX_OXYLOSS (SSmobs.wait/30)
-#define HEAT_DAMAGE_LEVEL_1 2 //Amount of damage applied when your body temperature just passes the 360.15k safety point
-#define HEAT_DAMAGE_LEVEL_2 3 //Amount of damage applied when your body temperature passes the 400K point
-#define HEAT_DAMAGE_LEVEL_3 8 //Amount of damage applied when your body temperature passes the 460K point and you are on fire
+#define HEAT_DAMAGE_LEVEL_1 2 // Amount of damage applied when your body temperature just passes the 360.15k safety point
+#define HEAT_DAMAGE_LEVEL_2 3 // Amount of damage applied when your body temperature passes the 400K point
+#define HEAT_DAMAGE_LEVEL_3 8 // Amount of damage applied when your body temperature passes the 460K point and you are on fire
-#define COLD_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when your body temperature just passes the 260.15k safety point
-#define COLD_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when your body temperature passes the 200K point
-#define COLD_DAMAGE_LEVEL_3 3 //Amount of damage applied when your body temperature passes the 120K point
+#define COLD_DAMAGE_LEVEL_1 0.5 // Amount of damage applied when your body temperature just passes the 260.15k safety point
+#define COLD_DAMAGE_LEVEL_2 1.5 // Amount of damage applied when your body temperature passes the 200K point
+#define COLD_DAMAGE_LEVEL_3 3 // Amount of damage applied when your body temperature passes the 120K point
-//Note that gas heat damage is only applied once every FOUR ticks.
-#define HEAT_GAS_DAMAGE_LEVEL_1 2 //Amount of damage applied when the current breath's temperature just passes the 360.15k safety point
-#define HEAT_GAS_DAMAGE_LEVEL_2 4 //Amount of damage applied when the current breath's temperature passes the 400K point
-#define HEAT_GAS_DAMAGE_LEVEL_3 8 //Amount of damage applied when the current breath's temperature passes the 1000K point
+// Note that gas heat damage is only applied once every FOUR ticks.
+#define HEAT_GAS_DAMAGE_LEVEL_1 2 // Amount of damage applied when the current breath's temperature just passes the 360.15k safety point
+#define HEAT_GAS_DAMAGE_LEVEL_2 4 // Amount of damage applied when the current breath's temperature passes the 400K point
+#define HEAT_GAS_DAMAGE_LEVEL_3 8 // Amount of damage applied when the current breath's temperature passes the 1000K point
-#define COLD_GAS_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when the current breath's temperature just passes the 260.15k safety point
-#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point
-#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point
+#define COLD_GAS_DAMAGE_LEVEL_1 0.5 // Amount of damage applied when the current breath's temperature just passes the 260.15k safety point
+#define COLD_GAS_DAMAGE_LEVEL_2 1.5 // Amount of damage applied when the current breath's temperature passes the 200K point
+#define COLD_GAS_DAMAGE_LEVEL_3 3 // Amount of damage applied when the current breath's temperature passes the 120K point
-//Brain Damage defines
-#define BRAIN_DAMAGE_MILD 20
+// Brain Damage defines
+#define BRAIN_DAMAGE_MILD 20
#define BRAIN_DAMAGE_SEVERE 100
-#define BRAIN_DAMAGE_DEATH 200
+#define BRAIN_DAMAGE_DEATH 200
#define BRAIN_TRAUMA_MILD /datum/brain_trauma/mild
#define BRAIN_TRAUMA_SEVERE /datum/brain_trauma/severe
#define BRAIN_TRAUMA_SPECIAL /datum/brain_trauma/special
#define BRAIN_TRAUMA_MAGIC /datum/brain_trauma/magic
-#define TRAUMA_RESILIENCE_BASIC 1 //Curable with chems
-#define TRAUMA_RESILIENCE_SURGERY 2 //Curable with brain surgery
-#define TRAUMA_RESILIENCE_LOBOTOMY 3 //Curable with lobotomy
-#define TRAUMA_RESILIENCE_WOUND 4 //Curable by healing the head wound
-#define TRAUMA_RESILIENCE_MAGIC 5 //Curable only with magic
-#define TRAUMA_RESILIENCE_ABSOLUTE 6 //This is here to stay
+#define TRAUMA_RESILIENCE_BASIC 1 // Curable with chems
+#define TRAUMA_RESILIENCE_SURGERY 2 // Curable with brain surgery
+#define TRAUMA_RESILIENCE_LOBOTOMY 3 // Curable with lobotomy
+#define TRAUMA_RESILIENCE_WOUND 4 // Curable by healing the head wound
+#define TRAUMA_RESILIENCE_MAGIC 5 // Curable only with magic
+#define TRAUMA_RESILIENCE_ABSOLUTE 6 // This is here to stay
-//Limit of traumas for each resilience tier
-#define TRAUMA_LIMIT_BASIC 3
-#define TRAUMA_LIMIT_SURGERY 2
-#define TRAUMA_LIMIT_WOUND 2
+// Limit of traumas for each resilience tier
+#define TRAUMA_LIMIT_BASIC 3
+#define TRAUMA_LIMIT_SURGERY 2
+#define TRAUMA_LIMIT_WOUND 2
#define TRAUMA_LIMIT_LOBOTOMY 3
-#define TRAUMA_LIMIT_MAGIC 3
+#define TRAUMA_LIMIT_MAGIC 3
#define TRAUMA_LIMIT_ABSOLUTE INFINITY
#define BRAIN_DAMAGE_INTEGRITY_MULTIPLIER 0.5
-//Surgery Defines
+// Surgery Defines
#define BIOWARE_GENERIC "generic"
#define BIOWARE_NERVES "nerves"
#define BIOWARE_CIRCULATION "circulation"
#define BIOWARE_LIGAMENTS "ligaments"
-//Health hud screws for carbon mobs
-#define SCREWYHUD_NONE 0
-#define SCREWYHUD_CRIT 1
-#define SCREWYHUD_DEAD 2
+// Health hud screws for carbon mobs
+#define SCREWYHUD_NONE 0
+#define SCREWYHUD_CRIT 1
+#define SCREWYHUD_DEAD 2
#define SCREWYHUD_HEALTHY 3
-//Threshold levels for beauty for humans
+// Threshold levels for beauty for humans
#define BEAUTY_LEVEL_HORRID -66
-#define BEAUTY_LEVEL_BAD -33
-#define BEAUTY_LEVEL_DECENT 33
-#define BEAUTY_LEVEL_GOOD 66
-#define BEAUTY_LEVEL_GREAT 100
+#define BEAUTY_LEVEL_BAD -33
+#define BEAUTY_LEVEL_DECENT 33
+#define BEAUTY_LEVEL_GOOD 66
+#define BEAUTY_LEVEL_GREAT 100
-//Moods levels for humans
-#define MOOD_LEVEL_HAPPY4 15
-#define MOOD_LEVEL_HAPPY3 10
-#define MOOD_LEVEL_HAPPY2 6
-#define MOOD_LEVEL_HAPPY1 2
-#define MOOD_LEVEL_NEUTRAL 0
-#define MOOD_LEVEL_SAD1 -3
-#define MOOD_LEVEL_SAD2 -12
-#define MOOD_LEVEL_SAD3 -18
-#define MOOD_LEVEL_SAD4 -25
+// Moods levels for humans
+#define MOOD_LEVEL_HAPPY4 15
+#define MOOD_LEVEL_HAPPY3 10
+#define MOOD_LEVEL_HAPPY2 6
+#define MOOD_LEVEL_HAPPY1 2
+#define MOOD_LEVEL_NEUTRAL 0
+#define MOOD_LEVEL_SAD1 -3
+#define MOOD_LEVEL_SAD2 -12
+#define MOOD_LEVEL_SAD3 -18
+#define MOOD_LEVEL_SAD4 -25
-//Sanity levels for humans
-#define SANITY_AMAZING 150
-#define SANITY_GREAT 125
-#define SANITY_NEUTRAL 100
+// Sanity levels for humans
+#define SANITY_AMAZING 150
+#define SANITY_GREAT 125
+#define SANITY_NEUTRAL 100
#define SANITY_DISTURBED 75
-#define SANITY_UNSTABLE 50
-#define SANITY_CRAZY 25
-#define SANITY_INSANE 0
+#define SANITY_UNSTABLE 50
+#define SANITY_CRAZY 25
+#define SANITY_INSANE 0
-//Nutrition levels for humans
-#define NUTRITION_LEVEL_FAT 600
-#define NUTRITION_LEVEL_FULL 550
+// Nutrition levels for humans
+#define NUTRITION_LEVEL_FAT 600
+#define NUTRITION_LEVEL_FULL 550
#define NUTRITION_LEVEL_WELL_FED 450
-#define NUTRITION_LEVEL_FED 350
-#define NUTRITION_LEVEL_HUNGRY 250
+#define NUTRITION_LEVEL_FED 350
+#define NUTRITION_LEVEL_HUNGRY 250
#define NUTRITION_LEVEL_STARVING 150
#define NUTRITION_LEVEL_START_MIN 250
#define NUTRITION_LEVEL_START_MAX 400
-//Disgust levels for humans
-#define DISGUST_LEVEL_MAXEDOUT 150
-#define DISGUST_LEVEL_DISGUSTED 75
-#define DISGUST_LEVEL_VERYGROSS 50
-#define DISGUST_LEVEL_GROSS 25
+// Disgust levels for humans
+#define DISGUST_LEVEL_MAXEDOUT 150
+#define DISGUST_LEVEL_DISGUSTED 75
+#define DISGUST_LEVEL_VERYGROSS 50
+#define DISGUST_LEVEL_GROSS 25
-//Charge levels for Ethereals
-#define ETHEREAL_CHARGE_NONE 0
-#define ETHEREAL_CHARGE_LOWPOWER 20
-#define ETHEREAL_CHARGE_NORMAL 50
+// Charge levels for Ethereals
+#define ETHEREAL_CHARGE_NONE 0
+#define ETHEREAL_CHARGE_LOWPOWER 20
+#define ETHEREAL_CHARGE_NORMAL 50
#define ETHEREAL_CHARGE_ALMOSTFULL 75
-#define ETHEREAL_CHARGE_FULL 100
-#define ETHEREAL_CHARGE_OVERLOAD 125
+#define ETHEREAL_CHARGE_FULL 100
+#define ETHEREAL_CHARGE_OVERLOAD 125
#define ETHEREAL_CHARGE_DANGEROUS 150
-//Slime evolution threshold. Controls how fast slimes can split/grow
+// Slime evolution threshold. Controls how fast slimes can split/grow
#define SLIME_EVOLUTION_THRESHOLD 10
-//Slime extract crossing. Controls how many extracts is required to feed to a slime to core-cross.
+// Slime extract crossing. Controls how many extracts is required to feed to a slime to core-cross.
#define SLIME_EXTRACT_CROSSING_REQUIRED 10
-//Slime commands defines
-#define SLIME_FRIENDSHIP_FOLLOW 3 //Min friendship to order it to follow
-#define SLIME_FRIENDSHIP_STOPEAT 5 //Min friendship to order it to stop eating someone
-#define SLIME_FRIENDSHIP_STOPEAT_NOANGRY 7 //Min friendship to order it to stop eating someone without it losing friendship
-#define SLIME_FRIENDSHIP_STOPCHASE 4 //Min friendship to order it to stop chasing someone (their target)
-#define SLIME_FRIENDSHIP_STOPCHASE_NOANGRY 6 //Min friendship to order it to stop chasing someone (their target) without it losing friendship
-#define SLIME_FRIENDSHIP_STAY 3 //Min friendship to order it to stay
-#define SLIME_FRIENDSHIP_ATTACK 8 //Min friendship to order it to attack
+// Slime commands defines
+#define SLIME_FRIENDSHIP_FOLLOW 3 // Min friendship to order it to follow
+#define SLIME_FRIENDSHIP_STOPEAT 5 // Min friendship to order it to stop eating someone
+#define SLIME_FRIENDSHIP_STOPEAT_NOANGRY 7 // Min friendship to order it to stop eating someone without it losing friendship
+#define SLIME_FRIENDSHIP_STOPCHASE 4 // Min friendship to order it to stop chasing someone (their target)
+#define SLIME_FRIENDSHIP_STOPCHASE_NOANGRY 6 // Min friendship to order it to stop chasing someone (their target) without it losing friendship
+#define SLIME_FRIENDSHIP_STAY 3 // Min friendship to order it to stay
+#define SLIME_FRIENDSHIP_ATTACK 8 // Min friendship to order it to attack
-//Sentience types, to prevent things like sentience potions from giving bosses sentience
-#define SENTIENCE_ORGANIC 1
+// Sentience types, to prevent things like sentience potions from giving bosses sentience
+#define SENTIENCE_ORGANIC 1
#define SENTIENCE_ARTIFICIAL 2
-// #define SENTIENCE_OTHER 3 unused
-#define SENTIENCE_MINEBOT 4
-#define SENTIENCE_BOSS 5
+//#define SENTIENCE_OTHER 3 // Unused
+#define SENTIENCE_MINEBOT 4
+#define SENTIENCE_BOSS 5
-//Mob AI Status
+// Mob AI Status
-//Hostile simple animals
-//If you add a new status, be sure to add a list for it to the simple_animals global in _globalvars/lists/mobs.dm
+// Hostile simple animals
+// If you add a new status, be sure to add a list for it to the simple_animals global in _globalvars/lists/mobs.dm
#define AI_ON 1
#define AI_IDLE 2
#define AI_OFF 3
#define AI_Z_OFF 4
-//determines if a mob can smash through it
-#define ENVIRONMENT_SMASH_NONE 0
-#define ENVIRONMENT_SMASH_STRUCTURES (1<<0) //crates, lockers, ect
-#define ENVIRONMENT_SMASH_WALLS (1<<1) //walls
-#define ENVIRONMENT_SMASH_RWALLS (1<<2) //rwalls
+// determines if a mob can smash through it
+#define ENVIRONMENT_SMASH_NONE 0
+#define ENVIRONMENT_SMASH_STRUCTURES (1<<0) // crates, lockers, ect
+#define ENVIRONMENT_SMASH_WALLS (1<<1) // walls
+#define ENVIRONMENT_SMASH_RWALLS (1<<2) // rwalls
-#define NO_SLIP_WHEN_WALKING (1<<0)
-#define SLIDE (1<<1)
-#define GALOSHES_DONT_HELP (1<<2)
-#define FLYING_DOESNT_HELP (1<<3)
-#define SLIDE_ICE (1<<4)
-#define SLIP_WHEN_CRAWLING (1<<5) //clown planet ruin amongst others
-#define SLIP_WHEN_JOGGING (1<<6) //slips prevented by walking are also dodged if the mob is nor sprinting or fatigued... unless this flag is on.
+#define NO_SLIP_WHEN_WALKING (1<<0)
+#define SLIDE (1<<1)
+#define GALOSHES_DONT_HELP (1<<2)
+#define FLYING_DOESNT_HELP (1<<3)
+#define SLIDE_ICE (1<<4)
+#define SLIP_WHEN_CRAWLING (1<<5) // clown planet ruin amongst others
+#define SLIP_WHEN_JOGGING (1<<6) // slips prevented by walking are also dodged if the mob is nor sprinting or fatigued... unless this flag is on.
#define MAX_CHICKENS 50
-///Flags used by the flags parameter of electrocute act.
+// /Flags used by the flags parameter of electrocute act.
-///Makes it so that the shock doesn't take gloves into account.
-#define SHOCK_NOGLOVES (1 << 0)
-///Used when the shock is from a tesla bolt.
-#define SHOCK_TESLA (1 << 1)
-///Used when an illusion shocks something. Makes the shock deal stamina damage and not trigger certain secondary effects.
-#define SHOCK_ILLUSION (1 << 2)
-///The shock doesn't stun.
-#define SHOCK_NOSTUN (1 << 3)
+// /Makes it so that the shock doesn't take gloves into account.
+#define SHOCK_NOGLOVES (1 << 0)
+// /Used when the shock is from a tesla bolt.
+#define SHOCK_TESLA (1 << 1)
+// /Used when an illusion shocks something. Makes the shock deal stamina damage and not trigger certain secondary effects.
+#define SHOCK_ILLUSION (1 << 2)
+// /The shock doesn't stun.
+#define SHOCK_NOSTUN (1 << 3)
-#define INCORPOREAL_MOVE_BASIC 1
-#define INCORPOREAL_MOVE_SHADOW 2 // leaves a trail of shadows
-#define INCORPOREAL_MOVE_JAUNT 3 // is blocked by holy water/salt
+#define INCORPOREAL_MOVE_BASIC 1
+#define INCORPOREAL_MOVE_SHADOW 2 // leaves a trail of shadows
+#define INCORPOREAL_MOVE_JAUNT 3 // is blocked by holy water/salt
-//Secbot and ED209 judgement criteria bitflag values
+// Secbot and ED209 judgement criteria bitflag values
#define JUDGE_EMAGGED (1<<0)
#define JUDGE_IDCHECK (1<<1)
#define JUDGE_WEAPONCHECK (1<<2)
#define JUDGE_RECORDCHECK (1<<3)
-//ED209's ignore monkeys
+// ED209's ignore monkeys
#define JUDGE_IGNOREMONKEYS (1<<4)
#define MEGAFAUNA_DEFAULT_RECOVERY_TIME 5
@@ -262,45 +262,45 @@
// Offsets defines
-#define OFFSET_UNIFORM "uniform"
-#define OFFSET_ID "id"
-#define OFFSET_GLOVES "gloves"
-#define OFFSET_GLASSES "glasses"
-#define OFFSET_EARS "ears"
-#define OFFSET_SHOES "shoes"
-#define OFFSET_S_STORE "s_store"
-#define OFFSET_FACEMASK "mask"
-#define OFFSET_HEAD "head"
-#define OFFSET_EYES "eyes"
-#define OFFSET_LIPS "lips"
-#define OFFSET_BELT "belt"
-#define OFFSET_BACK "back"
-#define OFFSET_SUIT "suit"
-#define OFFSET_NECK "neck"
-#define OFFSET_HAIR "hair"
-#define OFFSET_FHAIR "fhair"
-#define OFFSET_MUTPARTS "mutantparts"
+#define OFFSET_UNIFORM "uniform"
+#define OFFSET_ID "id"
+#define OFFSET_GLOVES "gloves"
+#define OFFSET_GLASSES "glasses"
+#define OFFSET_EARS "ears"
+#define OFFSET_SHOES "shoes"
+#define OFFSET_S_STORE "s_store"
+#define OFFSET_FACEMASK "mask"
+#define OFFSET_HEAD "head"
+#define OFFSET_EYES "eyes"
+#define OFFSET_LIPS "lips"
+#define OFFSET_BELT "belt"
+#define OFFSET_BACK "back"
+#define OFFSET_SUIT "suit"
+#define OFFSET_NECK "neck"
+#define OFFSET_HAIR "hair"
+#define OFFSET_FHAIR "fhair"
+#define OFFSET_MUTPARTS "mutantparts"
-//MINOR TWEAKS/MISC
-#define AGE_MIN 18 //youngest a character can be //CITADEL EDIT - 17 --> 18
-#define AGE_MAX 85 //oldest a character can be
-#define WIZARD_AGE_MIN 30 //youngest a wizard can be
-#define APPRENTICE_AGE_MIN 29 //youngest an apprentice can be
-#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
-#define SHOES_SPEED_SLIGHT SHOES_SLOWDOWN - 1 // slightest speed boost to movement
-#define POCKET_STRIP_DELAY 40 //time taken (in deciseconds) to search somebody's pockets
-#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
+// MINOR TWEAKS/MISC
+#define AGE_MIN 18 // youngest a character can be // CITADEL EDIT - 17 --> 18
+#define AGE_MAX 85 // oldest a character can be
+#define WIZARD_AGE_MIN 30 // youngest a wizard can be
+#define APPRENTICE_AGE_MIN 29 // youngest an apprentice can be
+#define SHOES_SLOWDOWN 0 // How much shoes slow you down by default. Negative values speed you up
+#define SHOES_SPEED_SLIGHT SHOES_SLOWDOWN - 1 // slightest speed boost to movement
+#define POCKET_STRIP_DELAY 40 // time taken (in deciseconds) to search somebody's pockets
+#define DOOR_CRUSH_DAMAGE 15 // the amount of damage that airlocks deal when they crush you
-#define HUNGER_FACTOR 0.1 //factor at which mob nutrition decreases
-#define ETHEREAL_CHARGE_FACTOR 0.08 //factor at which ethereal's charge decreases
-#define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default.
+#define HUNGER_FACTOR 0.1 // factor at which mob nutrition decreases
+#define ETHEREAL_CHARGE_FACTOR 0.08 // factor at which ethereal's charge decreases
+#define REAGENTS_METABOLISM 0.4 // How many units of reagent are consumed per tick, by default.
#define REAGENTS_EFFECT_MULTIPLIER (REAGENTS_METABOLISM / 0.4) // By defining the effect multiplier this way, it'll exactly adjust all effects according to how they originally were with the 0.4 metabolism
// Roundstart trait system
-#define MAX_QUIRKS 6 //The maximum amount of quirks one character can have at roundstart
+#define MAX_QUIRKS 6 // The maximum amount of quirks one character can have at roundstart
-#define MAX_REVIVE_FIRE_DAMAGE 180
+#define MAX_REVIVE_FIRE_DAMAGE 180
#define MAX_REVIVE_BRUTE_DAMAGE 180
// AI Toggles
@@ -308,28 +308,28 @@
#define AI_VOX // Comment out if you don't want VOX to be enabled and have players download the voice sounds.
// /obj/item/bodypart on_mob_life() retval flag
-#define BODYPART_LIFE_UPDATE_HEALTH (1<<0)
+#define BODYPART_LIFE_UPDATE_HEALTH (1<<0)
#define HUMAN_FIRE_STACK_ICON_NUM 3
#define TYPING_INDICATOR_TIMEOUT 20 MINUTES
-#define GRAB_PIXEL_SHIFT_PASSIVE 6
-#define GRAB_PIXEL_SHIFT_AGGRESSIVE 12
-#define GRAB_PIXEL_SHIFT_NECK 16
+#define GRAB_PIXEL_SHIFT_PASSIVE 6
+#define GRAB_PIXEL_SHIFT_AGGRESSIVE 12
+#define GRAB_PIXEL_SHIFT_NECK 16
#define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return;
#define INTERACTING_WITH(X, Y) (Y in X.do_afters)
-/// Field of vision defines.
+// / Field of vision defines.
#define FOV_90_DEGREES 90
#define FOV_180_DEGREES 180
#define FOV_270_DEGREES 270
-/// How far away you can be to make eye contact with someone while examining
+// / How far away you can be to make eye contact with someone while examining
#define EYE_CONTACT_RANGE 5
-/// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine()
+// / If you examine the same atom twice in this timeframe, we call examine_more() instead of examine()
#define EXAMINE_MORE_TIME 1 SECONDS
-#define SILENCE_RANGED_MESSAGE (1<<0)
+#define SILENCE_RANGED_MESSAGE (1<<0)
diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index 84eed5483a..aef77e7b57 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -40,6 +40,16 @@
#define PARALLAX_LOW 2
#define PARALLAX_DISABLE 3 //this option must be the highest number
+#define PIXEL_SCALING_AUTO 0
+#define PIXEL_SCALING_1X 1
+#define PIXEL_SCALING_1_2X 1.5
+#define PIXEL_SCALING_2X 2
+#define PIXEL_SCALING_3X 3
+
+#define SCALING_METHOD_NORMAL "normal"
+#define SCALING_METHOD_DISTORT "distort"
+#define SCALING_METHOD_BLUR "blur"
+
#define PARALLAX_DELAY_DEFAULT world.tick_lag
#define PARALLAX_DELAY_MED 1
#define PARALLAX_DELAY_LOW 2
diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm
index 80983b34be..a188bf8363 100644
--- a/code/__DEFINES/shuttles.dm
+++ b/code/__DEFINES/shuttles.dm
@@ -31,6 +31,11 @@
#define EARLY_LAUNCHED 2
#define ENDGAME_TRANSIT 3
+//positive value = cannot puchase
+#define SHUTTLEPURCHASE_PURCHASABLE 0 //station can buy a shuttle
+#define SHUTTLEPURCHASE_PURCHASED 1 //station has already bought a shuttle, so cannot
+#define SHUTTLEPURCHASE_FORCED 2 //station was given a new shuttle through events or other shenanigans
+
// Ripples, effects that signal a shuttle's arrival
#define SHUTTLE_RIPPLE_TIME 100
diff --git a/code/__DEFINES/skills/defines.dm b/code/__DEFINES/skills/defines.dm
index 47aaeeb1dc..a0b34895df 100644
--- a/code/__DEFINES/skills/defines.dm
+++ b/code/__DEFINES/skills/defines.dm
@@ -40,7 +40,6 @@
#define SKILL_TRAIN_ATTACK_OBJ "train_attack_obj"
#define SKILL_STAMINA_COST "stamina_cost" //Influences the stamina cost from weapon usage.
#define SKILL_THROW_STAM_COST "throw_stam_cost"
-#define SKILL_COMBAT_MODE "combat_mode" //The user must have combat mode on.
#define SKILL_SANITY "sanity" //Is the skill affected by (in)sanity.
#define SKILL_INTELLIGENCE "intelligence" //Is the skill affected by brain damage?
diff --git a/code/__DEFINES/species.dm b/code/__DEFINES/species.dm
new file mode 100644
index 0000000000..c6cc6a5037
--- /dev/null
+++ b/code/__DEFINES/species.dm
@@ -0,0 +1,50 @@
+
+// Species ID Defines ---------------------------
+
+#define SPECIES_ABDUCTOR "abductor"
+#define SPECIES_ANDROID "android"
+#define SPECIES_ANGEL "angel"
+#define SPECIES_MAMMAL "mammal"
+#define SPECIES_INSECT "insect"
+#define SPECIES_DULLAHAN "dullahan"
+#define SPECIES_DWARF "dwarf"
+#define SPECIES_ETHEREAL "ethereal"
+#define SPECIES_FELINID "felinid"
+#define SPECIES_FLY "fly"
+#define SPECIES_GOLEM "golem"
+#define SPECIES_HUMAN "human"
+#define SPECIES_IPC "ipc"
+#define SPECIES_JELLY "jelly"
+ #define SPECIES_SLIME "slime"
+ #define SPECIES_SLIME_HYBRID "slimeperson"
+ #define SPECIES_SLIME_LUMI "slimelumi"
+ #define SPECIES_STARGAZER "stargazer"
+#define SPECIES_LIZARD "lizard"
+ #define SPECIES_ASHWALKER "ashlizard"
+#define SPECIES_MUSHROOM "mush"
+#define SPECIES_PLASMAMAN "plasmaman"
+#define SPECIES_POD "pod"
+ #define SPECIES_POD_WEAK "podweak"
+#define SPECIES_SHADOW "shadow"
+ #define SPECIES_NIGHTMARE "nightmare"
+#define SPECIES_SKELETON "skeleton"
+ #define SPECIES_SKELETON_SPACE "spaceskeleton"
+#define SPECIES_SYNTH_LIZARD "synthliz"
+#define SPECIES_SYNTH "synth"
+ #define SPECIES_SYNTH_MIL "military_synth"
+#define SPECIES_VAMPIRE "vampire"
+#define SPECIES_XENOHYBRID "xeno"
+
+// Species Category Defines ---------------------
+
+#define SPECIES_CATEGORY_ALIEN "alien"
+#define SPECIES_CATEGORY_BASIC "human"
+#define SPECIES_CATEGORY_FURRY "furry" // Weird Category, but okay.
+#define SPECIES_CATEGORY_GOLEM "golem"
+#define SPECIES_CATEGORY_INSECT "insect"
+#define SPECIES_CATEGORY_PLANT "plant"
+#define SPECIES_CATEGORY_ROBOT "robotic"
+#define SPECIES_CATEGORY_JELLY "jelly"
+#define SPECIES_CATEGORY_SHADOW "shadow"
+#define SPECIES_CATEGORY_SKELETON "skeleton"
+#define SPECIES_CATEGORY_UNDEAD "undead"
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 9deddd4b46..b405db83b0 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -124,6 +124,7 @@
#define FIRE_PRIORITY_ATMOS_ADJACENCY 300
#define FIRE_PRIORITY_STATPANEL 390
#define FIRE_PRIORITY_CHAT 400
+#define FIRE_PRIORITY_RUNECHAT 410
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index f054f163b5..520f205381 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -164,6 +164,7 @@
#define TRAIT_NO_MIDROUND_ANTAG "no-midround-antag" //can't be turned into an antag by random events
#define TRAIT_PUGILIST "pugilist" //This guy punches people for a living
#define TRAIT_KI_VAMPIRE "ki-vampire" //when someone with this trait rolls maximum damage on a punch and stuns the target, they regain some stamina and do clone damage
+#define TRAIT_MAULER "mauler" // this guy punches the shit out of people to hurt them, not to drain their stamina
#define TRAIT_PASSTABLE "passtable"
#define TRAIT_GIANT "giant"
#define TRAIT_DWARF "dwarf"
@@ -207,6 +208,10 @@
#define TRAIT_FAST_PUMP "fast_pump"
#define TRAIT_NO_PROCESS_FOOD "no-process-food" // You don't get benefits from nutriment, nor nutrition from reagent consumables
#define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good...
+/// Prevents stamina buffer regeneration
+#define TRAIT_NO_STAMINA_BUFFER_REGENERATION "block_stamina_buffer_regen"
+/// Prevents stamina regeneration
+#define TRAIT_NO_STAMINA_REGENERATION "block_stamina_regen"
// mobility flag traits
// IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it)
@@ -219,6 +224,8 @@
#define TRAIT_MOBILITY_NOPICKUP "mobility_nopickup"
/// Disallow item use
#define TRAIT_MOBILITY_NOUSE "mobility_nouse"
+///Disallow resting/unresting
+#define TRAIT_MOBILITY_NOREST "mobility_norest"
#define TRAIT_SWIMMING "swimming" //only applied by /datum/element/swimming, for checking
@@ -311,6 +318,7 @@
#define CLOWNOP_TRAIT "clown-op"
#define MEGAFAUNA_TRAIT "megafauna"
#define DEATHSQUAD_TRAIT "deathsquad"
+#define SLIMEPUDDLE_TRAIT "slimepuddle"
/// This trait is added by the active directional block system.
#define ACTIVE_BLOCK_TRAIT "active_block"
/// This trait is added by the parry system.
diff --git a/code/__HELPERS/do_after.dm b/code/__HELPERS/do_after.dm
index 30d40f3867..c65cd80394 100644
--- a/code/__HELPERS/do_after.dm
+++ b/code/__HELPERS/do_after.dm
@@ -38,11 +38,11 @@
return FALSE
if((do_after_flags & DO_AFTER_REQUIRES_USER_ON_TURF) && !isturf(user.loc))
return FALSE
+ if(!(do_after_flags & DO_AFTER_NO_COEFFICIENT) && living_user)
+ delay *= living_user.cached_multiplicative_actions_slowdown
var/starttime = world.time
var/endtime = world.time + delay
var/obj/item/initially_held_item = mob_redirect?.get_active_held_item()
- if(!(do_after_flags & DO_AFTER_NO_COEFFICIENT) && living_user)
- delay *= living_user.do_after_coefficent()
var/atom/movable/AM_user = ismovable(user) && user
var/drifting = AM_user?.Process_Spacemove(NONE) && AM_user.inertia_dir
var/initial_dx = targetturf.x - userturf.x
@@ -245,7 +245,7 @@
if(holding)
holdingnull = 0 //Users hand started holding something, check to see if it's still holding that
- delay *= user.do_after_coefficent()
+ delay *= user.cached_multiplicative_actions_slowdown
var/datum/progressbar/progbar
if (progress)
@@ -300,10 +300,6 @@
LAZYREMOVE(user.do_afters, target)
LAZYREMOVE(target.targeted_by, user)
-/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1
- . = 1
- return
-
/proc/do_after_mob(mob/user, var/list/targets, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks)
if(!user || !targets)
return 0
@@ -326,6 +322,8 @@
if(progress)
progbar = new(user, time, targets[1])
+ time *= user.cached_multiplicative_actions_slowdown
+
var/endtime = world.time + time
var/starttime = world.time
. = 1
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index 4723577fad..90864cf359 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -1186,6 +1186,8 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
SSassets.transport.register_asset(key, I)
for (var/thing2 in targets)
SSassets.transport.send_assets(thing2, key)
+ if(sourceonly)
+ return SSassets.transport.get_asset_url(key)
return "
- Reverse Drop-off Location:
- {data.dropoff_turf ? data.dropoff_turf : 'None'}
-
- [Enable Reverse Mode for this feature]
- "+e+""
diff --git a/code/__HELPERS/radiation.dm b/code/__HELPERS/radiation.dm
index 1570eededb..d527d0ac51 100644
--- a/code/__HELPERS/radiation.dm
+++ b/code/__HELPERS/radiation.dm
@@ -12,15 +12,17 @@
))
var/list/processing_list = list(location)
. = list()
- while(processing_list.len)
- var/atom/thing = processing_list[1]
- processing_list -= thing
+ var/i = 0
+ var/lim = 1
+ while(i < lim)
+ var/atom/thing = processing_list[++i]
if(ignored_things[thing.type])
continue
. += thing
if((thing.rad_flags & RAD_PROTECT_CONTENTS) || (SEND_SIGNAL(thing, COMSIG_ATOM_RAD_PROBE) & COMPONENT_BLOCK_RADIATION))
continue
processing_list += thing.contents
+ lim = processing_list.len
/proc/radiation_pulse(atom/source, intensity, range_modifier, log=FALSE, can_contaminate=TRUE)
if(!SSradiation.can_fire)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 92bd726641..794a495ae3 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -457,21 +457,23 @@ Turf and target are separate in case you want to teleport some distance from a t
/atom/proc/GetAllContents(var/T)
var/list/processing_list = list(src)
+ var/i = 0
+ var/lim = 1
if(T)
. = list()
- var/i = 0
- while(i < length(processing_list))
+ while(i < lim)
var/atom/A = processing_list[++i]
//Byond does not allow things to be in multiple contents, or double parent-child hierarchies, so only += is needed
//This is also why we don't need to check against assembled as we go along
processing_list += A.contents
+ lim = processing_list.len
if(istype(A,T))
. += A
else
- var/i = 0
- while(i < length(processing_list))
+ while(i < lim)
var/atom/A = processing_list[++i]
processing_list += A.contents
+ lim = processing_list.len
return processing_list
/atom/proc/GetAllContentsIgnoring(list/ignore_typecache)
@@ -480,10 +482,12 @@ Turf and target are separate in case you want to teleport some distance from a t
var/list/processing = list(src)
. = list()
var/i = 0
- while(i < length(processing))
+ var/lim = 1
+ while(i < lim)
var/atom/A = processing[++i]
if(!ignore_typecache[A.type])
processing += A.contents
+ lim = processing.len
. += A
diff --git a/code/__HELPERS/view.dm b/code/__HELPERS/view.dm
index 48e68be20f..1c92971802 100644
--- a/code/__HELPERS/view.dm
+++ b/code/__HELPERS/view.dm
@@ -2,7 +2,7 @@
var/viewX
var/viewY
if(isnum(view))
- var/totalviewrange = 1 + 2 * view
+ var/totalviewrange = (view < 0 ? -1 : 1) + 2 * view
viewX = totalviewrange
viewY = totalviewrange
else
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 85f5e4fd9b..b558b28cf2 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -252,7 +252,6 @@ GLOBAL_LIST_INIT(bitfields, list(
"COMBAT_FLAG_SPRINT_ACTIVE" = COMBAT_FLAG_SPRINT_ACTIVE,
"COMBAT_FLAG_ATTEMPTING_CRAWL" = COMBAT_FLAG_ATTEMPTING_CRAWL,
"COMBAT_FLAG_HARD_STAMCRIT" = COMBAT_FLAG_HARD_STAMCRIT,
- "COMBAT_FLAG_SOFT_STAMCRIT" = COMBAT_FLAG_SOFT_STAMCRIT,
"COMBAT_FLAG_INTENTIONALLY_RESTING" = COMBAT_FLAG_INTENTIONALLY_RESTING,
"COMBAT_FLAG_RESISTING_REST" = COMBAT_FLAG_RESISTING_REST,
"COMBAT_FLAG_SPRINT_FORCED" = COMBAT_FLAG_SPRINT_FORCED
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index 717a0b1dbf..0444e42e91 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -273,20 +273,62 @@ 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(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))
+//SPECIES BODYPART LISTS
//locked parts are those that your picked species requires to have
//unlocked parts are those that anyone can choose on customisation regardless
//parts not in unlocked, but in all, are thus locked
GLOBAL_LIST_INIT(all_mutant_parts, list("tail_lizard" = "Tail", "mam_tail" = "Tail", "tail_human" = "Tail", "snout" = "Snout", "frills" = "Frills", "spines" = "Spines", "body_markings" = "Body Markings", "mam_body_markings" = "Species Markings" , "mam_ears" = "Ears", "ears" = "Ears", "mam_snouts" = "Snout", "legs" = "Legs", "deco_wings" = "Decorative Wings", "insect_wings" = "Insect Wings", "insect_fluff" = "Insect Fluff", "taur" = "Tauric Body", "insect_markings" = "Insect Markings", "wings" = "Wings", "arachnid_legs" = "Arachnid Legs", "arachnid_spinneret" = "Spinneret", "arachnid_mandibles" = "Mandibles", "xenohead" = "Caste Head", "xenotail" = "Tail", "xenodorsal" = "Dorsal Spines", "ipc_screen" = "Screen", "ipc_antenna" = "Antenna", "meat_type" = "Meat Type", "horns" = "Horns"))
GLOBAL_LIST_INIT(unlocked_mutant_parts, list("horns", "insect_fluff"))
+
//parts in either of the above two lists that require a second option that allows them to be coloured
GLOBAL_LIST_INIT(colored_mutant_parts, list("insect_wings" = "wings_color", "deco_wings" = "wings_color", "horns" = "horns_color"))
//body ids that have greyscale sprites
-GLOBAL_LIST_INIT(greyscale_limb_types, list("human","moth","lizard","pod","plant","jelly","slime","golem","lum","stargazer","mush","ethereal","snail","c_golem","b_golem","mammal","xeno","ipc","insect","synthliz","avian","aquatic"))
+GLOBAL_LIST_INIT(greyscale_limb_types, list("human","moth","lizard","pod","plant","jelly","slime","golem","slimelumi","stargazer","mush","ethereal","snail","c_golem","b_golem","mammal","xeno","ipc","insect","synthliz","avian","aquatic"))
//body ids that have prosthetic sprites
GLOBAL_LIST_INIT(prosthetic_limb_types, list("xion","bishop","cybersolutions","grayson","hephaestus","nanotrasen","talon"))
+
+//FAMILY HEIRLOOM LIST
+//this works by using the first number for the species as a probability to choose one of the items in the following list for their family heirloom
+//if the probability fails, or the species simply isn't in the list, then it defaults to the next global list, which has its own list of items for each job
+//the first item in the list is for if your job isn't in that list
+
+//species-heirloom list (we categorise them by the species id var)
+GLOBAL_LIST_INIT(species_heirlooms, list(
+ "dwarf" = list(25, list(/obj/item/reagent_containers/food/drinks/dwarf_mug)), //example: 25% chance for dwarves to get a dwarf mug as their heirloom (normal container but has manly dorf icon)
+ "insect" = list(25, list(/obj/item/flashlight/lantern/heirloom_moth)),
+ "ipc" = list(25, list(/obj/item/stock_parts/cell/family)), //gives a broken powercell for flavor text!
+ "synthliz" = list(25, list(/obj/item/stock_parts/cell/family)), //they're also robots
+ "slimeperson" = list(25, list(/obj/item/toy/plush/slimeplushie)),
+ "lizard" = list(25, list(/obj/item/toy/plush/lizardplushie)),
+ ))
+
+//job-heirloom list
+GLOBAL_LIST_INIT(job_heirlooms, list(
+ "NO_JOB" = list(/obj/item/toy/cards/deck, /obj/item/lighter, /obj/item/dice/d20),
+ "Clown" = list(/obj/item/paint/anycolor, /obj/item/bikehorn/golden),
+ "Mime" = list(/obj/item/paint/anycolor, /obj/item/toy/dummy),
+ "Cook" = list(/obj/item/kitchen/knife/scimitar),
+ "Botanist" = list(/obj/item/cultivator, /obj/item/reagent_containers/glass/bucket, /obj/item/storage/bag/plants, /obj/item/toy/plush/beeplushie),
+ "Medical Doctor" = list(/obj/item/healthanalyzer),
+ "Paramedic" = list(/obj/item/lighter), //..why?
+ "Station Engineer" = list(/obj/item/wirecutters/brass/family, /obj/item/crowbar/brass/family, /obj/item/screwdriver/brass/family, /obj/item/wrench/brass/family), //brass tools but without the tool speed modifier
+ "Atmospheric Technician" = list(/obj/item/extinguisher/mini/family),
+ "Lawyer" = list(/obj/item/storage/briefcase/lawyer/family),
+ "Janitor" = list(/obj/item/mop),
+ "Scientist" = list(/obj/item/toy/plush/slimeplushie),
+ "Assistant" = list(/obj/item/clothing/gloves/cut/family),
+ "Chaplain" = list(/obj/item/camera/spooky/family),
+ "Head of Personnel" = list(/obj/item/pinpointer/ian)
+ ))
+
+//body ids that have non-gendered bodyparts
+GLOBAL_LIST_INIT(nongendered_limb_types, list("fly", "zombie" ,"synth", "shadow", "cultgolem", "agent", "plasmaman", "clockgolem", "clothgolem"))
+
+//list of eye types, corresponding to a respective left and right icon state for the set of eyes
+GLOBAL_LIST_INIT(eye_types, list("normal", "insect", "moth", "double", "double2", "double3", "cyclops"))
diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index 134f9d9cbe..64bac1f9af 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -40,6 +40,7 @@ GLOBAL_LIST_EMPTY(sentient_disease_instances)
GLOBAL_LIST_EMPTY(latejoin_ai_cores)
GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup)
+GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup_floating)
GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traitor-target purposes.
@@ -47,14 +48,22 @@ GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traito
// NOTE: This is entirely based on the fact that byond typesof/subtypesof gets longer/deeper paths before shallower ones.
// If that ever breaks this entire proc breaks.
var/list/mob_types = typesof(/mob)
- var/list/entry_value = CONFIG_GET(keyed_list/multiplicative_movespeed)
+ var/list/mob_types_floating = typesof(/mob)
+ var/list/entry_value = CONFIG_GET(keyed_list/multiplicative_movespeed/normal)
+ var/list/entry_value_floating = CONFIG_GET(keyed_list/multiplicative_movespeed/floating)
var/list/configured_types = list()
+ var/list/configured_types_floating = list()
for(var/path in entry_value)
var/value = entry_value[path]
if(isnull(value))
continue
// associative list sets for elements that already exist preserve order
mob_types[path] = value
+ for(var/path in entry_value_floating)
+ var/value = entry_value_floating[path]
+ if(isnull(value))
+ continue
+ mob_types_floating[path] = value
// now go back up through it to set everything, making absolute sure that base paths are overridden by child paths all the way down the path tree.
for(var/i in length(mob_types) to 1 step -1)
var/path = mob_types[i]
@@ -63,7 +72,14 @@ GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traito
// we're going from bottom to top so it should be safe to do this without further checks..
for(var/subpath in typesof(path))
configured_types[subpath] = mob_types[path]
+ for(var/i in length(mob_types_floating) to 1 step -1)
+ var/path = mob_types_floating[i]
+ if(isnull(mob_types_floating[path]))
+ continue
+ for(var/subpath in typesof(path))
+ configured_types_floating[subpath] = mob_types_floating[path]
GLOB.mob_config_movespeed_type_lookup = configured_types
+ GLOB.mob_config_movespeed_type_lookup_floating = configured_types_floating
if(update_mobs)
update_mob_config_movespeeds()
diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm
index 706a5ed955..9abc37c7e4 100644
--- a/code/_globalvars/lists/objects.dm
+++ b/code/_globalvars/lists/objects.dm
@@ -43,5 +43,4 @@ GLOBAL_LIST_EMPTY(ai_status_displays)
GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert
-//list of everyone playing rock paper scissors
-GLOBAL_LIST_EMPTY(rockpaperscissors_players)
+GLOBAL_LIST_EMPTY(rockpaperscissors_players) // List of everyone playing rock paper scissors
diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm
index 777ebb0718..2ecfe80ab5 100644
--- a/code/_onclick/hud/map_popups.dm
+++ b/code/_onclick/hud/map_popups.dm
@@ -1,30 +1,11 @@
-/client
- /**
- * Assoc list with all the active maps - when a screen obj is added to
- * a map, it's put in here as well.
- *
- * Format: list(
Your stamina buffer can take [L.stambuffer] stamina loss, and recharges at no cost.
Your stamina buffer is [(L.stambuffer*(100/L.stambuffer))-(L.bufferedstam*(100/L.stambuffer))]% full.")
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max)
+ to_chat(L, "You have [L.getStaminaLoss()] stamina loss.
\
+
Your stamina buffer is [round((L.stamina_buffer / buffer_max) * 100, 0.1)]% full.")
/obj/screen/staminas/update_icon_state()
var/mob/living/carbon/user = hud?.mymob
@@ -24,6 +26,19 @@
else
icon_state = "stamina[clamp(FLOOR(user.getStaminaLoss() /20, 1), 0, 6)]"
+/obj/screen/staminas/update_overlays()
+ . = ..()
+ var/mob/living/carbon/user = hud?.mymob
+ if(!user)
+ return
+ var/percent = user.getStaminaLoss() / STAMINA_CRIT
+ if((user.stat == DEAD) || (user.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (user.hal_screwyhud in 1 to 2))
+ . += list("stamina_alert3")
+ else if(percent >= 0.85)
+ . += list("stamina_alert2")
+ else if(percent >= 0.7)
+ . += list("stamina_alert1")
+
//stam buffer
/obj/screen/staminabuffer
icon = 'modular_citadel/icons/ui/screen_gen.dmi'
@@ -33,29 +48,33 @@
layer = ABOVE_HUD_LAYER + 0.1
mouse_opacity = 0
-/obj/screen/staminabuffer/update_icon_state()
+/obj/screen/staminabuffer/proc/mark_dirty()
+ if(update_to_mob())
+ START_PROCESSING(SShuds, src)
+
+/obj/screen/staminabuffer/process()
+ if(!update_to_mob())
+ return PROCESS_KILL
+
+/obj/screen/staminabuffer/Destroy()
+ STOP_PROCESSING(SShuds, src)
+ return ..()
+
+/obj/screen/staminabuffer/proc/update_to_mob()
var/mob/living/carbon/user = hud?.mymob
- if(!user)
- return
+ user.UpdateStaminaBuffer(FALSE)
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max)
+ if(!user?.client)
+ return FALSE
if(user.stat == DEAD || (user.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (user.hal_screwyhud in 1 to 2))
- icon_state = "stambuffer7"
- else if(user.hal_screwyhud == 5)
icon_state = "stambuffer0"
+ return FALSE
+ else if(user.hal_screwyhud == 5)
+ icon_state = "stambuffer29"
+ return FALSE
+ else if(user.stamina_buffer >= buffer_max)
+ icon_state = "stambuffer29"
+ return FALSE
else
- switch(user.bufferedstam / user.stambuffer)
- if(0.95 to INFINITY)
- icon_state = "stambuffer7"
- if(0.9 to 0.95)
- icon_state = "stambuffer6"
- if(0.8 to 0.9)
- icon_state = "stambuffer5"
- if(0.6 to 0.8)
- icon_state = "stambuffer4"
- if(0.4 to 0.6)
- icon_state = "stambuffer3"
- if(0.2 to 0.4)
- icon_state = "stambuffer2"
- if(0.05 to 0.2)
- icon_state = "stambuffer1"
- else
- icon_state = "stambuffer0"
+ icon_state = "stambuffer[FLOOR((user.stamina_buffer / buffer_max) * 29, 1)]"
+ return TRUE
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 9e88476513..cd1ee56848 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -85,6 +85,9 @@
if(force && damtype != STAMINA && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "You don't want to harm other living beings!")
return
+
+ if(!UseStaminaBufferStandard(user, STAM_COST_ATTACK_MOB_MULT, null, TRUE))
+ return DISCARD_LAST_ACTION
if(!force)
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
@@ -100,10 +103,6 @@
log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
add_fingerprint(user)
- var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) //CIT CHANGE - makes attacking things cause stamina loss
- if(weight)
- user.adjustStaminaLossBuffered(weight)
-
// CIT SCREENSHAKE
if(force >= 15)
shake_camera(user, ((force - 10) * 0.01 + 1), ((force - 10) * 0.01))
@@ -120,31 +119,21 @@
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ)
return
if(item_flags & NOBLUDGEON)
- return
+ return DISCARD_LAST_ACTION
+ if(!UseStaminaBufferStandard(user, STAM_COST_ATTACK_OBJ_MULT, warn = TRUE))
+ return DISCARD_LAST_ACTION
user.do_attack_animation(O)
O.attacked_by(src, user)
- var/weight = getweight(user, STAM_COST_ATTACK_OBJ_MULT)
- if(weight)
- user.adjustStaminaLossBuffered(weight)//CIT CHANGE - makes attacking things cause stamina loss
/atom/movable/proc/attacked_by()
return
/obj/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
var/totitemdamage = I.force * damage_multiplier
- var/bad_trait
-
- var/stamloss = user.getStaminaLoss()
- if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
- var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
- totitemdamage *= 1 - penalty
-
- if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
if(I.used_skills && user.mind)
if(totitemdamage)
- totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait)
+ totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ)
for(var/skill in I.used_skills)
if(!(SKILL_TRAIN_ATTACK_OBJ in I.used_skills[skill]))
continue
@@ -187,28 +176,15 @@
if(!.)
return
- var/stamloss = user.getStaminaLoss()
var/stam_mobility_mult = 1
- if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
- var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
- stam_mobility_mult -= penalty
if(stam_mobility_mult > LYING_DAMAGE_PENALTY && !CHECK_MOBILITY(user, MOBILITY_STAND)) //damage penalty for fighting prone, doesn't stack with the above.
stam_mobility_mult = LYING_DAMAGE_PENALTY
. *= stam_mobility_mult
- var/bad_trait
- if(!(I.item_flags & NO_COMBAT_MODE_FORCE_MODIFIER))
- if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
- if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
- . *= 0.8
- else if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- . *= 1.2
-
if(!user.mind || !I.used_skills)
return
if(.)
- . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait)
+ . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB)
for(var/skill in I.used_skills)
if(!(SKILL_TRAIN_ATTACK_MOB in I.used_skills[skill]))
continue
@@ -263,21 +239,23 @@
. = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier
if(!user)
return
- var/bad_trait
- if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- . *= STAM_COST_NO_COMBAT_MULT
- bad_trait = SKILL_COMBAT_MODE
if(used_skills && user.mind)
- . = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, bad_trait, FALSE)
- var/total_health = user.getStaminaLoss()
- . = clamp(., 0, STAMINA_NEAR_CRIT - total_health)
+ . = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, null, FALSE)
+
+/**
+ * Uses the amount of stamina required for a standard hit
+ */
+/obj/item/proc/UseStaminaBufferStandard(mob/living/user, multiplier = 1, trait = SKILL_STAMINA_COST, warn = TRUE)
+ ASSERT(user)
+ var/cost = getweight(user, multiplier, trait)
+ return user.UseStaminaBuffer(cost, warn)
/// How long this staggers for. 0 and negatives supported.
/obj/item/proc/melee_stagger_duration(force_override)
if(!isnull(stagger_force))
return stagger_force
/// totally not an untested, arbitrary equation.
- return clamp((1.5 + (w_class/7.5)) * ((force_override || force) / 2), 0, 10 SECONDS)
+ return clamp((1.5 + (w_class/5)) * ((force_override || force) / 1.5), 0, 10 SECONDS)
/obj/item/proc/do_stagger_action(mob/living/target, mob/living/user, force_override)
if(!CHECK_BITFIELD(target.status_flags, CANSTAGGER))
diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm
index 28803f0979..3782d8be94 100644
--- a/code/controllers/admin.dm
+++ b/code/controllers/admin.dm
@@ -3,7 +3,9 @@
name = "Initializing..."
var/target
-/obj/effect/statclick/New(loc, text, target) //Don't port this to Initialize it's too critical
+INITIALIZE_IMMEDIATE(/obj/effect/statclick) //it's new, but rebranded.
+
+/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical
. = ..()
name = text
src.target = target
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 8f55293820..c91ac2e0d4 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -230,14 +230,6 @@
/datum/config_entry/keyed_list/multiplicative_movespeed
key_mode = KEY_MODE_TYPE
value_mode = VALUE_MODE_NUM
- config_entry_value = list( //DEFAULTS
- /mob/living/simple_animal = 1,
- /mob/living/silicon/pai = 1,
- /mob/living/carbon/alien/humanoid/sentinel = 0.25,
- /mob/living/carbon/alien/humanoid/drone = 0.5,
- /mob/living/carbon/alien/humanoid/royal/praetorian = 1,
- /mob/living/carbon/alien/humanoid/royal/queen = 3
- )
/datum/config_entry/keyed_list/multiplicative_movespeed/ValidateAndSet()
. = ..()
@@ -249,6 +241,24 @@
if(. && (var_name == NAMEOF(src, config_entry_value)))
update_config_movespeed_type_lookup(TRUE)
+/datum/config_entry/keyed_list/multiplicative_movespeed/normal
+ config_entry_value = list( //DEFAULTS
+ /mob/living/simple_animal = 1,
+ /mob/living/silicon/pai = 1,
+ /mob/living/carbon/alien/humanoid/sentinel = 0.25,
+ /mob/living/carbon/alien/humanoid/drone = 0.5,
+ /mob/living/carbon/alien/humanoid/royal/praetorian = 1,
+ /mob/living/carbon/alien/humanoid/royal/queen = 3
+ )
+
+/datum/config_entry/keyed_list/multiplicative_movespeed/floating
+ config_entry_value = list(
+ /mob/living = 0,
+ /mob/living/carbon/alien/humanoid = 0,
+ /mob/living/carbon/alien/humanoid/royal/praetorian = 0,
+ /mob/living/carbon/alien/humanoid/royal/queen = 2
+ )
+
/datum/config_entry/number/movedelay //Used for modifying movement speed for mobs.
abstract_type = /datum/config_entry/number/movedelay
integer = FALSE
@@ -280,6 +290,12 @@
/datum/config_entry/number/movedelay/sprint_speed_increase
config_entry_value = 1
+/datum/config_entry/number/movedelay/sprint_max_tiles_increase
+ config_entry_value = 5
+
+/datum/config_entry/number/movedelay/sprint_absolute_max_tiles
+ config_entry_value = 13
+
/datum/config_entry/number/movedelay/sprint_buffer_max
config_entry_value = 24
@@ -291,7 +307,7 @@
/////////////////////////////////////////////////Outdated move delay
/datum/config_entry/number/outdated_movedelay
- deprecated_by = /datum/config_entry/keyed_list/multiplicative_movespeed
+ deprecated_by = /datum/config_entry/keyed_list/multiplicative_movespeed/normal
abstract_type = /datum/config_entry/number/outdated_movedelay
var/movedelay_type
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index 273ac7fd3e..b3e00af458 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -468,6 +468,9 @@
/datum/config_entry/string/default_view
config_entry_value = "15x15"
+/datum/config_entry/string/default_view_square
+ config_entry_value = "15x15"
+
/datum/config_entry/flag/log_pictures
/datum/config_entry/flag/picture_logging_camera
diff --git a/code/controllers/configuration/entries/stamina_combat.dm b/code/controllers/configuration/entries/stamina_combat.dm
new file mode 100644
index 0000000000..65580899f1
--- /dev/null
+++ b/code/controllers/configuration/entries/stamina_combat.dm
@@ -0,0 +1,35 @@
+/datum/config_entry/number/stamina_combat
+ integer = FALSE
+ abstract_type = /datum/config_entry/number/stamina_combat
+
+/// Maximum stamina buffer
+/datum/config_entry/number/stamina_combat/buffer_max
+ config_entry_value = 25
+
+/// Seconds until percent_regeneration_out_of_combat kicks in
+/datum/config_entry/number/stamina_combat/out_of_combat_timer
+ config_entry_value = 15
+
+/// Base regeneration per second
+/datum/config_entry/number/stamina_combat/base_regeneration
+ config_entry_value = 0.5
+
+/// Combat mode regeneration per second
+/datum/config_entry/number/stamina_combat/combat_regeneration
+ config_entry_value = 5
+
+/// After out_of_combat_timer elapses, additionally regenerate this percent of total stamina per second. Unaffected by combat mode.
+/datum/config_entry/number/stamina_combat/percent_regeneration_out_of_combat
+ config_entry_value = 30
+
+/// Seconds after an action for which your regeneration is penalized
+/datum/config_entry/number/stamina_combat/post_action_penalty_delay
+ config_entry_value = 5
+
+/// Factor to multiply by for penalizing post-action-stamina-regen
+/datum/config_entry/number/stamina_combat/post_action_penalty_factor
+ config_entry_value = 0.25
+
+/// Factor to multiply by for stamina usage past buffer into health
+/datum/config_entry/number/stamina_combat/overdraw_penalty_factor
+ config_entry_value = 1.5
diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm
index 148822cdd1..22f047a297 100644
--- a/code/controllers/failsafe.dm
+++ b/code/controllers/failsafe.dm
@@ -1,4 +1,4 @@
- /**
+/**
* Failsafe
*
* Pretty much pokes the MC to make sure it's still alive.
@@ -31,7 +31,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
Initialize()
/datum/controller/failsafe/Initialize()
- set waitfor = 0
+ set waitfor = FALSE
Failsafe.Loop()
if(!QDELETED(src))
qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us
@@ -97,4 +97,4 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
/datum/controller/failsafe/stat_entry(msg)
msg = "Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])"
- return msg
+ return msg
\ No newline at end of file
diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm
index 6b5fb294ea..21f022acfd 100644
--- a/code/controllers/globals.dm
+++ b/code/controllers/globals.dm
@@ -20,8 +20,9 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
Initialize()
-/datum/controller/global_vars/Destroy()
- //fuck off kevinz
+/datum/controller/global_vars/Destroy(force)
+ // This is done to prevent an exploit where admins can get around protected vars
+ SHOULD_CALL_PARENT(FALSE)
return QDEL_HINT_IWILLGC
/datum/controller/global_vars/stat_entry(msg)
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index bb8ce951f5..e49da32557 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -97,9 +97,9 @@
return
//This is used so the mc knows when the subsystem sleeps. do not override.
-/datum/controller/subsystem/proc/ignite(resumed = 0)
+/datum/controller/subsystem/proc/ignite(resumed = FALSE)
SHOULD_NOT_OVERRIDE(TRUE)
- set waitfor = 0
+ set waitfor = FALSE
. = SS_SLEEPING
fire(resumed)
. = state
diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm
index 3243a8d8c8..6be5a4bdfa 100644
--- a/code/controllers/subsystem/dcs.dm
+++ b/code/controllers/subsystem/dcs.dm
@@ -1,6 +1,7 @@
PROCESSING_SUBSYSTEM_DEF(dcs)
name = "Datum Component System"
flags = SS_NO_INIT
+ wait = 1 SECONDS
var/list/elements_by_type = list()
diff --git a/code/controllers/subsystem/economy.dm b/code/controllers/subsystem/economy.dm
index 078d122aa6..47b00d1125 100644
--- a/code/controllers/subsystem/economy.dm
+++ b/code/controllers/subsystem/economy.dm
@@ -60,9 +60,9 @@ SUBSYSTEM_DEF(economy)
secmedsrv_payout() // Payout based on crew safety, health, and mood.
civ_payout() // Payout based on ??? Profit
car_payout() // Cargo's natural gain in the cash moneys.
- for(var/A in bank_accounts)
- var/datum/bank_account/B = A
- B.payday(1)
+ for(var/account in bank_accounts)
+ var/datum/bank_account/bank_account = account
+ bank_account.payday(1)
/datum/controller/subsystem/economy/proc/get_dep_account(dep_id)
diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm
index 2e4e728191..9bc8a631c1 100644
--- a/code/controllers/subsystem/events.dm
+++ b/code/controllers/subsystem/events.dm
@@ -100,7 +100,7 @@ SUBSYSTEM_DEF(events)
// REEEEEEEEE
/client/proc/forceEvent()
set name = "Trigger Event"
- set category = "Fun"
+ set category = "Admin.Events"
if(!holder ||!check_rights(R_FUN))
return
diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm
index 32936af9e9..bc3f6cf51b 100644
--- a/code/controllers/subsystem/input.dm
+++ b/code/controllers/subsystem/input.dm
@@ -64,10 +64,10 @@ SUBSYSTEM_DEF(input)
// Misc
macroset_classic_input["Tab"] = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_HOTKEYS] map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\""
macroset_classic_input["Escape"] = "\".winset \\\"input.text=\\\"\\\"\\\"\""
-
+
// FINALLY, WE CAN DO SOMETHING MORE NORMAL FOR THE SNOWFLAKE-BUT-LESS KEYSET.
-
- // HAHA - SIKE. Because of BYOND weirdness (tl;dr not specifically binding this way results in potentially duplicate chatboxes when
+
+ // HAHA - SIKE. Because of BYOND weirdness (tl;dr not specifically binding this way results in potentially duplicate chatboxes when
// conflicts occur with something like say indicator vs say), we're going to snowflake this anyways
var/list/hard_binds = list(
"O" = "ooc",
@@ -80,7 +80,7 @@ SUBSYSTEM_DEF(input)
for(var/key in hard_binds)
for(var/modifier in anti_collision_modifiers)
hard_bind_anti_collision["[modifier]+[key]"] = ".NONSENSICAL_VERB_THAT_DOES_NOTHING"
-
+
macroset_classic_hotkey = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
@@ -88,7 +88,7 @@ SUBSYSTEM_DEF(input)
"Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
)
-
+
macroset_classic_hotkey |= hard_binds
macroset_classic_hotkey |= hard_bind_anti_collision
@@ -100,7 +100,7 @@ SUBSYSTEM_DEF(input)
"Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
)
-
+
macroset_hotkey |= hard_binds
macroset_hotkey |= hard_bind_anti_collision
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 4f59992ace..0f936bdeff 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -55,9 +55,10 @@ SUBSYSTEM_DEF(job)
continue
if(!job.config_check())
continue
- if(!job.map_check()) //Even though we initialize before mapping, this is fine because the config is loaded at new
+ if(!job.map_check(SSmapping.config)) //Even though we initialize before mapping, this is fine because the config is loaded at new
testing("Removed [job.type] due to map config");
continue
+ job.process_map_overrides(SSmapping.config)
occupations += job
name_occupations[job.title] = job
type_occupations[J] = job
@@ -665,7 +666,7 @@ SUBSYSTEM_DEF(job)
message_admins(msg)
CRASH(msg)
-/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff, bypass_prereqs = FALSE)
+/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff, bypass_prereqs = FALSE, can_drop = TRUE)
var/mob/the_mob = N
if(!the_mob)
the_mob = M // cause this doesn't get assigned if player is a latejoiner
@@ -694,9 +695,15 @@ SUBSYSTEM_DEF(job)
var/mob/living/carbon/C = M
var/obj/item/storage/backpack/B = C.back
if(!B || !SEND_SIGNAL(B, COMSIG_TRY_STORAGE_INSERT, I, null, TRUE, TRUE)) // Otherwise, try to put it in the backpack, for carbons.
- I.forceMove(get_turf(C))
+ if(can_drop)
+ I.forceMove(get_turf(C))
+ else
+ qdel(I)
else if(!M.equip_to_slot_if_possible(I, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // Otherwise, try to put it in the backpack
- I.forceMove(get_turf(M)) // If everything fails, just put it on the floor under the mob.
+ if(can_drop)
+ I.forceMove(get_turf(M)) // If everything fails, just put it on the floor under the mob.
+ else
+ qdel(I)
/datum/controller/subsystem/job/proc/FreeRole(rank)
if(!rank)
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 617004646a..2ea3b29c91 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -447,7 +447,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
//Manual loading of away missions.
/client/proc/admin_away()
set name = "Load Away Mission / Virtual Reality"
- set category = "Fun"
+ set category = "Admin.Events"
if(!holder ||!check_rights(R_FUN))
return
diff --git a/code/controllers/subsystem/minimum_spawns.dm b/code/controllers/subsystem/minimum_spawns.dm
new file mode 100644
index 0000000000..caab2b1949
--- /dev/null
+++ b/code/controllers/subsystem/minimum_spawns.dm
@@ -0,0 +1,144 @@
+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
+ wait = 2
+ var/where_we_droppin_boys_iterations = 0
+ var/snaxi_snowflake_check = FALSE
+ var/list/active_spawns = list() // lavaland, snaxi, etc. primary spawn list
+ var/list/active_spawns_2 = list() // snaxi underground, etc. secondary spawn list
+ var/list/valid_mining_turfs = list() // lavaland/snaxi turfs
+ var/list/valid_mining_turfs_2 = list() // snaxi underground turfs
+
+GLOBAL_LIST_INIT(minimum_lavaland_spawns, list(
+ /obj/structure/spawner/lavaland,
+ /obj/structure/spawner/lavaland/goliath,
+ /obj/structure/spawner/lavaland/legion,
+ /mob/living/simple_animal/hostile/megafauna/dragon,
+ /mob/living/simple_animal/hostile/megafauna/colossus,
+ /mob/living/simple_animal/hostile/megafauna/bubblegum
+))
+
+GLOBAL_LIST_INIT(minimum_snow_surface_spawns, list(
+ /obj/structure/spawner/ice_moon,
+ /obj/structure/spawner/ice_moon/polarbear
+))
+GLOBAL_LIST_INIT(minimum_snow_under_spawns, list(
+ /obj/structure/spawner/ice_moon/demonic_portal,
+ /obj/structure/spawner/ice_moon/demonic_portal/ice_whelp,
+ /obj/structure/spawner/ice_moon/demonic_portal/snowlegion
+))
+
+// step 1: check for which list(s) to use - done
+// step 2: check for caves - done
+// step 3: check for mobs - done
+// step 4: start throwing shit down - done
+// step 5: snaxi support - done?
+
+/datum/controller/subsystem/min_spawns/Initialize(start_timeofday)
+ var/list/snaxi_zs_list = SSmapping.levels_by_trait(ZTRAIT_ICE_RUINS) // boy if these things arent mutually exclusive
+ var/list/lavaland_zs_list = SSmapping.levels_by_trait(ZTRAIT_LAVA_RUINS) // i'm gonna fuckin scream
+ if(snaxi_zs_list.len)
+ active_spawns = GLOB.minimum_snow_surface_spawns
+ active_spawns_2 = GLOB.minimum_snow_under_spawns
+ snaxi_snowflake_check = TRUE
+ else if(lavaland_zs_list.len) //todo: recognizing maps that aren't lavaland mining but are also not snaxi
+ active_spawns = GLOB.minimum_lavaland_spawns
+ else
+ return ..() // call it a day i guess
+ // borrowing this from auxbase code - see code\modules\mining\aux_base.dm
+ if(snaxi_snowflake_check)
+ for(var/z_level in SSmapping.levels_by_trait(ZTRAIT_ICE_RUINS))
+ for(var/turf/TT in Z_TURFS(z_level))
+ if(!isarea(TT.loc))
+ continue
+ var/area/A = TT.loc
+ if(!A.mob_spawn_allowed)
+ continue
+ if(!istype(TT, /turf/open/floor/plating/asteroid))
+ continue
+ if(typesof(/turf/open/lava) in orange(9, TT))
+ continue
+ valid_mining_turfs.Add(TT)
+ for(var/z_level in SSmapping.levels_by_trait(ZTRAIT_ICE_RUINS_UNDERGROUND))
+ for(var/turf/TT in Z_TURFS(z_level))
+ if(!isarea(TT.loc))
+ continue
+ var/area/A = TT.loc
+ if(!A.mob_spawn_allowed)
+ continue
+ if(!istype(TT, /turf/open/floor/plating/asteroid))
+ continue
+ if(typesof(/turf/open/lava) in orange(9, TT))
+ continue
+ 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))
+ if(!isarea(TT.loc))
+ continue
+ var/area/A = TT.loc
+ if(!A.mob_spawn_allowed)
+ continue
+ if(!istype(TT, /turf/open/floor/plating/asteroid))
+ continue
+ if(typesof(/turf/open/lava) in orange(9, TT))
+ continue
+ valid_mining_turfs.Add(TT)
+ if(!valid_mining_turfs.len)
+ return ..() // call it a day i guess
+ // if we're at this point we might as well fucking hit it
+ where_we_droppin_boys()
+ return ..()
+
+/datum/controller/subsystem/min_spawns/proc/where_we_droppin_boys()
+ while(active_spawns.len)
+ where_we_droppin_boys_iterations++
+ CHECK_TICK
+ if(where_we_droppin_boys_iterations >= 1250)
+ INIT_ANNOUNCE("Minimum Spawns subsystem stopped early on spawns list 1 - too many iterations!")
+ break
+ var/turf/RT = pick_n_take(valid_mining_turfs) //Pick a random mining Z-level turf
+ var/MS_tospawn = pick_n_take(active_spawns)
+ 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?
+ 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?
+ 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?
+ // man the overhead on this is gonna SUCK
+ new MS_tospawn(RT)
+ while(active_spawns_2.len)
+ where_we_droppin_boys_iterations++
+ CHECK_TICK
+ if(where_we_droppin_boys_iterations >= 1250)
+ INIT_ANNOUNCE("Minimum Spawns subsystem stopped early on active list 2 - too many iterations!")
+ break
+ var/turf/RT2 = pick_n_take(valid_mining_turfs_2) //Pick a random mining Z-level turf
+ var/MS2_tospawn = pick_n_take(active_spawns_2)
+ 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?
+ 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?
+ for(var/obj/structure/spawner/LT in urange(70,RT2)) //prevents tendril/mega clumps
+ if((istype(MS2_tospawn, /mob/living/simple_animal/hostile/megafauna)) && get_dist(RT2, LT) <= 70)
+ active_spawns_2.Add(MS2_tospawn)
+ continue //let's try not to dump megas too close to each other?
+ if((istype(MS2_tospawn, /obj/structure/spawner)) && get_dist(RT2, LT) <= 40)
+ active_spawns_2.Add(MS2_tospawn)
+ continue //let's at least /try/ to space these out?
+ // man the overhead on this is gonna SUCK
+ new MS2_tospawn(RT2)
+ if(!active_spawns.len && !active_spawns_2.len)
+ return // we're done here
diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm
index c67deaede1..c20820c092 100644
--- a/code/controllers/subsystem/npcpool.dm
+++ b/code/controllers/subsystem/npcpool.dm
@@ -5,6 +5,10 @@ SUBSYSTEM_DEF(npcpool)
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/currentrun = list()
+ /// catches sleeping
+ var/invoking = FALSE
+ /// Invoke start time
+ var/invoke_start = 0
/datum/controller/subsystem/npcpool/stat_entry(msg)
var/list/activelist = GLOB.simple_animals[AI_ON]
@@ -12,7 +16,6 @@ SUBSYSTEM_DEF(npcpool)
return ..()
/datum/controller/subsystem/npcpool/fire(resumed = FALSE)
-
if (!resumed)
var/list/activelist = GLOB.simple_animals[AI_ON]
src.currentrun = activelist.Copy()
@@ -24,12 +27,22 @@ SUBSYSTEM_DEF(npcpool)
var/mob/living/simple_animal/SA = currentrun[currentrun.len]
--currentrun.len
- if(!SA.ckey && !SA.mob_transforming)
- if(SA.stat != DEAD)
- SA.handle_automated_movement()
- if(SA.stat != DEAD)
- SA.handle_automated_action()
- if(SA.stat != DEAD)
- SA.handle_automated_speech()
+ invoking = TRUE
+ invoke_start = world.time
+ INVOKE_ASYNC(src, .proc/invoke_process, SA)
+ if(invoking)
+ stack_trace("WARNING: [SA] ([SA.type]) slept during NPCPool processing.")
+ invoking = FALSE
+
if (MC_TICK_CHECK)
return
+
+/datum/controller/subsystem/npcpool/proc/invoke_process(mob/living/simple_animal/SA)
+ if(!SA.ckey && !SA.mob_transforming)
+ if(SA.stat != DEAD)
+ SA.handle_automated_movement()
+ if(SA.stat != DEAD)
+ SA.handle_automated_action()
+ if(SA.stat != DEAD)
+ SA.handle_automated_speech()
+ invoking = FALSE
diff --git a/code/controllers/subsystem/runechat.dm b/code/controllers/subsystem/runechat.dm
new file mode 100644
index 0000000000..ec296e7d32
--- /dev/null
+++ b/code/controllers/subsystem/runechat.dm
@@ -0,0 +1,238 @@
+/// Controls how many buckets should be kept, each representing a tick. (30 seconds worth)
+#define BUCKET_LEN (world.fps * 1 * 30)
+/// Helper for getting the correct bucket for a given chatmessage
+#define BUCKET_POS(scheduled_destruction) (((round((scheduled_destruction - SSrunechat.head_offset) / world.tick_lag) + 1) % BUCKET_LEN) || BUCKET_LEN)
+/// Gets the maximum time at which messages will be handled in buckets, used for deferring to secondary queue
+#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.
+ */
+SUBSYSTEM_DEF(runechat)
+ name = "Runechat"
+ flags = SS_TICKER | SS_NO_INIT
+ wait = 1
+ priority = FIRE_PRIORITY_RUNECHAT
+
+ /// 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 first non-empty bucket
+ var/practical_offset = 1
+ /// world.tick_lag the bucket was designed for
+ var/bucket_resolution = 0
+ /// How many messages are in the buckets
+ var/bucket_count = 0
+ /// List of buckets, each bucket holds every message that has to be killed that byond tick
+ var/list/bucket_list = list()
+ /// Queue used for storing messages that are scheduled for deletion too far in the future for the buckets
+ var/list/datum/chatmessage/second_queue = list()
+
+/datum/controller/subsystem/runechat/PreInit()
+ bucket_list.len = BUCKET_LEN
+ head_offset = world.time
+ bucket_resolution = world.tick_lag
+
+/datum/controller/subsystem/runechat/stat_entry(msg)
+ msg = "ActMsgs:[bucket_count] SecQueue:[length(second_queue)]"
+ return msg
+
+/datum/controller/subsystem/runechat/fire(resumed = FALSE)
+ // Store local references to datum vars as it is faster to access them this way
+ var/list/bucket_list = src.bucket_list
+
+ if (MC_TICK_CHECK)
+ return
+
+
+ // 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
+ // Store a reference to the 'working' chatmessage so that we can resume if the MC
+ // has us stop mid-way through processing
+ var/static/datum/chatmessage/cm
+ if (!resumed)
+ cm = null
+
+ // 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/chatmessage/bucket_head = bucket_list[practical_offset]
+ if (!cm || !bucket_head || cm == bucket_head)
+ bucket_head = bucket_list[practical_offset]
+ cm = bucket_head
+
+ while (cm)
+ // If the chatmessage hasn't yet had its life ended then do that now
+ var/datum/chatmessage/next = cm.next
+ if (!cm.eol_complete)
+ cm.end_of_life()
+ else if (!QDELETED(cm)) // otherwise if we haven't deleted it yet, do so (this is after EOL completion)
+ qdel(cm)
+
+ if (MC_TICK_CHECK)
+ return
+
+ // Break once we've processed the entire bucket
+ cm = next
+ if (cm == bucket_head)
+ break
+
+ // 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))
+ cm = second_queue[i]
+ if (cm.scheduled_destruction >= BUCKET_LIMIT)
+ i--
+ break
+
+ // Transfer the message into the bucket, performing necessary circular doubly-linked list operations
+ bucket_count++
+ var/bucket_pos = max(1, BUCKET_POS(cm.scheduled_destruction))
+ var/datum/timedevent/head = bucket_list[bucket_pos]
+ if (!head)
+ bucket_list[bucket_pos] = cm
+ cm.next = null
+ cm.prev = null
+ continue
+
+ if (!head.prev)
+ head.prev = head
+ cm.next = head
+ cm.prev = head.prev
+ cm.next.prev = cm
+ cm.prev.next = cm
+ if (i)
+ second_queue.Cut(1, i + 1)
+ cm = null
+
+/datum/controller/subsystem/runechat/Recover()
+ bucket_list |= SSrunechat.bucket_list
+ second_queue |= SSrunechat.second_queue
+
+/datum/controller/subsystem/runechat/proc/reset_buckets()
+ bucket_list.len = BUCKET_LEN
+ head_offset = world.time
+ 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
+ */
+/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
+ var/list/second_queue = SSrunechat.second_queue
+
+ // When necessary, de-list the chatmessage from its previous position
+ if (new_sched_destruction)
+ if (scheduled_destruction >= BUCKET_LIMIT)
+ second_queue -= src
+ else
+ SSrunechat.bucket_count--
+ var/bucket_pos = BUCKET_POS(scheduled_destruction)
+ if (bucket_pos > 0)
+ var/datum/chatmessage/bucket_head = bucket_list[bucket_pos]
+ if (bucket_head == src)
+ bucket_list[bucket_pos] = next
+ if (prev != next)
+ prev.next = next
+ next.prev = prev
+ else
+ prev?.next = null
+ next?.prev = null
+ prev = next = null
+ scheduled_destruction = new_sched_destruction
+
+ // Ensure the scheduled destruction time is properly bound to avoid missing a scheduled event
+ scheduled_destruction = max(CEILING(scheduled_destruction, world.tick_lag), world.time + world.tick_lag)
+
+ // 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)
+ return
+
+ // Get bucket position and a local reference to the datum var, it's faster to access this way
+ var/bucket_pos = BUCKET_POS(scheduled_destruction)
+
+ // Get the bucket head for that bucket, increment the bucket count
+ var/datum/chatmessage/bucket_head = bucket_list[bucket_pos]
+ SSrunechat.bucket_count++
+
+ // If there is no existing head of this bucket, we can set this message to be that head
+ if (!bucket_head)
+ bucket_list[bucket_pos] = src
+ return
+
+ // Otherwise it's a simple insertion into the circularly doubly-linked list
+ if (!bucket_head.prev)
+ bucket_head.prev = bucket_head
+ next = bucket_head
+ prev = bucket_head.prev
+ next.prev = src
+ prev.next = src
+
+
+/**
+ * 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)
+
+ // Get local references to the subsystem's vars, faster than accessing on the datum
+ var/list/bucket_list = SSrunechat.bucket_list
+ var/list/second_queue = SSrunechat.second_queue
+
+ // Attempt to get the head of the bucket
+ var/datum/chatmessage/bucket_head
+ if (bucket_pos > 0)
+ bucket_head = bucket_list[bucket_pos]
+
+ // Decrement the number of messages in buckets if the message is
+ // the head of the bucket, or has a SD less than BUCKET_LIMIT implying it fits
+ // into an existing bucket, or is otherwise not present in the secondary queue
+ if(bucket_head == src)
+ bucket_list[bucket_pos] = next
+ SSrunechat.bucket_count--
+ else if(scheduled_destruction < BUCKET_LIMIT)
+ SSrunechat.bucket_count--
+ else
+ var/l = length(second_queue)
+ second_queue -= src
+ if(l == length(second_queue))
+ SSrunechat.bucket_count--
+
+ // Remove the message from the bucket, ensuring to maintain
+ // the integrity of the bucket's list if relevant
+ if(prev != next)
+ prev.next = next
+ next.prev = prev
+ else
+ prev?.next = null
+ next?.prev = null
+ prev = next = null
+
+#undef BUCKET_LEN
+#undef BUCKET_POS
+#undef BUCKET_LIMIT
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index c802448536..b74f1d46d3 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -47,7 +47,7 @@ SUBSYSTEM_DEF(shuttle)
var/datum/round_event/shuttle_loan/shuttle_loan
- var/shuttle_purchased = FALSE //If the station has purchased a replacement escape shuttle this round
+ var/shuttle_purchased = SHUTTLEPURCHASE_PURCHASABLE //If the station has purchased a replacement escape shuttle this round
var/list/shuttle_purchase_requirements_met = list() //For keeping track of ingame events that would unlock new shuttles, such as defeating a boss or discovering a secret item
var/lockdown = FALSE //disallow transit after nuke goes off
diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm
index cf7d4ba533..161fd92f77 100644
--- a/code/controllers/subsystem/statpanel.dm
+++ b/code/controllers/subsystem/statpanel.dm
@@ -27,28 +27,6 @@ SUBSYSTEM_DEF(statpanels)
var/ETA = SSshuttle.emergency.getModeStr()
if(ETA)
global_data += "[ETA] [SSshuttle.emergency.getTimerStr()]"
-/* Please fix
- if(SSvote.mode)
- var/static/list/supported = list(PLURALITY_VOTING, APPROVAL_VOTING)
- global_data += "Vote active!, There is currently a vote running. Question: [SSvote.question]"
- if(!(SSvote.vote_system in supported))
- global_data += "
"
- if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits))
- if(!use_skintones && !mutant_colors)
- dat += APPEARANCE_CATEGORY_COLUMN
- if(left_eye_color != right_eye_color)
- split_eye_colors = TRUE
- dat += "Heterochromia
"
- dat += "[split_eye_colors ? "Enabled" : "Disabled"]"
- if(!split_eye_colors)
- dat += "Eye Color
"
- dat += " Change"
+ if(!(NOEYES in pref_species.species_traits))
+ dat += "Eye Type
"
+ dat += "[eye_type]
"
+ if((EYECOLOR in pref_species.species_traits))
+ if(!use_skintones && !mutant_colors)
+ dat += APPEARANCE_CATEGORY_COLUMN
+ if(left_eye_color != right_eye_color)
+ split_eye_colors = TRUE
+ dat += "Heterochromia
"
+ dat += "[split_eye_colors ? "Enabled" : "Disabled"]"
+ if(!split_eye_colors)
+ dat += "Eye Color
"
+ dat += " Change"
+ dat += ""
+ else
+ dat += "Left Eye Color
"
+ dat += " Change"
+ dat += "Right Eye Color
"
+ dat += " Change
"
+ dat += ""
+ else if(use_skintones || mutant_colors)
dat += ""
- else
- dat += "Left Eye Color
"
- dat += " Change"
- dat += "Right Eye Color
"
- dat += " Change
"
- dat += ""
- else if(use_skintones || mutant_colors)
- dat += ""
dat += APPEARANCE_CATEGORY_COLUMN
dat += "Speech preferences
"
@@ -753,6 +764,20 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "HUD Button Flashes: [hud_toggle_flash ? "Enabled" : "Disabled"]
"
dat += "HUD Button Flash Color: Change
"
+/* CITADEL EDIT - We're using top menu instead
+ button_name = pixel_size
+ dat += "Pixel Scaling: [(button_name) ? "Pixel Perfect [button_name]x" : "Stretch to fit"]
"
+
+ switch(scaling_method)
+ if(SCALING_METHOD_NORMAL)
+ button_name = "Nearest Neighbor"
+ if(SCALING_METHOD_DISTORT)
+ button_name = "Point Sampling"
+ if(SCALING_METHOD_BLUR)
+ button_name = "Bilinear"
+ dat += "Scaling Method: [button_name]
"
+*/
+
if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation))
var/p_map = preferred_map
if (!p_map)
@@ -1587,6 +1612,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_eyes)
right_eye_color = sanitize_hexcolor(new_eyes, 6)
+ if("eye_type")
+ var/new_eye_type = input(user, "Choose your character's eye type.", "Character Preference") as null|anything in GLOB.eye_types
+ if(new_eye_type)
+ eye_type = new_eye_type
+
if("toggle_split_eyes")
split_eye_colors = !split_eye_colors
right_eye_color = left_eye_color
@@ -1620,6 +1650,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(features["mcolor3"] == "#000000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
features["mcolor3"] = pref_species.default_color
+ //switch to the type of eyes the species uses
+ eye_type = pref_species.eye_type
+
if("custom_species")
var/new_species = reject_bad_name(input(user, "Choose your species subtype, if unique. This will show up on examinations and health scans. Do not abuse this:", "Character Preference", custom_species) as null|text)
if(new_species)
@@ -1633,7 +1666,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(new_mutantcolor == "#000000")
features["mcolor"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright, but only if they affect the skin
features["mcolor"] = sanitize_hexcolor(new_mutantcolor, 6)
else
to_chat(user, "Invalid color. Your color is not bright enough.")
@@ -1644,7 +1677,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(new_mutantcolor == "#000000")
features["mcolor2"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright, but only if they affect the skin
features["mcolor2"] = sanitize_hexcolor(new_mutantcolor, 6)
else
to_chat(user, "Invalid color. Your color is not bright enough.")
@@ -1655,7 +1688,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(new_mutantcolor == "#000000")
features["mcolor3"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright, but only if they affect the skin
features["mcolor3"] = sanitize_hexcolor(new_mutantcolor, 6)
else
to_chat(user, "Invalid color. Your color is not bright enough.")
@@ -2008,7 +2041,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/temp_hsv = RGBtoHSV(new_cockcolor)
if(new_cockcolor == "#000000")
features["cock_color"] = pref_species.default_color
- else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3])
features["cock_color"] = sanitize_hexcolor(new_cockcolor, 6)
else
to_chat(user,"Invalid color. Your color is not bright enough.")
@@ -2048,7 +2081,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/temp_hsv = RGBtoHSV(new_ballscolor)
if(new_ballscolor == "#000000")
features["balls_color"] = pref_species.default_color
- else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3])
features["balls_color"] = sanitize_hexcolor(new_ballscolor, 6)
else
to_chat(user,"Invalid color. Your color is not bright enough.")
@@ -2075,7 +2108,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/temp_hsv = RGBtoHSV(new_breasts_color)
if(new_breasts_color == "#000000")
features["breasts_color"] = pref_species.default_color
- else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3])
features["breasts_color"] = sanitize_hexcolor(new_breasts_color, 6)
else
to_chat(user,"Invalid color. Your color is not bright enough.")
@@ -2097,7 +2130,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/temp_hsv = RGBtoHSV(new_vagcolor)
if(new_vagcolor == "#000000")
features["vag_color"] = pref_species.default_color
- else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3])
features["vag_color"] = sanitize_hexcolor(new_vagcolor, 6)
else
to_chat(user,"Invalid color. Your color is not bright enough.")
@@ -2267,7 +2300,32 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["has_womb"] = !features["has_womb"]
if("widescreenpref")
widescreenpref = !widescreenpref
- user.client.change_view(CONFIG_GET(string/default_view))
+ user.client.view_size.setDefault(getScreenSize(widescreenpref))
+
+ if("pixel_size")
+ switch(pixel_size)
+ if(PIXEL_SCALING_AUTO)
+ pixel_size = PIXEL_SCALING_1X
+ if(PIXEL_SCALING_1X)
+ pixel_size = PIXEL_SCALING_1_2X
+ if(PIXEL_SCALING_1_2X)
+ pixel_size = PIXEL_SCALING_2X
+ if(PIXEL_SCALING_2X)
+ pixel_size = PIXEL_SCALING_3X
+ if(PIXEL_SCALING_3X)
+ pixel_size = PIXEL_SCALING_AUTO
+ user.client.view_size.apply() //Let's winset() it so it actually works
+
+ if("scaling_method")
+ switch(scaling_method)
+ if(SCALING_METHOD_NORMAL)
+ scaling_method = SCALING_METHOD_DISTORT
+ if(SCALING_METHOD_DISTORT)
+ scaling_method = SCALING_METHOD_BLUR
+ if(SCALING_METHOD_BLUR)
+ scaling_method = SCALING_METHOD_NORMAL
+ user.client.view_size.setZoomMode()
+
if("autostand")
autostand = !autostand
if("auto_ooc")
@@ -2641,6 +2699,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.dna.features = features.Copy()
character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
+ character.dna.species.eye_type = eye_type
if(chosen_limb_id && (chosen_limb_id in character.dna.species.allowed_limb_ids))
character.dna.species.mutant_bodyparts["limbs_id"] = chosen_limb_id
character.dna.real_name = character.real_name
@@ -2679,9 +2738,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
//limb stuff, only done when initially spawning in
if(initial_spawn)
- //delete any existing prosthetic limbs to make sure no remnant prosthetics are left over
+ //delete any existing prosthetic limbs to make sure no remnant prosthetics are left over - But DO NOT delete those that are species-related
for(var/obj/item/bodypart/part in character.bodyparts)
- if(part.status == BODYPART_ROBOTIC)
+ if(part.status == BODYPART_ROBOTIC && !part.render_like_organic)
qdel(part)
character.regenerate_limbs() //regenerate limbs so now you only have normal limbs
for(var/modified_limb in modified_limbs)
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 9aa377bce6..3bad31a919 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
-#define SAVEFILE_VERSION_MAX 36
+#define SAVEFILE_VERSION_MAX 38
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -204,10 +204,28 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(S["species"] == "lizard")
features["mam_snouts"] = features["snout"]
- if(current_version < 36)
+ if(current_version < 36) //introduction of heterochromia
left_eye_color = S["eye_color"]
right_eye_color = S["eye_color"]
+ if(current_version < 37) //introduction of chooseable eye types/sprites
+ if(S["species"] == "insect")
+ left_eye_color = "#000000"
+ right_eye_color = "#000000"
+ if(chosen_limb_id == "moth" || chosen_limb_id == "moth_not_greyscale") //these actually have slightly different eyes!
+ eye_type = "moth"
+ else
+ eye_type = "insect"
+
+ if(current_version < 38) //further eye sprite changes
+ if(S["species"] == "plasmaman")
+ left_eye_color = "#FFC90E"
+ right_eye_color = "#FFC90E"
+ else
+ if(S["species"] == "skeleton")
+ left_eye_color = "#BAB99E"
+ right_eye_color = "#BAB99E"
+
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
return
@@ -271,6 +289,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["parallax"] >> parallax
S["ambientocclusion"] >> ambientocclusion
S["auto_fit_viewport"] >> auto_fit_viewport
+ S["widescreenpref"] >> widescreenpref
+ S["pixel_size"] >> pixel_size
+ S["scaling_method"] >> scaling_method
S["hud_toggle_flash"] >> hud_toggle_flash
S["hud_toggle_color"] >> hud_toggle_color
S["menuoptions"] >> menuoptions
@@ -288,7 +309,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["arousable"] >> arousable
S["screenshake"] >> screenshake
S["damagescreenshake"] >> damagescreenshake
- S["widescreenpref"] >> widescreenpref
S["autostand"] >> autostand
S["cit_toggles"] >> cit_toggles
S["preferred_chaos"] >> preferred_chaos
@@ -324,6 +344,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
parallax = sanitize_integer(parallax, PARALLAX_INSANE, PARALLAX_DISABLE, null)
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport))
+ widescreenpref = sanitize_integer(widescreenpref, 0, 1, initial(widescreenpref))
+ pixel_size = sanitize_integer(pixel_size, PIXEL_SCALING_AUTO, PIXEL_SCALING_3X, initial(pixel_size))
+ scaling_method = sanitize_text(scaling_method, initial(scaling_method))
hud_toggle_flash = sanitize_integer(hud_toggle_flash, 0, 1, initial(hud_toggle_flash))
hud_toggle_color = sanitize_hexcolor(hud_toggle_color, 6, 1, initial(hud_toggle_color))
ghost_form = sanitize_inlist(ghost_form, GLOB.ghost_forms, initial(ghost_form))
@@ -337,7 +360,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
pda_skin = sanitize_inlist(pda_skin, GLOB.pda_reskins, PDA_SKIN_ALT)
screenshake = sanitize_integer(screenshake, 0, 800, initial(screenshake))
damagescreenshake = sanitize_integer(damagescreenshake, 0, 2, initial(damagescreenshake))
- widescreenpref = sanitize_integer(widescreenpref, 0, 1, initial(widescreenpref))
autostand = sanitize_integer(autostand, 0, 1, initial(autostand))
cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles))
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
@@ -509,6 +531,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["age"] >> age
S["hair_color"] >> hair_color
S["facial_hair_color"] >> facial_hair_color
+ S["eye_type"] >> eye_type
S["left_eye_color"] >> left_eye_color
S["right_eye_color"] >> right_eye_color
S["use_custom_skin_tone"] >> use_custom_skin_tone
@@ -695,6 +718,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
hair_color = sanitize_hexcolor(hair_color, 6, FALSE)
facial_hair_color = sanitize_hexcolor(facial_hair_color, 6, FALSE)
+ eye_type = sanitize_inlist(eye_type, GLOB.eye_types, DEFAULT_EYES_TYPE)
left_eye_color = sanitize_hexcolor(left_eye_color, 6, FALSE)
right_eye_color = sanitize_hexcolor(right_eye_color, 6, FALSE)
@@ -828,6 +852,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["age"] , age)
WRITE_FILE(S["hair_color"] , hair_color)
WRITE_FILE(S["facial_hair_color"] , facial_hair_color)
+ WRITE_FILE(S["eye_type"] , eye_type)
WRITE_FILE(S["left_eye_color"] , left_eye_color)
WRITE_FILE(S["right_eye_color"] , right_eye_color)
WRITE_FILE(S["use_custom_skin_tone"] , use_custom_skin_tone)
diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm
index e16a491c61..a019ade471 100644
--- a/code/modules/client/preferences_toggles.dm
+++ b/code/modules/client/preferences_toggles.dm
@@ -386,7 +386,7 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
//Admin Preferences
/client/proc/toggleadminhelpsound()
set name = "Hear/Silence Adminhelps"
- set category = "Preferences"
+ set category = "Preferences.Admin"
set desc = "Toggle hearing a notification when admin PMs are received"
if(!holder)
return
@@ -397,7 +397,7 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
/client/proc/toggleannouncelogin()
set name = "Do/Don't Announce Login"
- set category = "Preferences"
+ set category = "Preferences.Admin"
set desc = "Toggle if you want an announcement to admins when you login during a round"
if(!holder)
return
@@ -408,7 +408,7 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
/client/proc/toggle_hear_radio()
set name = "Show/Hide Radio Chatter"
- set category = "Preferences"
+ set category = "Preferences.Admin"
set desc = "Toggle seeing radiochatter from nearby radios and speakers"
if(!holder)
return
@@ -419,7 +419,7 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
/client/proc/deadchat()
set name = "Show/Hide Deadchat"
- set category = "Preferences"
+ set category = "Preferences.Admin"
set desc ="Toggles seeing deadchat"
prefs.chat_toggles ^= CHAT_DEAD
prefs.save_preferences()
@@ -428,7 +428,7 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
/client/proc/toggleprayers()
set name = "Show/Hide Prayers"
- set category = "Preferences"
+ set category = "Preferences.Admin"
set desc = "Toggles seeing prayers"
prefs.chat_toggles ^= CHAT_PRAYER
prefs.save_preferences()
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index dd1ebd74f9..5a8325fd64 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -111,16 +111,16 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
/client/proc/set_ooc(newColor as color)
set name = "Set Player OOC Color"
set desc = "Modifies player OOC Color"
- set category = "Fun"
+ set category = "Admin.Fun"
GLOB.OOC_COLOR = sanitize_ooccolor(newColor)
/client/proc/reset_ooc()
set name = "Reset Player OOC Color"
set desc = "Returns player OOC Color to default"
- set category = "Fun"
+ set category = "Admin.Fun"
GLOB.OOC_COLOR = null
-/client/verb/colorooc()
+/client/verb/colorooc() //this is admin and people who bought byond.
set name = "Set Your OOC Color"
set category = "Preferences"
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 2fbe738acb..ea01b0c0ed 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -45,13 +45,12 @@
var/dynamic_fhair_suffix = ""//mask > head for facial hair
//basically a restriction list.
- var/list/species_restricted = null
+ var/list/species_restricted
//Basically syntax is species_restricted = list("Species Name","Species Name")
//Add a "exclude" string to do the opposite, making it only only species listed that can't wear it.
//You append this to clothing objects
-
// How much clothing damage has been dealt to each of the limbs of the clothing, assuming it covers more than one limb
var/list/damage_by_parts
// How much integrity is in a specific limb before that limb is disabled (for use in [/obj/item/clothing/proc/take_damage_zone], and only if we cover multiple zones.) Set to 0 to disable shredding.
@@ -477,7 +476,6 @@ BLIND // can't see anything
return TRUE
-
/// If we're a clothing with at least 1 shredded/disabled zone, give the wearer a periodic heads up letting them know their clothes are damaged
/obj/item/clothing/proc/bristle(mob/living/L)
if(!istype(L))
diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm
index b5d92fb780..f9f587ae5b 100644
--- a/code/modules/clothing/gloves/miscellaneous.dm
+++ b/code/modules/clothing/gloves/miscellaneous.dm
@@ -20,8 +20,14 @@
body_parts_covered = ARMS
cold_protection = ARMS
strip_delay = 300 //you can't just yank them off
+ /// did you ever get around to wearing these or no
+ var/wornonce = FALSE
///Extra damage through the punch.
var/enhancement = 0 //it's a +0 to your punches because it isn't magical
+ ///extra wound bonus through the punch (MAYBE DON'T BE GENEROUS WITH THIS)
+ var/wound_enhancement = 0
+ /// do we give the flavortext for wearing them
+ var/silent = FALSE
///Main trait added by the gloves to the user on wear.
var/inherited_trait = TRAIT_NOGUNS //what are you, dishonoroable?
///Secondary trait added by the gloves to the user on wear.
@@ -29,7 +35,18 @@
/obj/item/clothing/gloves/fingerless/pugilist/equipped(mob/user, slot)
. = ..()
- if(slot == SLOT_GLOVES)
+ if(current_equipped_slot == SLOT_GLOVES)
+ use_buffs(user, TRUE)
+ wornonce = TRUE
+
+/obj/item/clothing/gloves/fingerless/pugilist/dropped(mob/user)
+ . = ..()
+ if(wornonce)
+ use_buffs(user, FALSE)
+ wornonce = FALSE
+
+/obj/item/clothing/gloves/fingerless/pugilist/proc/use_buffs(mob/user, buff)
+ if(buff) // tarukaja
if(ishuman(user))
var/mob/living/carbon/human/H = user
ADD_TRAIT(H, TRAIT_PUGILIST, GLOVE_TRAIT)
@@ -37,17 +54,20 @@
ADD_TRAIT(H, secondary_trait, GLOVE_TRAIT)
H.dna.species.punchdamagehigh += enhancement
H.dna.species.punchdamagelow += enhancement
-
-/obj/item/clothing/gloves/fingerless/pugilist/dropped(mob/user)
-
- REMOVE_TRAIT(user, TRAIT_PUGILIST, GLOVE_TRAIT)
- REMOVE_TRAIT(user, inherited_trait, GLOVE_TRAIT)
- REMOVE_TRAIT(user, secondary_trait, GLOVE_TRAIT)
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- H.dna.species.punchdamagehigh -= enhancement
- H.dna.species.punchdamagelow -= enhancement
- return ..()
+ H.dna.species.punchwoundbonus += wound_enhancement
+ if(!silent)
+ to_chat(H, "With [src] on your arms, you feel ready to punch things.")
+ else // dekaja
+ REMOVE_TRAIT(user, TRAIT_PUGILIST, GLOVE_TRAIT)
+ REMOVE_TRAIT(user, inherited_trait, GLOVE_TRAIT)
+ REMOVE_TRAIT(user, secondary_trait, GLOVE_TRAIT)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.dna.species.punchdamagehigh -= enhancement
+ H.dna.species.punchdamagelow -= enhancement
+ H.dna.species.punchwoundbonus -= wound_enhancement
+ if(!silent)
+ to_chat(user, "With [src] off of your arms, you feel less ready to punch things.")
/obj/item/clothing/gloves/fingerless/pugilist/chaplain
name = "armwraps of unyielding resolve"
@@ -93,6 +113,7 @@
icon_state = "rapid"
item_state = "rapid"
enhancement = 10 //omae wa mou shindeiru
+ wound_enhancement = 10
var/warcry = "AT"
secondary_trait = TRAIT_NOSOFTCRIT //basically extra health
diff --git a/code/modules/clothing/gloves/tacklers.dm b/code/modules/clothing/gloves/tacklers.dm
index f4b4140a1a..eda36ea12f 100644
--- a/code/modules/clothing/gloves/tacklers.dm
+++ b/code/modules/clothing/gloves/tacklers.dm
@@ -65,12 +65,14 @@
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
+ strip_mod = 1.2 // because apparently black gloves had this
/obj/item/clothing/gloves/tackler/combat/insulated
name = "guerrilla gloves"
desc = "Superior quality combative gloves, good for performing tackle takedowns as well as absorbing electrical shocks."
siemens_coefficient = 0
permeability_coefficient = 0.05
+ strip_mod = 1.5 // and combat gloves had this??
/obj/item/clothing/gloves/tackler/combat/insulated/infiltrator
name = "insidious guerrilla gloves"
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 3774ce575f..e19a0538fc 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -190,7 +190,7 @@
/obj/item/clothing/head/wig
name = "wig"
desc = "A bunch of hair without a head attached."
- icon = 'icons/mob/human_face.dmi' // default icon for all hairs
+ icon = 'icons/mob/hair.dmi' // default icon for all hairs
icon_state = "hair_vlong"
flags_inv = HIDEHAIR
color = "#000"
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 11df38cfdd..5dd35788f1 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -355,7 +355,7 @@
/obj/item/clothing/mask/paper/Initialize(mapload)
- .=..()
+ . = ..()
papermask_designs = list(
"Blank" = image(icon = src.icon, icon_state = "plainmask"),
"Neutral" = image(icon = src.icon, icon_state = "neutralmask"),
@@ -384,7 +384,7 @@
"Vertical" = "verticalmask", "Horizontal" = "horizontalmask", "X" ="xmask",
"Bugeyes" = "bugmask", "Double" = "doublemask", "Mark" = "markmask")
- var/choice = show_radial_menu(user,src, papermask_designs, custom_check = FALSE, radius = 36, require_near = TRUE)
+ var/choice = show_radial_menu(user, src, papermask_designs, custom_check = FALSE, radius = 36, require_near = TRUE)
if(src && choice && !user.incapacitated() && in_range(user,src))
icon_state = options[choice]
diff --git a/code/modules/events/shuttle_catastrophe b/code/modules/events/shuttle_catastrophe
new file mode 100644
index 0000000000..d948b39d3b
--- /dev/null
+++ b/code/modules/events/shuttle_catastrophe
@@ -0,0 +1,37 @@
+/datum/round_event_control/shuttle_catastrophe
+ name = "Shuttle Catastrophe"
+ typepath = /datum/round_event/shuttle_catastrophe
+ weight = 10
+ max_occurrences = 1
+
+/datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players, gamemode)
+ if(SSshuttle.emergency.name == "Build your own shuttle kit")
+ return FALSE //don't undo manual player engineering, it also would unload people and ghost them, there's just a lot of problems
+ return ..()
+
+
+/datum/round_event/shuttle_catastrophe
+ var/datum/map_template/shuttle/new_shuttle
+
+/datum/round_event/shuttle_catastrophe/announce(fake)
+ var/cause = pick("was attacked by [syndicate_name()] Operatives", "mysteriously teleported away", "had its refuelling crew mutiny",
+ "was found with its engines stolen", "\[REDACTED\]", "flew into the sunset, and melted", "learned something from a very wise cow, and left on its own",
+ "had cloning devices on it", "had its shuttle inspector put the shuttle in reverse instead of park, causing the shuttle to crash into the hangar")
+
+ priority_announce("Your emergency shuttle [cause]. Your replacement shuttle will be the [new_shuttle.name] until further notice.", "CentCom Spacecraft Engineering")
+
+/datum/round_event/shuttle_catastrophe/setup()
+ var/list/valid_shuttle_templates = list()
+ for(var/shuttle_id in SSmapping.shuttle_templates)
+ var/datum/map_template/shuttle/template = SSmapping.shuttle_templates[shuttle_id]
+ if(template.can_be_bought && template.credit_cost < INFINITY) //if we could get it from the communications console, it's cool for us to get it here
+ valid_shuttle_templates += template
+ new_shuttle = pick(valid_shuttle_templates)
+
+/datum/round_event/shuttle_catastrophe/start()
+ SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_FORCED
+ SSshuttle.unload_preview()
+ SSshuttle.load_template(new_shuttle)
+ SSshuttle.existing_shuttle = SSshuttle.emergency
+ SSshuttle.action_load(new_shuttle)
+ log_shuttle("Shuttle Catastrophe set a new shuttle, [new_shuttle.name].")
diff --git a/code/modules/events/stray_cargo.dm b/code/modules/events/stray_cargo.dm
index 031642c875..aae39e28a4 100644
--- a/code/modules/events/stray_cargo.dm
+++ b/code/modules/events/stray_cargo.dm
@@ -55,7 +55,7 @@
crate.update_icon()
var/obj/structure/closet/supplypod/pod = make_pod()
crate.forceMove(pod)
- new /obj/effect/abstract/DPtarget(LZ, pod)
+ new /obj/effect/pod_landingzone(LZ, pod)
///Handles the creation of the pod, in case it needs to be modified beforehand
/datum/round_event/stray_cargo/proc/make_pod()
diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm
index 0920c9ccb6..e723ddd79b 100644
--- a/code/modules/events/wormholes.dm
+++ b/code/modules/events/wormholes.dm
@@ -29,7 +29,7 @@
for(var/i = 1, i <= number_of_wormholes, i++)
var/turf/T = pick(pick_turfs)
- wormholes += new /obj/effect/portal/wormhole(T, null, 0, null, FALSE)
+ wormholes += new /obj/effect/portal/wormhole(T, 0, null, FALSE)
/datum/round_event/wormholes/announce(fake)
priority_announce("Space-time anomalies detected on the station. There is no additional data.", "Anomaly Alert", "spanomalies")
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index a3ee8c5228..140923c1ef 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -618,3 +618,9 @@
icon_state = "monkey_energy"
list_reagents = list(/datum/reagent/consumable/monkey_energy = 50)
foodtype = SUGAR | JUNKFOOD
+
+/obj/item/reagent_containers/food/drinks/dwarf_mug //dwarf family heirloom (just a cup that always has the manly dorf icon!)
+ name = "ale mug"
+ desc = "An old stained mug used for filling with dwarven ale."
+ icon_state = "manlydorfglass"
+ isGlass = FALSE //it's a wooden mug!
diff --git a/code/modules/food_and_drinks/food/snacks_soup.dm b/code/modules/food_and_drinks/food/snacks_soup.dm
index eea7cdb87d..38a68ad364 100644
--- a/code/modules/food_and_drinks/food/snacks_soup.dm
+++ b/code/modules/food_and_drinks/food/snacks_soup.dm
@@ -291,3 +291,12 @@
tastes = list("creamy peas"= 2, "parsnip" = 1)
filling_color = "#9dc530"
foodtype = VEGETABLES
+
+/obj/item/reagent_containers/food/snacks/soup/facehuggerpot
+ name = "pot of face hugger jambalaya"
+ desc = "An entire pot of an extremely spicy dish made using extremely exotic ingredients. Highly recommend by an interdimensional businessman."
+ icon_state = "facehuggerpot"
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 4)
+ tastes = list("face huggers" = 1)
+ foodtype = MEAT
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm
index 6372137edc..c52218c913 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm
@@ -291,3 +291,18 @@
)
result = /obj/item/reagent_containers/food/snacks/soup/peasoup
subcategory = CAT_SOUP
+
+/datum/crafting_recipe/food/facehuggerjambalayapot
+ name = "Facehugger jambalaya"
+ reqs = list(
+ /datum/reagent/bluespace = 10,
+ /datum/reagent/consumable/ethanol/booger =10,
+ /obj/item/organ/heart= 3,
+ /obj/item/clothing/mask/facehugger = 1,
+ /obj/item/reagent_containers/food/snacks/egg = 1,
+ /datum/reagent/consumable/blackpepper = 5,
+ /datum/reagent/toxin/acid = 5
+
+ )
+ result = /obj/item/reagent_containers/food/snacks/soup/facehuggerpot
+ subcategory = CAT_SOUP
diff --git a/code/modules/holiday/halloween/bartholomew.dm b/code/modules/holiday/halloween/bartholomew.dm
index c9a4a946a3..117e03c357 100644
--- a/code/modules/holiday/halloween/bartholomew.dm
+++ b/code/modules/holiday/halloween/bartholomew.dm
@@ -130,9 +130,13 @@
/obj/item/reagent_containers/pill = 2,
/obj/item/clothing/shoes = 8,
/obj/item/clothing/head = 3,
- /obj/item/reagent_containers/food/snacks = 3,
+ /obj/item/reagent_containers/food/snacks = 5,
/obj/item/reagent_containers/syringe/dart = 2,
- /obj/item/reagent_containers/food/drinks/soda_cans = 5)
+ /obj/item/reagent_containers/food/drinks/soda_cans = 5,
+ /obj/item/reagent_containers/food/drinks/drinkingglass = 4,
+ /obj/item/reagent_containers/food/drinks = 6,
+ /obj/item/reagent_containers/food/snacks/grown/apple = 1,
+ /obj/item/reagent_containers/food/snacks/grown/banana = 2)
if(length >= 5)
return TRUE
//var/metalist = pickweight(GLOB.maintenance_loot)
diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm
index 573b04a296..16151c4191 100644
--- a/code/modules/holiday/halloween/jacqueen.dm
+++ b/code/modules/holiday/halloween/jacqueen.dm
@@ -48,8 +48,8 @@
var/progression = list() //Keep track of where people are in the story.
var/active = TRUE //Turn this to false to keep normal mob behavour
var/cached_z
- /// I'm busy chatting, don't move.
- var/busy_chatting = FALSE
+ /// I'm busy, don't move.
+ var/busy = FALSE
/mob/living/simple_animal/jacq/Initialize()
..()
@@ -68,11 +68,14 @@
playsound(loc, 'sound/spookoween/ahaha.ogg', 100, 0.25)
var/mob/living/simple_animal/jacq/Jacq = new src.type(loc)
Jacq.progression = progression
+ if(ckey) //transfer over any ghost posessions
+ Jacq.key = key
..()
/mob/living/simple_animal/jacq/death() //What is alive may never die
visible_message("[src] cackles, \"You'll nae get rid a me that easily!\"")
playsound(loc, 'sound/spookoween/ahaha.ogg', 100, 0.25)
+ fully_heal(FALSE)
health = 25
poof()
@@ -81,9 +84,9 @@
say("Hello there [gender_check(M)]!")
return ..()
if(!ckey)
- busy_chatting = FALSE
+ stopmove()
chit_chat(M)
- busy_chatting = TRUE
+ canmove()
..()
/mob/living/simple_animal/jacq/attack_paw(mob/living/carbon/monkey/M)
@@ -91,11 +94,28 @@
say("Hello there [gender_check(M)]!")
return ..()
if(!ckey)
- busy_chatting = FALSE
+ stopmove()
chit_chat(M)
- busy_chatting = TRUE
+ canmove()
..()
+/mob/living/simple_animal/jacq/proc/canmove()
+ busy = FALSE
+ update_mobility()
+
+/mob/living/simple_animal/jacq/proc/stopmove()
+ if(ckey) //if someone is in her, don't disable her movement!
+ canmove()
+ return
+ busy = TRUE
+ update_mobility()
+
+/mob/living/simple_animal/jacq/proc/jacqrunes(message, mob/living/carbon/C) //Displays speechtext over Jacq for the user only.
+ var/atom/hearer = C
+ var/list/spans = list("spooky")
+ new /datum/chatmessage(message, src, hearer, spans)
+
+
/mob/living/simple_animal/jacq/proc/poof()
last_poof = world.realtime
var/datum/reagents/R = new/datum/reagents(100)//Hey, just in case.
@@ -104,7 +124,7 @@
s.set_up(R, 0, loc)
s.start()
visible_message("[src] disappears in a puff of smoke!")
- busy_chatting = TRUE
+ canmove()
health = 25
//Try to go to populated areas
@@ -120,7 +140,7 @@
continue
targets += H
- if(!targets)
+ if(!targets.len)
targets = GLOB.generic_event_spawns
for(var/i in 1 to 6) //Attempts a jump up to 6 times.
@@ -151,14 +171,16 @@
if(!progression["[C.real_name]"] || !(progression["[C.real_name]"] & JACQ_HELLO))
visible_message("[src] smiles ominously at [C], \"Well halo there [gender]! Ah'm Jacqueline, tae great Pumpqueen, great tae meet ye.\"")
+ jacqrunes("Well halo there [gender]! Ah'm Jacqueline, tae great Pumpqueen, great tae meet ye.", C)
sleep(20)
visible_message("[src] continues, \"Ah'm sure yae well stunned, but ah've got nae taem fer that. Ah'm after the candies around this station. If yae get mae enoof o the wee buggers, Ah'll give ye a treat, or if yae feeling bold, Ah ken trick ye instead.\" giving [C] a wide grin.")
+ jacqrunes("Ah'm sure yae well stunned, but ah've got nae taem fer that. Ah'm after the candies around this station. If yae get mae enoof o the wee buggers, Ah'll give ye a treat, or if yae feeling bold, Ah ken trick ye instead.", C)
if(!progression["[C.real_name]"])
progression["[C.real_name]"] = NONE //TO MAKE SURE THAT THE LIST ENTRY EXISTS.
progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_HELLO
- var/choices = list("Trick", "Treat", "How do I get candies?")
+ var/choices = list("Trick", "Treat", "How do I get candies?", "Do I know you from somewhere?")
var/choice = input(C, "Trick or Treat?", "Trick or Treat?") in choices
switch(choice)
if("Trick")
@@ -168,14 +190,20 @@
if(check_candies(C))
treat(C, gender)
else
- visible_message("[src] raises an eyebrow, \"You've nae got any candies Ah want! They're the orange round ones, now bugger off an go get em first.\"")
+ visible_message("[src] raises aneyebrow, \"You've nae got any candies Ah want! They're the orange round ones, now bugger off an go get em first.\"")
+ jacqrunes("You've nae got any candies Ah want! They're the orange round ones, now bugger off an go get em first.", C)
return
if("How do I get candies?")
visible_message("[src] says, \"Gae find my familiar; Bartholomew. Ee's tendin the cauldron which ken bring oot t' magic energy in items scattered aroond. Knowing him, ee's probably gone tae somewhere with books.\"")
+ jacqrunes("Gae find my familiar; Bartholomew. Ee's tendin the cauldron which ken bring oot t' magic energy in items scattered aroond. Knowing him, ee's probably gone tae somewhere with books.", C)
return
+ if("Do I know you from somewhere?")
+ visible_message("[src] says, \"Aye ye micht dae, ah was kicking aboot round 'ere aboot a year ago when ah had a wee... altercation wit the witch academy n' ran oot here tae crash oan me sis's floor. Course she pushed me tae git it a' sorted oot lik', bit nae before ah hud a wee bit o' fun oan this station. Or maybe ye jest recognise me ma's prized pumpkin atop me nonce.\"")
+ jacqrunes("Aye ye micht dae, ah was kicking aboot round 'ere aboot a year ago when ah had a wee... altercation wit the witch academy n' ran oot here tae crash oan me sis's floor. Course she pushed me tae git it a' sorted oot lik', bit nae before ah hud a wee bit o' fun oan this station. Or maybe ye jest recognise me ma's prized pumpkin atop me nonce.", C)
/mob/living/simple_animal/jacq/proc/treat(mob/living/carbon/C, gender)
visible_message("[src] gives off a glowing smile, \"What ken Ah offer ye? I can magic up an object, a potion or a plushie fer ye.\"")
+ jacqrunes("What ken Ah offer ye? I can magic up an object, a potion or a plushie fer ye.", C)
var/choices_reward = list("Object - 3 candies", "Potion - 2 candies", "Jacqueline Tracker - 2 candies", "Plushie - 1 candy", "Can I get to know you instead?", "Become a pumpkinhead dullahan (perma) - 4 candies")
var/choice_reward = input(usr, "Trick or Treat?", "Trick or Treat?") in choices_reward
@@ -184,8 +212,10 @@
if("Become a pumpkinhead dullahan (perma) - 4 candies")
if(!take_candies(C, 4))
visible_message("[src] raises an eyebrown, \"It's 4 candies for that [gender]! Thems the rules!\"")
+ jacqrunes("It's 4 candies for that [gender]! Thems the rules!", C)
return
visible_message("[src] waves their arms around, \"Off comes your head, a pumpkin taking it's stead!\"")
+ jacqrunes("Off comes your head, a pumpkin taking it's stead!", C)
C.reagents.add_reagent(/datum/reagent/mutationtoxin/pumpkinhead, 5)
sleep(20)
poof()
@@ -194,6 +224,7 @@
if("Object - 3 candies")
if(!take_candies(C, 3))
visible_message("[src] raises an eyebrown, \"It's 3 candies per trinket [gender]! Thems the rules!\"")
+ jacqrunes("It's 3 candies per trinket [gender]! Thems the rules!", C)
return
var/new_obj = pick(subtypesof(/obj))
@@ -203,36 +234,43 @@
var/reward = new new_obj(C.loc)
C.put_in_hands(reward)
visible_message("[src] waves her hands, magicking up a [reward] from thin air, \"There ye are [gender], enjoy! \"")
+ jacqrunes("There ye are [gender], enjoy!", C)
sleep(20)
poof()
return
if("Potion - 2 candies")
if(!take_candies(C, 2))
visible_message("[src] raises an eyebrow, \"It's 2 candies per potion [gender]! Thems the rules!\"")
+ jacqrunes("It's 2 candies per potion [gender]! Thems the rules!", C)
return
var/reward = new /obj/item/reagent_containers/potion_container(C.loc)
C.put_in_hands(reward)
visible_message("[src] waves her hands, magicking up a [reward] from thin air, \"There ye are [gender], enjoy! \"")
+ jacqrunes("There ye are [gender], enjoy!", C)
sleep(20)
poof()
return
if("Plushie - 1 candy")
if(!take_candies(C, 1))
visible_message("[src] raises an eyebrow, \"It's 1 candy per plushie [gender]! Thems the rules!\"")
+ jacqrunes("It's 1 candy per plushie [gender]! Thems the rules!", C)
return
new /obj/item/toy/plush/random(C.loc)
visible_message("[src] waves her hands, magicking up a plushie from thin air, \"There ye are [gender], enjoy! \"")
+ jacqrunes("There ye are [gender], enjoy!", C)
sleep(20)
poof()
return
if("Jacqueline Tracker - 2 candies")
if(!take_candies(C, 2))
visible_message("[src] raises an eyebrow, \"It's 1 candy per plushie [gender]! Thems the rules!\"")
+ jacqrunes("It's 1 candy per plushie [gender]! Thems the rules!", C)
return
new /obj/item/pinpointer/jacq(C.loc)
visible_message("[src] waves her hands, magicking up a tracker from thin air, \"Feels weird to magic up a tracker fer meself but, here ye are [gender], enjoy! \"")
+ jacqrunes("Feels weird to magic up a tracker fer meself but, here ye are [gender], enjoy!", C)
sleep(20)
poof()
return
@@ -252,7 +290,7 @@
choices += "What is that on your head?"
if(!(progression["[C.real_name]"] & JACQ_EXPELL))
if(progression["[C.real_name]"] & JACQ_WITCH)
- choices += "So you got ex-spell-ed?"
+ choices += "What is it like being a witch?"
else
choices += "Are you a witch?"
@@ -270,47 +308,79 @@
//If you've nothing to ask
if(!LAZYLEN(choices))
visible_message("[src] sighs, \"Ah'm all questioned oot fer noo, [gender].\"")
+ jacqrunes("Ah'm all questioned oot fer noo, [gender]", C)
return
//Otherwise, lets go!
visible_message("[src] says, \"A question? Sure, it'll cost you a candy though!\"")
+ jacqrunes("A question? Sure, it'll cost you a candy though!", C)
choices += "Nevermind"
//Candies for chitchats
var/choice = input(C, "What do you want to ask?", "What do you want to ask?") in choices
if(!take_candies(C, 1))
visible_message("[src] raises an eyebrow, \"It's a candy per question [gender]! Thems the rules!\"")
+ jacqrunes("It's a candy per question [gender]! Thems the rules!", C)
return
//Talking
switch(choice)
if("Why do you want the candies?")
visible_message("[src] says, \"Ave ye tried them? They're full of all sorts of reagents. Ah'm after them so ah ken magic em up an hopefully find rare stuff fer me brews. Honestly it's a lot easier magicking up tatt fer ye lot than runnin aroond on me own like. I'd ask me familiars but most a my familiars are funny fellows 'n constantly bugger off on adventures when given simple objectives like; Go grab me a tea cake or watch over me cauldron. Ah mean, ye might run into Bartholomew my cat. Ee's supposed tae be tending my cauldron, but I've nae idea where ee's got tae.\"")
+ jacqrunes("Ave ye tried them? They're full of all sorts of reagents. Ah'm after them so ah ken magic em up an hopefully find rare stuff fer me brews. Honestly it's a lot easier magicking up tatt fer ye lot than runnin aroond on me own like. I'd ask me familiars but most a my familiars are funny fellows 'n constantly bugger off on adventures when given simple objectives like; Go grab me a tea cake or watch over me cauldron. Ah mean, ye might run into Bartholomew my cat. Ee's supposed tae be tending my cauldron, but I've nae idea where ee's got tae.", C)
progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_CANDIES
sleep(30)
if("You really came all this way for candy?")
- visible_message("[src] l ooks tae the side sheepishly, \"Aye, well, tae be honest, Ah'm here tae see me sis, but dunnae let her knew that. She's an alchemist too like, but she dunnae use a caldron like mae, she buggered off like tae her posh ivory tower tae learn bloody chemistry instead!\" [src] scowls, \"She's tae black sheep o' the family too, so we dunnae see eye tae eye sometimes on alchemy. Ah mean, she puts moles in her brews! Ye dunnae put moles in yer brews! Yae threw your brews at tae wee bastards an blew em up!\" [src] sighs, \"But she's a heart o gold so.. Ah wanted tae see her an check up oon her, make sure she's okay.\"")
+ visible_message("[src] looks to the side sheepishly, \"Aye, well, tae be honest, Ah'm here tae see me sis, but dunnae let her knew that. She's an alchemist too like, but she dunnae use a caldron like mae, she buggered off like tae her posh ivory tower tae learn bloody chemistry instead!\" [src] scowls, \"She's tae black sheep o' the family too, so we dunnae see eye tae eye sometimes on alchemy. Ah mean, she puts moles in her brews! Ye dunnae put moles in yer brews! Yae threw your brews at tae wee bastards an blew em up!\" [src] sighs, \"But she's a heart o gold so.. Ah wanted tae see her an check up oon her, make sure she's okay.\"")
+ jacqrunes("Aye, well, tae be honest, Ah'm here tae see me sis, but dunnae let her knew that. She's an alchemist too like, but she dunnae use a caldron like mae, she buggered off like tae her posh ivory tower tae learn bloody chemistry instead", C)
progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_FAR
- sleep(30)
+ sleep(10)
+ jacqrunes("She's tae black sheep o' the family too, so we dunnae see eye tae eye sometimes on alchemy. Ah mean, she puts moles in her brews! Ye dunnae put moles in yer brews! Yae threw your brews at tae wee bastards an blew em up!", C)
+ sleep(10)
+ jacqrunes("But she's a heart o gold so.. Ah wanted tae see her an check up oon her, make sure she's okay.", C)
+ sleep(10)
if("What is that on your head?")
- visible_message("[src] pats the pumpkin atop her head, \"This thing? This ain't nae ordinary pumpkin! Me Ma grew this monster ooer a year o love, dedication an hard work. Honestly it felt like she loved this thing more than any of us, which Ah knew ain't true an it's not like she was hartless or anything but.. well, we had a falling oot when Ah got back home with all me stuff in tow. An all she had done is sent me owl after owl over t' last year aboot this bloody pumpkin and ah had enough. So ah took it, an put it on me head. You know, as ye do. Ah am the great Pumpqueen after all, Ah deserve this.\"")
+ visible_message("[src] pats the pumpkin atop her head, \"This thing? This ain't nae ordinary pumpkin! Me Ma grew this monster ooer a year o love, dedication an hard work. Honestly I got bloody sick o'er harpin' on aboot it, all she had done is sent me owl after owl over aboot this bloody pumpkin since i left the nest and ah had enough after a ... mild altercation like. So I nabbed it last halloween. Caught bloody hell fer it ah did, course me sis talked to me ma and, well, simmered her doon. We've all but made up noo, but seein' as ah'm the great Pumpqueen after all, I cannae be seen withoot it like.\"")
+ jacqrunes("This thing? This ain't nae ordinary pumpkin! Me Ma grew this monster ooer a year o love, dedication an hard work. Honestly I got bloody sick o'er harpin' on aboot it, all she had done is sent me owl after owl over aboot this bloody pumpkin since i left the nest and ah had enough after a ... mild altercation like. So I nabbed it last halloween. Caught bloody hell fer it ah did, course me sis talked to me ma and, well, simmered her doon. We've all but made up noo, but seein' as ah'm the great Pumpqueen after all, I cannae be seen withoot it like.", C)
progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_HEAD
sleep(30)
+ //Year 1 answer: for anyone who is interested!
+ /*This thing? This ain't nae ordinary pumpkin! Me Ma grew this monster ooer a year o love, dedication an hard work. Honestly it felt like she loved this thing more than any of us, which Ah knew ain't true an it's not like she was hartless or anything but.. well, we had a falling oot when Ah got back home with all me stuff in tow. An all she had done is sent me owl after owl over t' last year aboot this bloody pumpkin and ah had enough. So ah took it, an put it on me head. You know, as ye do. Ah am the great Pumpqueen after all, Ah deserve this.*/
+
if("Are you a witch?")
- visible_message("[src] grumbles, \"If ye must know, Ah got kicked oot of the witch academy fer being too much of a \"loose cannon\". A bloody loose cannon? Nae they were just pissed off Ah had the brass tae proclaim myself as the Pumpqueen! And also maybe the time Ah went and blew up one of the towers by trying tae make a huge batch of astrogen might've had something tae do with it. Ah mean it would've worked fine if the cauldrons weren't so shite and were actually upgraded by the faculty. So technically no, I'm not a witch.\"")
+ visible_message("[src] smirks, \"Weel, after getting kicked oot over a very minor explosion last year, ah wis able tae git back in 'n' finish me witching degree thanks tae me sis! 'twas bloody brutal finishing th' degree though, ah will tell ye, ye take a peek o'er at t' other witches all prim 'n' proper like 'n' it gets in yer heid, ye'r nae as guid. But ah bloody well ended up summoning Nar'Sie last year for the lot o' yous. Aye a'm a loose cannon - but ah get results.\" thumping her chest with pride as she finishes speaking.")
+ jacqrunes("Weel, after getting kicked oot over a very minor explosion last year, ah wis able tae git back in 'n' finish me witching degree thanks tae me sis! 'twas bloody brutal finishing th' degree though, ah will tell ye, ye take a peek o'er at t' other witches all prim 'n' proper like 'n' it gets in yer heid, ye'r nae as guid. But ah bloody well ended up summoning Nar'Sie last year for the lot o' yous. Aye a'm a loose cannon - but ah get results." , C)
progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_WITCH
sleep(30)
- if("So you got ex-spell-ed?")
- visible_message("[src] Gives you a blank look at the pun, before continuing, \"Not quite, Ah know Ah ken get back into the academy, it's only an explosion, they happen all the time, but, tae be fair it's my fault that things came tae their explosive climax. You don't know what it's like when you're after a witch doctorate, everyone else is doing well, everyone's making new spells and the like, and I'm just good at making explosions really, or fireworks. So, Ah did something Ah knew was dangerous, because Ah had tae do something tae stand oot, but Ah know this life ain't fer me, Ah don't want tae be locked up in dusty towers, grinding reagent after reagent together, trying tae find new reactions, some of the wizards in there haven't left fer years. Ah want tae live, Ah want tae fly around on a broom, turn people into cats fer a day and disappear cackling! That's what got me into witchcraft!\" she throws her arms up in the arm, spinning the pumpkin upon her head slightly. She carefully spins it back to face you, giving oot a soft sigh, \"Ah know my mother's obsession with this dumb thing on my head is just her trying tae fill the void of me and my sis moving oot, and it really shouldn't be on my head. And Ah know that I'm really here tae get help from my sis.. She's the sensible one, and she gives good hugs.\"")
- sleep(30)
+ //Year 1 answer for anyone who is interested:
+ /* Are you a witch?
+ If ye must know, Ah got kicked oot of the witch academy fer being too much of a \"loose cannon\". A bloody loose cannon? Nae they were just pissed off Ah had the brass tae proclaim myself as the Pumpqueen! And also maybe the time Ah went and blew up one of the towers by trying tae make a huge batch of astrogen might've had something tae do with it. Ah mean it would've worked fine if the cauldrons weren't so shite and were actually upgraded by the faculty. So technically no, I'm not a witch.*/
+
+ if("What is it like being a witch?") //What is it like being a witch?
+
+ visible_message("[src] says, \"Tae be honest, ah dunnae. Ah mean ah have a piece o’ paper that implies that a’m, ‘n’ a few folk who seem keen in shoving me back in their magic tower, but I don’t know if that’s fer me really.\" she gives the back of her pumpkin a quick scratch as she continues \"What draws me tae witchcraft is the chaos, ah live tae see th’ utter madness that comes fae the spells ah cast ‘n’ th’ like, ‘n’ ah know you do tae, it’s why you’re ‘ere, aye? Ah kin conjure some utterly chaotic things, and ah love tae do it, just tae see what I’ll git! It’s why visiting here is so fun, ye wee lot scurrying about, getting me candies, hoping I’ll conjure up something utterly chaotic!\" she throws her arms up in the arm with a laugh, spinning the pumpkin upon her head slightly. She carefully spins it back to face you, \"But o’ course life ain’t that easy, ye can’t just go around being a pure agent o’ chaos, ‘n’ ah feel like the reality o’ the world be trying tae dull me, to shove me in a boring dusty auld room where ah spend t’ rest o’ me days researching some boggin’ magic till ah die. Ah want tae bloody well change t’ world, ah want to do something that leaves an impact, but ah dunnae want t’ kill people doing it.\" she gives out a soft sigh, \"Who knows, maybe I’ll bugger off ‘n’ make some pumkinmobiles or something daft like that.\" ")
+ jacqrunes("Tae be honest, ah dunnae. Ah mean ah have a piece o’ paper that implies that a’m, ‘n’ a few folk who seem keen in shoving me back in their magic tower, but I don’t know if that’s fer me really." , C)
+ sleep(10)
+ jacqrunes("What draws me tae witchcraft is the chaos, ah live tae see th’ utter madness that comes fae the spells ah cast ‘n’ th’ like, ‘n’ ah know you do tae, it’s why you’re ‘ere, aye? Ah kin conjure some utterly chaotic things, and ah love tae do it, just tae see what I’ll git! It’s why visiting here is so fun, ye wee lot scurrying about, getting me candies, hoping I’ll conjure up something utterly chaotic!" , C)
+ sleep(10)
+ jacqrunes("But o’ course life ain’t that easy, ye can’t just go around being a pure agent o’ chaos, ‘n’ ah feel like the reality o’ the world be trying tae dull me, to shove me in a boring dusty auld room where ah spend t’ rest o’ me days researching some boggin’ magic till ah die. Ah want tae bloody well change t’ world, ah want to do something that leaves an impact, but ah dunnae want t’ kill people doing it.", C)
+ sleep(10)
+ jacqrunes("Who knows, maybe I’ll bugger off ‘n’ make some pumkinmobiles or something daft like that.", C)
+ sleep(25)
visible_message("[src] says, \"Thanks [C], Ah guess Ah didn't realise Ah needed someone tae talk tae but, I'm glad ye spent all your candies talking tae me. Funny how things seem much worse in yer head.\"")
+ jacqrunes("Thanks [C], Ah guess Ah didn't realise Ah needed someone tae talk tae but, I'm glad ye spent all your candies talking tae me. Funny how things seem much worse in yer head." , C)
progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_EXPELL
sleep(30)
+ //Year 1 answer for anyone who is interested:
+ /*"So you got ex-spell-ed?"
+ Gives you a blank look at the pun, before continuing, \"Not quite, Ah know Ah ken get back into the academy, it's only an explosion, they happen all the time, but, tae be fair it's my fault that things came tae their explosive climax. You don't know what it's like when you're after a witch doctorate, everyone else is doing well, everyone's making new spells and the like, and I'm just good at making explosions really, or fireworks. So, Ah did something Ah knew was dangerous, because Ah had tae do something tae stand oot, but Ah know this life ain't fer me, Ah don't want tae be locked up in dusty towers, grinding reagent after reagent together, trying tae find new reactions, some of the wizards in there haven't left fer years. Ah want tae live, Ah want tae fly around on a broom, turn people into cats fer a day and disappear cackling! That's what got me into witchcraft!\" she throws her arms up in the arm, spinning the pumpkin upon her head slightly. She carefully spins it back to face you, giving oot a soft sigh, \"Ah know my mother's obsession with this dumb thing on my head is just her trying tae fill the void of me and my sis moving oot, and it really shouldn't be on my head. And Ah know that I'm really here tae get help from my sis.. She's the sensible one, and she gives good hugs.
+ */
+
if("Can I take you out on a date?")
visible_message("[src] blushes, \"...You want tae ask me oot on a date? Me? After all that nonsense Ah just said? It seems a waste of a candy honestly.\"")
- //progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_DATE
+ jacqrunes("...You want tae ask me oot on a date? Me? After all that nonsense Ah just said? It seems a waste of a candy honestly." , C)
visible_message("[src] looks to the side, deep in thought.")
dating_start(C, gender)
@@ -328,15 +398,18 @@
switch(option)
if(1)
visible_message("[src] waves their arms around, \"Hocus pocus, making friends is now your focus!\"")
+ jacqrunes("Hocus pocus, making friends is now your focus!", C)
var/message = pick("make a tasty sandwich for", "compose a poem for", "aquire a nice outfit to give to", "strike up a conversation about pumpkins with", "write a letter and deliver it to", "give a nice hat to")
var/mob/living/L2 = pick(GLOB.player_list)
message += " [L2.name]."
to_chat(C, " You feel an overwhelming desire to [message]")
if(2)
visible_message("[src] waves their arms around, \"If only you had a better upbringing, your ears are now full of my singing!\"")
- C.client.tgui_panel?.play_music("https://puu.sh/ExBbv.mp4")
+ jacqrunes("If only you had a better upbringing, your ears are now full of my singing!", C)
+ C.client.tgui_panel?.play_music("https://katlin.dog/v/spooky.mp4")
if(3)
visible_message("[src] waves their arms around, \"You're cute little bumpkin, On your head is a pumpkin!\"")
+ jacqrunes("You're cute little bumpkin, On your head is a pumpkin!", C)
if(C.head)
var/obj/item/W = C.head
C.dropItemToGround(W, TRUE)
@@ -344,12 +417,15 @@
C.equip_to_slot(jaqc_latern, SLOT_HEAD, 1, 1)
if(4)
visible_message("[src] waves their arms around, \"In your body there's something amiss, you'll find it's a chem made by my sis!\"")
+ jacqrunes("In your body there's something amiss, you'll find it's a chem made by my sis!", C)
C.reagents.add_reagent(/datum/reagent/fermi/eigenstate, 30)
if(5)
visible_message("[src] waves their arms around, \"A new familiar for me, and you'll see it's thee!\"")
- C.reagents.add_reagent("secretcatchem", 30)
+ jacqrunes("A new familiar for me, and you'll see it's thee!", C)
+ C.reagents.add_reagent(/datum/reagent/fermi/secretcatchem, 30)
if(6)
visible_message("[src] waves their arms around, \"While you may not be a ghost, for this sheet you'll always be it's host.\"")
+ jacqrunes("While you may not be a ghost, for this sheet you'll always be it's host.", C)
var/mob/living/carbon/human/H = C
if(H.wear_suit)
var/obj/item/W = H.wear_suit
@@ -370,22 +446,30 @@
message_admins("[C2]/[C2.key] has agreed to go on a date with [C] as Jacqueline.")
log_game("HALLOWEEN: [C2]/[C2.key] has agreed to go on a date with [C] as Jacqueline")
to_chat(src, "You are Jacqueline the great pumpqueen, witch Extraordinaire! You're a very Scottish lass with a kind heart, but also a little crazy. You also blew up the wizarding school and you're suspended for a while, so you visited the station before heading home. On your head lies the prize pumpkin of your Mother's pumpkin patch. You're currently on a date with [C] and well, I didn't think anyone would get this far. Please be good so I can do events like this in the future. ")
- return
+ canmove()
+ return TRUE
else
candies =- C2
visible_message("[src] looks to the side, \"Look, Ah like ye but, Ah don't think Ah can right now. If ye can't tell, the stations covered in volatile candies, I've a few other laddies and lassies running after me treats, and tae top it all off, I've the gods breathing down me neck, watching every treat Ah make fer the lot of yous.\" she sighs, \"But that's not a no, right? That's.. just a nae right noo.\"")
+ jacqrunes("Look, Ah like ye but, Ah don't think Ah can right now. If ye can't tell, the stations covered in volatile candies, I've a few other laddies and lassies running after me treats, and tae top it all off, I've the gods breathing down me neck, watching every treat Ah make fer the lot of yous.", C)
sleep(20)
+ jacqrunes("But that's not a no, right? That's.. just a nae right noo.", C)
visible_message("[src] takes off the pumpkin on her head, a rich blush on her cheeks. She leans over planting a kiss upon your forehead quickly befere popping the pumpkin back on her head.")
- sleep(10)
+ sleep(20)
visible_message("[src] waves their arms around, \"There, that aught tae be worth a candy.\"")
+ jacqrunes("There, that aught tae be worth a candy.", C)
sleep(20)
poof()
/mob/living/simple_animal/jacq/update_mobility()
. = ..()
- if(busy_chatting)
+ if(busy)
DISABLE_BITFIELD(., MOBILITY_MOVE)
- mobility_flags = .
+ else
+ ENABLE_BITFIELD(., MOBILITY_MOVE)
+ mobility_flags = .
+
+
/obj/item/clothing/head/hardhat/pumpkinhead/jaqc
name = "Jacq o' latern"
diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm
index 83bb67b879..f6e4684e21 100644
--- a/code/modules/holiday/holidays.dm
+++ b/code/modules/holiday/holidays.dm
@@ -351,7 +351,7 @@
/datum/holiday/halloween
name = HALLOWEEN
- begin_day = 28
+ begin_day = 1
begin_month = OCTOBER
end_day = 2
end_month = NOVEMBER
diff --git a/code/modules/hydroponics/grown/grass_carpet.dm b/code/modules/hydroponics/grown/grass_carpet.dm
index e6fd991169..51e94afb3c 100644
--- a/code/modules/hydroponics/grown/grass_carpet.dm
+++ b/code/modules/hydroponics/grown/grass_carpet.dm
@@ -50,7 +50,7 @@
plantname = "Fairygrass"
product = /obj/item/reagent_containers/food/snacks/grown/grass/fairy
icon_grow = "fairygrass-grow"
- icon_dead = "fairygrass-dead"
+ icon_dead = "grass-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/blue)
mutatelist = list (/obj/item/seeds/grass/carpet)
reagents_add = list(/datum/reagent/consumable/nutriment = 0.02, /datum/reagent/hydrogen = 0.05, /datum/reagent/drug/space_drugs = 0.15)
diff --git a/code/modules/hydroponics/grown/mushrooms.dm b/code/modules/hydroponics/grown/mushrooms.dm
index 80ba6b7375..e6d2484632 100644
--- a/code/modules/hydroponics/grown/mushrooms.dm
+++ b/code/modules/hydroponics/grown/mushrooms.dm
@@ -193,6 +193,8 @@
growthstages = 3
genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
+ icon_grow = "chanter-grow"
+ icon_dead = "chanter-dead"
reagents_add = list(/datum/reagent/consumable/nutriment = 0.1)
mutatelist = list(/obj/item/seeds/chanterelle/jupitercup)
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index d6022c1345..a1a177c028 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -42,6 +42,14 @@
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "hydrotray3"
+/obj/machinery/hydroponics/constructable/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated))
+ AddComponent(/datum/component/plumbing/simple_demand)
+
+/obj/machinery/hydroponics/constructable/proc/can_be_rotated(mob/user, rotation_type)
+ return !anchored
+
/obj/machinery/hydroponics/constructable/RefreshParts()
var/tmp_capacity = 0
for (var/obj/item/stock_parts/matter_bin/M in component_parts)
@@ -285,7 +293,7 @@
else
plant_overlay.icon_state = myseed.icon_harvest
else
- var/t_growthstate = min(round((age / myseed.maturation) * myseed.growthstages), myseed.growthstages)
+ var/t_growthstate = clamp(round((age / myseed.maturation) * myseed.growthstages), 1, myseed.growthstages)
plant_overlay.icon_state = "[myseed.icon_grow][t_growthstate]"
add_overlay(plant_overlay)
diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm
index efd98c4d50..833b2963ad 100644
--- a/code/modules/integrated_electronics/subtypes/output.dm
+++ b/code/modules/integrated_electronics/subtypes/output.dm
@@ -44,18 +44,18 @@
/obj/item/integrated_circuit/output/screen/large/do_work()
..()
- if(isliving(assembly.loc))//this whole block just returns if the assembly is neither in a mobs hands or on the ground
- var/mob/living/H = assembly.loc
- if(H.get_active_held_item() != assembly && H.get_inactive_held_item() != assembly)
- return
- else
- if(!isturf(assembly.loc))
- return
-
- var/atom/host = assembly || src
var/list/mobs = list()
- for(var/mob/M in range(0, get_turf(src)))
- mobs += M
+ if(isliving(assembly.loc))
+ mobs += assembly.loc
+ var/mob/living/L = assembly.loc
+ if(L.is_holding(src))
+ for(var/mob/M in range(1, get_turf(src)))
+ mobs += M
+ else
+ for(var/mob/M in range(2, get_turf(src)))
+ mobs += M
+
+ var/atom/host = assembly || src
to_chat(mobs, "[icon2html(host.icon, world, host.icon_state)] flashes a message: [stuff_to_display]")
host.investigate_log("displayed \"[html_encode(stuff_to_display)]\" as [type].", INVESTIGATE_CIRCUIT)
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 0feceaf1a8..b0ac5248c1 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -73,6 +73,31 @@
/// Starting skill modifiers.
var/list/starting_modifiers
+/**
+ * Checks if we should be created on a certain map
+ */
+/datum/job/proc/map_check(datum/map_config/C)
+ return (length(C.job_whitelist)? (type in C.job_whitelist) : !(type in C.job_blacklist))
+
+/**
+ * Processes map specific overrides
+ */
+/datum/job/proc/process_map_overrides(datum/map_config/C)
+ if(type in C.job_override_spawn_positions)
+ spawn_positions = C.job_override_spawn_positions[type]
+ if(type in C.job_override_total_positions)
+ total_positions = C.job_override_total_positions[type]
+ if(type in C.job_access_override)
+ access = C.job_access_override[type]
+ minimal_access = access
+ else
+ if(type in C.job_access_add)
+ access += C.job_access_add[type]
+ minimal_access += C.job_access_add[type]
+ if(type in C.job_access_remove)
+ access -= C.job_access_add[type]
+ minimal_access -= C.job_access_remove[type]
+
//Only override this proc
//H is usually a human unless an /equip override transformed it
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
@@ -175,9 +200,6 @@
/datum/job/proc/config_check()
return TRUE
-/datum/job/proc/map_check()
- return TRUE
-
/datum/job/proc/radio_help_message(mob/M)
to_chat(M, "Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.")
diff --git a/code/modules/jobs/map_changes/map_changes.dm b/code/modules/jobs/map_changes/map_changes.dm
deleted file mode 100644
index 575075037b..0000000000
--- a/code/modules/jobs/map_changes/map_changes.dm
+++ /dev/null
@@ -1,4 +0,0 @@
-//this needs to come after the job_types subfolder to keep the correct ordering
-
-#include "..\..\..\..\_maps\map_files\PubbyStation\job_changes.dm"
-#undef JOB_MODIFICATION_MAP_NAME
\ No newline at end of file
diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm
index 3a47cd2315..3d12f89cfe 100644
--- a/code/modules/keybindings/bindings_client.dm
+++ b/code/modules/keybindings/bindings_client.dm
@@ -1,6 +1,7 @@
// Clients aren't datums so we have to define these procs indpendently.
// These verbs are called for all key press and release events
/client/verb/keyDown(_key as text)
+ SHOULD_NOT_SLEEP(TRUE)
set instant = TRUE
set hidden = TRUE
@@ -83,6 +84,7 @@
keyUp("[key]")
/client/verb/keyUp(_key as text)
+ SHOULD_NOT_SLEEP(TRUE)
set instant = TRUE
set hidden = TRUE
diff --git a/code/modules/keybindings/keybind/movement.dm b/code/modules/keybindings/keybind/movement.dm
index 176e6b9fb8..cc5798710c 100644
--- a/code/modules/keybindings/keybind/movement.dm
+++ b/code/modules/keybindings/keybind/movement.dm
@@ -154,7 +154,7 @@
/datum/keybinding/living/toggle_sprint/down(client/user)
var/mob/living/L = user.mob
- L.default_toggle_sprint(TRUE)
+ L.default_toggle_sprint()
return TRUE
/datum/keybinding/mob/toggle_move_intent
diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm
index a53820b5d2..47dbfd855f 100644
--- a/code/modules/keybindings/setup.dm
+++ b/code/modules/keybindings/setup.dm
@@ -1,12 +1,11 @@
/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially
- return
+ SHOULD_NOT_SLEEP(TRUE)
/datum/proc/key_up(key, client/user) // Called when a key is released
- return
+ SHOULD_NOT_SLEEP(TRUE)
/datum/proc/keyLoop(client/user) // Called once every frame
- set waitfor = FALSE
- return
+ SHOULD_NOT_SLEEP(TRUE)
// removes all the existing macros
/client/proc/erase_all_macros()
diff --git a/code/modules/mapping/map_config.dm b/code/modules/mapping/map_config.dm
index c03ef65f43..d18ca1e1e3 100644
--- a/code/modules/mapping/map_config.dm
+++ b/code/modules/mapping/map_config.dm
@@ -43,6 +43,21 @@
/// Orientation to load in by default.
var/orientation = SOUTH //byond defaults to placing everyting SOUTH.
+ /// Jobs whitelist - if this is not empty, ONLY these jobs are allowed. Overrides blacklist.
+ var/list/job_whitelist
+ /// Jobs blacklist - if this is not empty, jobs in this aren't allowed.
+ var/list/job_blacklist
+ /// Job spawn position mod - type = number
+ var/list/job_override_spawn_positions
+ /// Job total position mod - type = number
+ var/list/job_override_total_positions
+ /// Add these accesses to jobs - type = list()
+ var/list/job_access_add
+ /// Remove these accesses from jobs - type = list()
+ var/list/job_access_remove
+ /// Override job accesses - type = list() - overrides everything else
+ var/list/job_access_override
+
/proc/load_map_config(filename = "data/next_map.json", default_to_box, delete_after, error_if_missing = TRUE)
var/datum/map_config/config = new
if (default_to_box)
@@ -161,6 +176,69 @@
allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE
+ if("job_whitelist" in json)
+ job_whitelist = list()
+ for(var/path in json["job_whitelist"])
+ var/type = text2path(path)
+ if(!path)
+ log_config("map datum [config_filename] failed to validate path [path] in job overrides.")
+ continue
+ job_whitelist += type
+
+ if("job_blacklist" in json)
+ job_blacklist = list()
+ for(var/path in json["job_blacklist"])
+ var/type = text2path(path)
+ if(!path)
+ log_config("map datum [config_filename] failed to validate path [path] in job overrides.")
+ continue
+ job_blacklist += type
+
+ if("job_override_spawn_positions" in json)
+ job_override_spawn_positions = list()
+ for(var/path in json["job_override_spawn_positions"])
+ var/type = text2path(path)
+ if(!path)
+ log_config("map datum [config_filename] failed to validate path [path] in job overrides.")
+ continue
+ job_override_spawn_positions += type
+
+ if("job_override_total_positions" in json)
+ job_override_total_positions = list()
+ for(var/path in json["job_override_total_positions"])
+ var/type = text2path(path)
+ if(!path)
+ log_config("map datum [config_filename] failed to validate path [path] in job overrides.")
+ continue
+ job_override_total_positions += type
+
+ if("job_access_add" in json)
+ job_access_add = list()
+ for(var/path in json["job_acces_add"])
+ var/type = text2path(path)
+ if(!path)
+ log_config("map datum [config_filename] failed to validate path [path] in job overrides.")
+ continue
+ job_access_add[type] = json["job_access_add"]
+
+ if("job_access_remove" in json)
+ job_access_remove = list()
+ for(var/path in json["job_acces_add"])
+ var/type = text2path(path)
+ if(!path)
+ log_config("map datum [config_filename] failed to validate path [path] in job overrides.")
+ continue
+ job_access_remove[type] = json["job_access_remove"]
+
+ if("job_access_override" in json)
+ job_access_override = list()
+ for(var/path in json["job_acces_add"])
+ var/type = text2path(path)
+ if(!path)
+ log_config("map datum [config_filename] failed to validate path [path] in job overrides.")
+ continue
+ job_access_override[type] = json["job_access_override"]
+
defaulted = FALSE
return TRUE
#undef CHECK_EXISTS
@@ -190,6 +268,13 @@
jsonlist["announcertype"] = announcertype
jsonlist["orientation"] = orientation
jsonlist["allow_custom_shuttles"] = allow_custom_shuttles
+ jsonlist["job_whitelist"] = job_whitelist
+ jsonlist["job_blacklist"] = job_blacklist
+ jsonlist["job_override_spawn_positions"] = job_override_spawn_positions
+ jsonlist["job_override_total_positions"] = job_override_total_positions
+ jsonlist["job_access_add"] = job_access_add
+ jsonlist["job_access_remove"] = job_access_remove
+ jsonlist["job_access_override"] = job_access_override
if(fexists("data/next_map.json"))
fdel("data/next_map.json")
var/F = file("data/next_map.json")
diff --git a/code/modules/mapping/minimaps.dm b/code/modules/mapping/minimaps.dm
index e0eb174cb3..51fde1f8db 100644
--- a/code/modules/mapping/minimaps.dm
+++ b/code/modules/mapping/minimaps.dm
@@ -134,12 +134,13 @@
return num;
}
window.onload = function() {
- var datas = \[[jointext(datas, ",")]]
- if(!window.HTMLCanvasElement){
- //something has gone horribly wrong!
+ if(!window.HTMLCanvasElement) {
+ var label = document.getElementById("label-1");
+ label.textContent = "WARNING! HTMLCanvasElement not found!
"
return false
}
- for(var i = 0; i < [length(minimaps)]; i++){
+ var datas = \[[jointext(datas, ",")]]
+ for(var i = 0; i < [length(minimaps)]; i++) {
//the fuck is this wrapped?
var data = datas\[i];
var img = document.getElementById("map-" + (i + 1));
@@ -160,13 +161,16 @@
ctx.drawImage(document.getElementById("map-" + (i+1) + "-meta"), 0, 0);
var imagedata = ctx.getImageData(0, 0, img.width, img.height);
- var label = document.getElementById("label-" + (i+1));
+
canvas.onmousemove = function(e){
var rect = canvas.getBoundingClientRect();
var x = Math.floor(e.offsetX * img.width / rect.width);
var y = Math.floor(e.offsetY * img.height / rect.height);
+
var color_idx = x * 4 + (y * 4 * imagedata.width);
var color = "#" + hexify(imagedata.data\[color_idx]) + hexify(imagedata.data\[color_idx+1]) + hexify(imagedata.data\[color_idx+2]);
+ var label = document.getElementById("label-" + (i+1)); //label-String(n)
+
label.textContent = data\[color];
canvas.title = data\[color];
}
diff --git a/code/modules/mapping/ruins.dm b/code/modules/mapping/ruins.dm
index 193106c294..b681c348e0 100644
--- a/code/modules/mapping/ruins.dm
+++ b/code/modules/mapping/ruins.dm
@@ -135,7 +135,12 @@
//That's done remove from priority even if it failed
if(forced)
//TODO : handle forced ruins with multiple variants
+ // this might work?
forced_ruins -= current_pick
+ if(!current_pick.allow_duplicates)
+ for(var/datum/map_template/ruin/R in forced_ruins)
+ if(R.id == current_pick.id)
+ forced_ruins -= R
forced = FALSE
if(failed_to_place)
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index c69e990033..30a933db39 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -11,8 +11,8 @@
/obj/item/survivalcapsule
name = "bluespace shelter capsule"
desc = "An emergency shelter stored within a pocket of bluespace."
- icon_state = "capsule"
icon = 'icons/obj/mining.dmi'
+ icon_state = "capsule"
w_class = WEIGHT_CLASS_TINY
var/template_id = "shelter_alpha"
var/datum/map_template/shelter/template
@@ -72,9 +72,10 @@
/obj/item/survivalcapsule/luxury
name = "luxury bluespace shelter capsule"
desc = "An exorbitantly expensive luxury suite stored within a pocket of bluespace."
+ icon_state = "capsule-lux"
template_id = "shelter_beta"
-/obj/item/survivalcapsule/luxuryelite
+/obj/item/survivalcapsule/luxury/elitebar
name = "luxury elite bar capsule"
desc = "A luxury bar in a capsule. Bartender required and not included."
template_id = "shelter_charlie"
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 2cbb965ef5..ec6a430c0c 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -42,7 +42,7 @@
new /datum/data/mining_equipment("Fulton Pack", /obj/item/extraction_pack, 1000),
new /datum/data/mining_equipment("Lazarus Injector", /obj/item/lazarus_injector, 1000),
new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/pickaxe/silver, 1000),
- new /datum/data/mining_equipment("Mining Conscription Kit", /obj/item/storage/backpack/duffelbag/mining_conscript, 1000),
+ new /datum/data/mining_equipment("Mining Conscription Kit", /obj/item/storage/backpack/duffelbag/mining/conscript, 1000),
new /datum/data/mining_equipment("1000 Point Transfer Card", /obj/item/card/mining_point_card/mp1000, 1000),
new /datum/data/mining_equipment("1500 Point Transfer Card", /obj/item/card/mining_point_card/mp1500, 1500),
new /datum/data/mining_equipment("2000 Point Transfer Card", /obj/item/card/mining_point_card/mp2000, 2000),
@@ -55,7 +55,7 @@
new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500),
new /datum/data/mining_equipment("Ice hiking boots", /obj/item/clothing/shoes/winterboots/ice_boots, 2500),
new /datum/data/mining_equipment("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 3000),
- new /datum/data/mining_equipment("Luxury Bar Capsule", /obj/item/survivalcapsule/luxuryelite, 10000),
+ new /datum/data/mining_equipment("Luxury Bar Capsule", /obj/item/survivalcapsule/luxury/elitebar, 10000),
new /datum/data/mining_equipment("Nanotrasen Minebot", /mob/living/simple_animal/hostile/mining_drone, 800),
new /datum/data/mining_equipment("Minebot Melee Upgrade", /obj/item/mine_bot_upgrade, 400),
new /datum/data/mining_equipment("Minebot Armor Upgrade", /obj/item/mine_bot_upgrade/health, 400),
@@ -70,9 +70,10 @@
new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000),
new /datum/data/mining_equipment("KA Cooldown Decrease", /obj/item/borg/upgrade/modkit/cooldown, 1000),
new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000),
- new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining_cloned, 3000),
+ new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining/cloned, 3000),
new /datum/data/mining_equipment("Premium Accelerator", /obj/item/gun/energy/kinetic_accelerator/premiumka, 8000),
- new /datum/data/mining_equipment("Kinetic Glaive", /obj/item/kinetic_crusher/glaive, 2250),
+ new /datum/data/mining_equipment("Kinetic Glaive Kit", /obj/item/storage/backpack/duffelbag/mining/glaivekit, 2250),
+ new /datum/data/mining_equipment("Survival Dagger", /obj/item/kitchen/knife/combat/survival/knuckledagger, 550),
)
/datum/data/mining_equipment
@@ -222,7 +223,7 @@
new /obj/item/extinguisher/mini(drop_location)
new /obj/item/kinetic_crusher(drop_location)
if("Mining Conscription Kit")
- new /obj/item/storage/backpack/duffelbag/mining_conscript(drop_location)
+ new /obj/item/storage/backpack/duffelbag/mining/conscript(drop_location)
SSblackbox.record_feedback("tally", "mining_voucher_redeemed", 1, selection)
qdel(voucher)
@@ -328,11 +329,11 @@
to_chat(user, "You upgrade [I] with mining access.")
qdel(src)
-/obj/item/storage/backpack/duffelbag/mining_conscript
+/obj/item/storage/backpack/duffelbag/mining/conscript
name = "mining conscription kit"
desc = "A kit containing everything a crewmember needs to support a shaft miner in the field."
-/obj/item/storage/backpack/duffelbag/mining_conscript/PopulateContents()
+/obj/item/storage/backpack/duffelbag/mining/conscript/PopulateContents()
new /obj/item/pickaxe/mini(src)
new /obj/item/clothing/glasses/meson(src)
new /obj/item/t_scanner/adv_mining_scanner/lesser(src)
@@ -347,11 +348,11 @@
//CITADEL ADDITIONS BELOW
-/obj/item/storage/backpack/duffelbag/mining_cloned
+/obj/item/storage/backpack/duffelbag/mining/cloned
name = "mining replacement kit"
- desc = "A large bag that has advance tools and a spare jumpsuit, boots, and gloves for a newly cloned miner to get back in the field. Even has a new ID!"
+ desc = "A large bag that has advanced tools and a spare jumpsuit, boots, and gloves for a newly cloned miner to get back in the field. Even has a new ID!"
-/obj/item/storage/backpack/duffelbag/mining_cloned/PopulateContents()
+/obj/item/storage/backpack/duffelbag/mining/cloned/PopulateContents()
new /obj/item/pickaxe/mini(src)
new /obj/item/clothing/under/rank/cargo/miner/lavaland(src)
new /obj/item/clothing/shoes/workboots/mining(src)
@@ -369,6 +370,12 @@
new /obj/item/storage/bag/ore(src)
new /obj/item/clothing/glasses/meson/prescription(src)
+/obj/item/storage/backpack/duffelbag/mining/glaivekit
+
+/obj/item/storage/backpack/duffelbag/mining/glaivekit/PopulateContents()
+ new /obj/item/kinetic_crusher/glaive(src)
+ new /obj/item/kitchen/knife/combat/survival/knuckledagger(src)
+
/obj/machinery/mineral/equipment_vendor/proc/RedeemSVoucher(obj/item/suit_voucher/voucher, mob/redeemer)
var/items = list( "Exo-suit" = image(icon = 'icons/obj/clothing/suits.dmi', icon_state = "exo"),
"SEVA suit" = image(icon = 'icons/obj/clothing/suits.dmi', icon_state = "seva"))
diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm
index c3c0787aa8..2e1ffe718f 100644
--- a/code/modules/mob/dead/new_player/preferences_setup.dm
+++ b/code/modules/mob/dead/new_player/preferences_setup.dm
@@ -26,7 +26,8 @@
features = random_features(pref_species?.id, gender)
age = rand(AGE_MIN,AGE_MAX)
-/datum/preferences/proc/update_preview_icon(equip_job = TRUE)
+/datum/preferences/proc/update_preview_icon(current_tab)
+ var/equip_job = (current_tab != 2)
// Determine what job is marked as 'High' priority, and dress them up as such.
var/datum/job/previewJob = get_highest_job()
@@ -45,9 +46,13 @@
mannequin.add_overlay(mutable_appearance('modular_citadel/icons/ui/backgrounds.dmi', bgstate, layer = SPACE_LAYER))
copy_to(mannequin, initial_spawn = TRUE)
- if(previewJob && equip_job)
- mannequin.job = previewJob.title
- previewJob.equip(mannequin, TRUE, preference_source = parent)
+ if(current_tab == 3)
+ //give it its loadout if not on the appearance tab
+ SSjob.equip_loadout(parent.mob, mannequin, FALSE, bypass_prereqs = TRUE, can_drop = FALSE)
+ else
+ if(previewJob && equip_job)
+ mannequin.job = previewJob.title
+ previewJob.equip(mannequin, TRUE, preference_source = parent)
COMPILE_OVERLAYS(mannequin)
parent.show_character_previews(new /mutable_appearance(mannequin))
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm
index a07fdaa5d3..23b1f87bd2 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm
@@ -2,7 +2,7 @@
// Facial Hair Definitions //
/////////////////////////////
/datum/sprite_accessory/facial_hair
- icon = 'icons/mob/human_face.dmi'
+ icon = 'icons/mob/hair.dmi'
gender = MALE // barf (unless you're a dorf, dorfs dig chix w/ beards :P)
// please make sure they're sorted alphabetically and categorized
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm
index 8e4e6ad617..55ab18c20c 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm
@@ -2,7 +2,7 @@
// Hair Definitions //
//////////////////////
/datum/sprite_accessory/hair
- icon = 'icons/mob/human_face.dmi' // default icon for all hairs
+ icon = 'icons/mob/hair.dmi' // default icon for all hairs
// please make sure they're sorted alphabetically and, where needed, categorized
// try to capitalize the names please~
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index e1d078c632..0c57c13e3f 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -408,7 +408,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(mind.current.key && mind.current.key[1] != "@") //makes sure we don't accidentally kick any clients
to_chat(usr, "Another consciousness is in your body...It is resisting you.")
return
- client.change_view(CONFIG_GET(string/default_view))
+ client.view_size.setDefault(getScreenSize(client.prefs.widescreenpref))//Let's reset so people can't become allseeing gods
transfer_ckey(mind.current, FALSE)
SStgui.on_transfer(src, mind.current) // Transfer NanoUIs.
mind.current.client.init_verbs()
@@ -568,15 +568,15 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set desc = "Change your view range."
var/max_view = client.prefs.unlock_content ? GHOST_MAX_VIEW_RANGE_MEMBER : GHOST_MAX_VIEW_RANGE_DEFAULT
- if(client.view == CONFIG_GET(string/default_view))
+ if(client.view_size.getView() == client.view_size.default)
var/list/views = list()
for(var/i in 7 to max_view)
views |= i
- var/new_view = input("Choose your new view", "Modify view range", 7) as null|anything in views
+ var/new_view = input("Choose your new view", "Modify view range", 0) as null|anything in views
if(new_view)
- client.change_view(clamp(new_view, 7, max_view))
+ client.view_size.setTo(clamp(new_view, 7, max_view) - 7)
else
- client.change_view(CONFIG_GET(string/default_view))
+ client.view_size.resetToDefault()
/mob/dead/observer/verb/add_view_range(input as num)
set name = "Add View Range"
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 1706763f6b..26486f255a 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -191,8 +191,8 @@
if(HAS_TRAIT(src, TRAIT_PACIFISM))
to_chat(src, "You gently let go of [throwable_mob].")
return
-
- adjustStaminaLossBuffered(STAM_COST_THROW_MOB * ((throwable_mob.mob_size+1)**2))// throwing an entire person shall be very tiring
+ if(!UseStaminaBuffer(STAM_COST_THROW_MOB * ((throwable_mob.mob_size+1)**2), TRUE))
+ return
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
var/turf/end_T = get_turf(target)
if(start_T && end_T)
@@ -206,7 +206,8 @@
to_chat(src, "You set [I] down gently on the ground.")
return
- adjustStaminaLossBuffered(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST))
+ if(!UseStaminaBuffer(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST), warn = TRUE))
+ return
if(thrown_thing)
var/power_throw = 0
@@ -594,15 +595,23 @@
remove_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit)
/mob/living/carbon/update_stamina()
- var/stam = getStaminaLoss()
- if(stam > DAMAGE_PRECISION)
- var/total_health = (maxHealth - stam)
- if(total_health <= crit_threshold && !stat)
- if(CHECK_MOBILITY(src, MOBILITY_STAND))
- to_chat(src, "You're too exhausted to keep going...")
- KnockToFloor(TRUE)
- update_health_hud()
-
+ var/total_health = getStaminaLoss()
+ if(total_health)
+ if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health >= STAMINA_CRIT && !stat)
+ to_chat(src, "You're too exhausted to keep going...")
+ set_resting(TRUE, FALSE, FALSE)
+ SEND_SIGNAL(src, COMSIG_DISABLE_COMBAT_MODE)
+ ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT)
+ filters += CIT_FILTER_STAMINACRIT
+ update_mobility()
+ if((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health <= STAMINA_CRIT)
+ to_chat(src, "You don't feel nearly as exhausted anymore.")
+ DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT)
+ filters -= CIT_FILTER_STAMINACRIT
+ update_mobility()
+ UpdateStaminaBuffer()
+ update_health_hud()
+
/mob/living/carbon/update_sight()
if(!client)
return
@@ -979,30 +988,15 @@
O.held_index = r_arm_index_next //2, 4, 6, 8...
hand_bodyparts += O
-/mob/living/carbon/do_after_coefficent()
- . = ..()
- var/datum/component/mood/mood = src.GetComponent(/datum/component/mood) //Currently, only carbons or higher use mood, move this once that changes.
- if(mood)
- switch(mood.sanity) //Alters do_after delay based on how sane you are
- if(SANITY_INSANE to SANITY_DISTURBED)
- . *= 1.25
- if(SANITY_NEUTRAL to SANITY_GREAT)
- . *= 0.90
-
- for(var/i in status_effects)
- var/datum/status_effect/S = i
- . *= S.interact_speed_modifier()
-
-
/mob/living/carbon/proc/create_internal_organs()
for(var/X in internal_organs)
var/obj/item/organ/I = X
I.Insert(src)
-/mob/living/carbon/proc/update_disabled_bodyparts()
+/mob/living/carbon/proc/update_disabled_bodyparts(silent = FALSE)
for(var/B in bodyparts)
var/obj/item/bodypart/BP = B
- BP.update_disabled()
+ BP.update_disabled(silent)
/mob/living/carbon/vv_get_dropdown()
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index ce6aa71f67..710d49c075 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -254,10 +254,10 @@
if(href_list["pockets"])
var/strip_mod = 1
var/strip_silence = FALSE
- var/obj/item/clothing/gloves/g = gloves
- if (istype(g))
- strip_mod = g.strip_mod
- strip_silence = g.strip_silence
+ var/obj/item/clothing/gloves/G = gloves
+ if(istype(G))
+ strip_mod = G.strip_mod
+ strip_silence = G.strip_silence
var/pocket_side = href_list["pockets"]
var/pocket_id = (pocket_side == "right" ? SLOT_R_STORE : SLOT_L_STORE)
var/obj/item/pocket_item = (pocket_id == SLOT_R_STORE ? r_store : l_store)
@@ -805,7 +805,7 @@
hud_used.healthdoll.icon_state = "healthdoll_DEAD"
hud_used.staminas?.update_icon_state()
- hud_used.staminabuffer?.update_icon_state()
+ hud_used.staminabuffer?.mark_dirty()
/mob/living/carbon/human/fully_heal(admin_revive = FALSE)
if(admin_revive)
@@ -1044,9 +1044,9 @@
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
return
- var/stambufferinfluence = (bufferedstam*(100/stambuffer))*0.2 //CIT CHANGE - makes stamina buffer influence movedelay
if(!HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN)) //if we want to ignore slowdown from damage, but not from equipment
- var/health_deficiency = ((maxHealth + stambufferinfluence) - health + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it
+ var/scaling = maxHealth / 100
+ var/health_deficiency = ((maxHealth / scaling) - (health / scaling) + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it
if(health_deficiency >= 40)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, (health_deficiency-39) / 75)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, (health_deficiency-39) / 25)
@@ -1057,11 +1057,6 @@
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
-
-/mob/living/carbon/human/do_after_coefficent()
- . = ..()
- . *= physiology.do_after_speed
-
/mob/living/carbon/human/is_bleeding()
if(NOBLOOD in dna.species.species_traits || bleedsuppress)
return FALSE
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index a6a3f408dc..89a4570e8d 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -7,7 +7,7 @@
buckle_lying = FALSE
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
/// Enable stamina combat
- combat_flags = COMBAT_FLAGS_DEFAULT | COMBAT_FLAG_UNARMED_PARRY
+ combat_flags = COMBAT_FLAGS_STAMINA_COMBAT | COMBAT_FLAG_UNARMED_PARRY
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
has_field_of_vision = FALSE //Handled by species.
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index bcb658eab8..97c40c96d7 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -11,11 +11,6 @@
/mob/living/carbon/human/movement_delay()
. = ..()
- if(CHECK_MOBILITY(src, MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE))
- var/static/datum/config_entry/number/movedelay/sprint_speed_increase/SSI
- if(!SSI)
- SSI = CONFIG_GET_ENTRY(number/movedelay/sprint_speed_increase)
- . -= SSI.config_entry_value
if (m_intent == MOVE_INTENT_WALK && HAS_TRAIT(src, TRAIT_SPEEDY_STEP))
. -= 1.5
@@ -61,7 +56,11 @@
HM.on_move(NewLoc)
if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && (!pulledby || (pulledby.pulledby == src)))
if(!HAS_TRAIT(src, TRAIT_FREESPRINT))
- doSprintLossTiles(1)
+ var/datum/movespeed_modifier/equipment_speedmod/MM = get_movespeed_modifier_datum(/datum/movespeed_modifier/equipment_speedmod)
+ var/amount = 1
+ if(MM?.multiplicative_slowdown >= 1)
+ amount *= (1 + (6 - (3 / MM.multiplicative_slowdown)))
+ doSprintLossTiles(amount)
if((oldpseudoheight - pseudo_z_axis) >= 8)
to_chat(src, "You trip off of the elevated surface!")
for(var/obj/item/I in held_items)
@@ -101,3 +100,8 @@
if(dna.species.space_move(src))
return TRUE
return ..()
+
+/mob/living/carbon/human/CanPass(atom/movable/mover, turf/target)
+ if(dna.species.species_pass_check())
+ return TRUE
+ return ..()
diff --git a/code/modules/mob/living/carbon/human/physiology.dm b/code/modules/mob/living/carbon/human/physiology.dm
index fd0df0bde9..22c197f7de 100644
--- a/code/modules/mob/living/carbon/human/physiology.dm
+++ b/code/modules/mob/living/carbon/human/physiology.dm
@@ -23,8 +23,6 @@
var/hunger_mod = 1 //% of hunger rate taken per tick.
- var/do_after_speed = 1 //Speed mod for do_after. Lower is better. If temporarily adjusting, please only modify using *= and /=, so you don't interrupt other calculations.
-
/// footstep type override for both shoeless and not footstep sounds.
var/footstep_type
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 6161d0582c..d445274f36 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -64,7 +64,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/stunmod = 1 // multiplier for stun duration
var/punchdamagelow = 1 //lowest possible punch damage. if this is set to 0, punches will always miss
var/punchdamagehigh = 10 //highest possible punch damage
- var/punchstunthreshold = 10//damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical
+ var/punchstunthreshold = 10 //damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical
+ var/punchwoundbonus = 0 // additional wound bonus. generally zero.
var/siemens_coeff = 1 //base electrocution coefficient
var/damage_overlay_type = "human" //what kind of damage overlays (if any) appear on our species when wounded?
var/fixed_mut_color = "" //to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"]
@@ -106,7 +107,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/whitelisted = 0 //Is this species restricted to certain players?
var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both.
var/icon_limbs //Overrides the icon used for the limbs of this species. Mainly for downstream, and also because hardcoded icons disgust me. Implemented and maintained as a favor in return for a downstream's implementation of synths.
- var/species_type
+ var/species_category
var/tail_type //type of tail i.e. mam_tail
var/wagging_type //type of wagging i.e. waggingtail_lizard
@@ -118,6 +119,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/list/allowed_limb_ids
var/override_bp_icon //override for the icon path used when setting bodypart overlays. Intended for species that don't fit in the standard 32x32 files.
+ //the type of eyes this species has
+ var/eye_type = "normal"
///////////
// PROCS //
@@ -514,7 +517,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/mutable_appearance/hair_overlay = mutable_appearance(layer = -HAIR_LAYER)
if(!hair_hidden && !H.getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain
if(!(NOBLOOD in species_traits))
- hair_overlay.icon = 'icons/mob/human_face.dmi'
+ hair_overlay.icon = 'icons/mob/hair.dmi'
hair_overlay.icon_state = "debrained"
else if(H.hair_style && (HAIR in species_traits))
@@ -573,7 +576,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(HD && !(HAS_TRAIT(H, TRAIT_HUSK)))
// lipstick
if(H.lip_style && (LIPS in species_traits))
- var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER)
+ var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/lips.dmi', "lips_[H.lip_style]", -BODY_LAYER)
lip_overlay.color = H.lip_color
if(OFFSET_LIPS in H.dna.species.offset_features)
@@ -586,10 +589,15 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!(NOEYES in species_traits))
var/has_eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(!has_eyes)
- standing += mutable_appearance('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER)
+ standing += mutable_appearance('icons/mob/eyes.dmi', "eyes_missing", -BODY_LAYER)
else
- var/mutable_appearance/left_eye = mutable_appearance('icons/mob/human_face.dmi', "left_eye", -BODY_LAYER)
- var/mutable_appearance/right_eye = mutable_appearance('icons/mob/human_face.dmi', "right_eye", -BODY_LAYER)
+ var/left_state = DEFAULT_LEFT_EYE_STATE
+ var/right_state = DEFAULT_RIGHT_EYE_STATE
+ if(eye_type in GLOB.eye_types)
+ left_state = eye_type + "_left_eye"
+ right_state = eye_type + "_right_eye"
+ var/mutable_appearance/left_eye = mutable_appearance('icons/mob/eyes.dmi', left_state, -BODY_LAYER)
+ var/mutable_appearance/right_eye = mutable_appearance('icons/mob/eyes.dmi', right_state, -BODY_LAYER)
if((EYECOLOR in species_traits) && has_eyes)
left_eye.color = "#" + H.left_eye_color
right_eye.color = "#" + H.right_eye_color
@@ -1357,9 +1365,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK))
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
- user.adjustStaminaLossBuffered(1.5)
- else
- user.adjustStaminaLossBuffered(3.5)
+ if(!user.UseStaminaBuffer(1.5, warn = TRUE))
+ return
+ else if(!user.UseStaminaBuffer(3.5, warn = TRUE))
+ return
if(attacker_style && attacker_style.harm_act(user,target))
return TRUE
@@ -1380,6 +1389,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
user.do_attack_animation(target, ATTACK_EFFECT_PUNCH)
var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh)
+ var/punchwoundbonus = user.dna.species.punchwoundbonus
var/puncherstam = user.getStaminaLoss()
var/puncherbrute = user.getBruteLoss()
var/punchedstam = target.getStaminaLoss()
@@ -1395,6 +1405,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//END OF CITADEL CHANGES
var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
+ if(HAS_TRAIT(user, TRAIT_PUGILIST))
+ affecting = target.get_bodypart(check_zone(user.zone_selected)) // if you're going the based unarmed route you won't miss
if(!affecting) //Maybe the bodypart is missing? Or things just went wrong..
affecting = target.get_bodypart(BODY_ZONE_CHEST) //target chest instead, as failsafe. Or hugbox? You decide.
@@ -1406,8 +1418,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(user.dna.species.punchdamagelow)
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
miss_chance = 0
- else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance
- miss_chance = 10
+ else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists, being good at Punching People, also never miss
+ miss_chance = 0
else
miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob()
@@ -1421,12 +1433,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/armor_block = target.run_armor_check(affecting, "melee")
+ if(HAS_TRAIT(user, TRAIT_MAULER)) // maulers get 15 armorpierce because if you're going to punch someone you might as well do a good job of it
+ armor_block = target.run_armor_check(affecting, "melee", armour_penetration = 15) // lot of good that sec jumpsuit did you
playsound(target.loc, user.dna.species.attack_sound, 25, 1, -1)
-
- target.visible_message("[user] [atk_verb]s [target]!", \
- "[user] [atk_verb]s you!", null, COMBAT_MESSAGE_RANGE, null, \
- user, "You [atk_verb] [target]!")
+ target.visible_message("[user] [atk_verb]ed [target]!", \
+ "[user] [atk_verb]ed you!", null, COMBAT_MESSAGE_RANGE, null, \
+ user, "You [atk_verb]ed [target]!")
target.lastattacker = user.real_name
target.lastattackerckey = user.ckey
@@ -1436,11 +1449,15 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.dismembering_strike(user, affecting.body_zone)
if(atk_verb == ATTACK_EFFECT_KICK)//kicks deal 1.5x raw damage + 0.5x stamina damage
- target.apply_damage(damage*1.5, attack_type, affecting, armor_block)
+ target.apply_damage(damage*1.5, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
log_combat(user, target, "kicked")
- else//other attacks deal full raw damage + 2x in stamina damage
- target.apply_damage(damage, attack_type, affecting, armor_block)
+ else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.3x raw damage + 1x stam damage, and have some armor pierce
+ target.apply_damage(damage*1.3, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
+ target.apply_damage(damage, STAMINA, affecting, armor_block)
+ log_combat(user, target, "punched (mauler)")
+ else //other attacks deal full raw damage + 2x in stamina damage
+ target.apply_damage(damage, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
target.apply_damage(damage*2, STAMINA, affecting, armor_block)
log_combat(user, target, "punched")
@@ -1490,6 +1507,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
return FALSE
else if(aim_for_mouth && ( target_on_help || target_restrained || target_aiming_for_mouth))
+ if(!user.UseStaminaBuffer(3, warn = TRUE))
+ return
playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1)
target.visible_message(\
@@ -1497,7 +1516,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
"[user] slaps you in the face! ",\
"You hear a slap.", target = user, target_message = "You slap [user == target ? "yourself" : "\the [target]"] in the face! ")
user.do_attack_animation(target, ATTACK_EFFECT_FACE_SLAP)
- user.adjustStaminaLossBuffered(3)
if (!HAS_TRAIT(target, TRAIT_PERMABONER))
stop_wagging_tail(target)
return FALSE
@@ -1505,8 +1523,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(target.client?.prefs.cit_toggles & NO_ASS_SLAP)
to_chat(user,"A force stays your hand, preventing you from slapping \the [target]'s ass!")
return FALSE
+ if(!user.UseStaminaBuffer(3, warn = TRUE))
+ return FALSE
user.do_attack_animation(target, ATTACK_EFFECT_ASS_SLAP)
- user.adjustStaminaLossBuffered(3)
target.adjust_arousal(20,maso = TRUE)
if (ishuman(target) && HAS_TRAIT(target, TRAIT_MASO) && target.has_dna() && prob(10))
target.mob_climax(forced_climax=TRUE)
@@ -1524,9 +1543,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes disarmspam cause staminaloss, pugilists can do it almost effortlessly
- user.adjustStaminaLossBuffered(1)
+ if(!user.UseStaminaBuffer(1, warn = TRUE))
+ return
else
- user.adjustStaminaLossBuffered(3)
+ if(!user.UseStaminaBuffer(1, warn = TRUE))
+ return
if(attacker_style && attacker_style.disarm_act(user,target))
return TRUE
@@ -1762,9 +1783,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(CHECK_MOBILITY(user, MOBILITY_STAND))
to_chat(user, "You can only force yourself up if you're on the ground.")
return
+ if(!user.UseStaminaBuffer(STAMINA_COST_SHOVE_UP, TRUE))
+ return
user.visible_message("[user] forces [p_them()]self up to [p_their()] feet!", "You force yourself up to your feet!")
user.set_resting(FALSE, TRUE)
- user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting
playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
/datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
@@ -1783,8 +1805,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
else
if(user == target)
return
+ if(!user.UseStaminaBuffer(4, warn = TRUE))
+ return
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
- user.adjustStaminaLossBuffered(4)
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
if(target.w_uniform)
@@ -1941,6 +1964,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(HAS_BONE in species_traits)
. |= BIO_JUST_BONE
+//a check for if you should render any overlays or not
+/datum/species/proc/should_render(mob/living/carbon/human/H)
+ return TRUE
+
+//a check for if you want to forcibly make CanPass return TRUE for the mob with this species
+/datum/species/proc/species_pass_check()
+ return FALSE
+
/////////////
//BREATHING//
/////////////
diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductor.dm
similarity index 90%
rename from code/modules/mob/living/carbon/human/species_types/abductors.dm
rename to code/modules/mob/living/carbon/human/species_types/abductor.dm
index 38e10e8662..004ba267e8 100644
--- a/code/modules/mob/living/carbon/human/species_types/abductors.dm
+++ b/code/modules/mob/living/carbon/human/species_types/abductor.dm
@@ -1,12 +1,12 @@
/datum/species/abductor
name = "Abductor"
- id = "abductor"
+ id = SPECIES_ABDUCTOR
say_mod = "gibbers"
sexes = FALSE
species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_CHUNKYFINGERS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
mutanttongue = /obj/item/organ/tongue/abductor
- species_type = "alien"
+ species_category = SPECIES_CATEGORY_ALIEN
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm
index 5d43d18429..7f755ce027 100644
--- a/code/modules/mob/living/carbon/human/species_types/android.dm
+++ b/code/modules/mob/living/carbon/human/species_types/android.dm
@@ -1,6 +1,6 @@
/datum/species/android
name = "Android"
- id = "android"
+ id = SPECIES_ANDROID
say_mod = "states"
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,ROBOTIC_LIMBS)
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT)
@@ -11,7 +11,7 @@
mutanttongue = /obj/item/organ/tongue/robot
species_language_holder = /datum/language_holder/synthetic
limbs_id = "synth"
- species_type = "robotic"
+ species_category = SPECIES_CATEGORY_ROBOT
/datum/species/android/on_species_gain(mob/living/carbon/C)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/angel.dm b/code/modules/mob/living/carbon/human/species_types/angel.dm
index 3cae574a90..9c87f3ad5d 100644
--- a/code/modules/mob/living/carbon/human/species_types/angel.dm
+++ b/code/modules/mob/living/carbon/human/species_types/angel.dm
@@ -1,6 +1,6 @@
/datum/species/angel
name = "Angel"
- id = "angel"
+ id = SPECIES_ANGEL
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "wings" = "Angel")
@@ -9,7 +9,7 @@
blacklisted = 1
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
- species_type = "human" //they're a kind of human
+ species_category = SPECIES_CATEGORY_BASIC //they're a kind of human
var/datum/action/innate/flight/fly
diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/anthromorph.dm
similarity index 87%
rename from code/modules/mob/living/carbon/human/species_types/furrypeople.dm
rename to code/modules/mob/living/carbon/human/species_types/anthromorph.dm
index 534536d6e7..95aec26d9f 100644
--- a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/anthromorph.dm
@@ -1,6 +1,6 @@
/datum/species/mammal
name = "Anthromorph"
- id = "mammal"
+ id = SPECIES_MAMMAL
default_color = "4B4B4B"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BEAST
@@ -15,6 +15,6 @@
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
- species_type = "furry"
+ species_category = SPECIES_CATEGORY_FURRY
- allowed_limb_ids = list("mammal","aquatic","avian")
\ No newline at end of file
+ allowed_limb_ids = list("mammal","aquatic","avian")
diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
index 16b371c772..773651d464 100644
--- a/code/modules/mob/living/carbon/human/species_types/bugmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
@@ -1,6 +1,6 @@
/datum/species/insect
name = "Anthromorphic Insect"
- id = "insect"
+ id = SPECIES_INSECT
say_mod = "chitters"
default_color = "00FF00"
species_traits = list(LIPS,EYECOLOR,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
@@ -18,6 +18,8 @@
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
- species_type = "insect"
+ species_category = SPECIES_CATEGORY_INSECT
allowed_limb_ids = list("insect","apid","moth","moth_not_greyscale")
+
+ eye_type = "insect"
diff --git a/code/modules/mob/living/carbon/human/species_types/corporate.dm b/code/modules/mob/living/carbon/human/species_types/corporate.dm
index a2597ed286..e9baa786da 100644
--- a/code/modules/mob/living/carbon/human/species_types/corporate.dm
+++ b/code/modules/mob/living/carbon/human/species_types/corporate.dm
@@ -18,4 +18,4 @@
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER)
sexes = 0
gib_types = /obj/effect/gibspawner/robot
- species_type = "robotic"
\ No newline at end of file
+ species_category = SPECIES_CATEGORY_ROBOT
diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
index f3b499093b..f756fd8816 100644
--- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
@@ -1,6 +1,6 @@
/datum/species/dullahan
name = "Dullahan"
- id = "dullahan"
+ id = SPECIES_DULLAHAN
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
@@ -14,7 +14,7 @@
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
has_field_of_vision = FALSE //Too much of a trouble, their vision is already bound to their severed head.
- species_type = "undead"
+ species_category = SPECIES_CATEGORY_UNDEAD
var/pumpkin = FALSE
var/obj/item/dullahan_relay/myhead
diff --git a/code/modules/mob/living/carbon/human/species_types/dwarves.dm b/code/modules/mob/living/carbon/human/species_types/dwarves.dm
index a465e7c3a9..ce67a947de 100644
--- a/code/modules/mob/living/carbon/human/species_types/dwarves.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dwarves.dm
@@ -4,7 +4,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
/datum/species/dwarf //not to be confused with the genetic manlets
name = "Dwarf"
- id = "dwarf" //Also called Homo sapiens pumilionis
+ id = SPECIES_DWARF //Also called Homo sapiens pumilionis
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_DWARF,TRAIT_SNOB)
@@ -18,7 +18,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
mutant_organs = list(/obj/item/organ/dwarfgland) //Dwarven alcohol gland, literal gland warrior
mutantliver = /obj/item/organ/liver/dwarf //Dwarven super liver (Otherwise they r doomed)
species_language_holder = /datum/language_holder/dwarf
- species_type = "human" //a kind of human
+ species_category = SPECIES_CATEGORY_BASIC //a kind of human
/mob/living/carbon/human/species/dwarf //species admin spawn path
race = /datum/species/dwarf //and the race the path is set to.
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index c182defda4..d92f4ab14a 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -2,7 +2,7 @@
/datum/species/ethereal
name = "Ethereal"
- id = "ethereal"
+ id = SPECIES_ETHEREAL
attack_verb = "burn"
attack_sound = 'sound/weapons/etherealhit.ogg'
miss_sound = 'sound/weapons/etherealmiss.ogg'
diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm
index b760fd0aee..011b6b7642 100644
--- a/code/modules/mob/living/carbon/human/species_types/felinid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm
@@ -1,7 +1,7 @@
//Subtype of human
/datum/species/human/felinid
name = "Felinid"
- id = "felinid"
+ id = SPECIES_FELINID
limbs_id = "human"
mutant_bodyparts = list("mam_tail" = "Cat", "mam_ears" = "Cat", "deco_wings" = "None")
@@ -11,7 +11,7 @@
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
- species_type = "furry"
+ species_category = SPECIES_CATEGORY_FURRY
/datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
if(ishuman(C))
diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
index c56adaf1b0..c3e406244b 100644
--- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
@@ -1,6 +1,6 @@
/datum/species/fly
name = "Anthromorphic Fly"
- id = "fly"
+ id = SPECIES_FLY
say_mod = "buzzes"
species_traits = list(NOEYES,HAS_FLESH,HAS_BONE)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
@@ -12,7 +12,7 @@
liked_food = GROSS
exotic_bloodtype = "BUG"
exotic_blood_color = BLOOD_COLOR_BUG
- species_type = "insect"
+ species_category = SPECIES_CATEGORY_INSECT
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
if(istype(chem, /datum/reagent/toxin/pestkiller))
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 438eaf1eea..ff0287d7b9 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -1,7 +1,7 @@
/datum/species/golem
// Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck.
name = "Golem"
- id = "iron golem"
+ id = SPECIES_GOLEM
species_traits = list(NOBLOOD,MUTCOLORS,NO_UNDERWEAR,NOGENITALS,NOAROUSAL)
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
inherent_biotypes = MOB_HUMANOID|MOB_MINERAL
@@ -32,7 +32,7 @@
var/special_name_chance = 5
var/owner //dobby is a free golem
- species_type = "golem"
+ species_category = SPECIES_CATEGORY_GOLEM
/datum/species/golem/random_name(gender,unique,lastname)
var/golem_surname = pick(GLOB.golem_names)
diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm
index f175ddb921..e8e0ff1a78 100644
--- a/code/modules/mob/living/carbon/human/species_types/humans.dm
+++ b/code/modules/mob/living/carbon/human/species_types/humans.dm
@@ -1,6 +1,6 @@
/datum/species/human
name = "Human"
- id = "human"
+ id = SPECIES_HUMAN
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR,HAS_FLESH,HAS_BONE)
@@ -12,7 +12,7 @@
tail_type = "tail_human"
wagging_type = "waggingtail_human"
- species_type = "human"
+ species_category = SPECIES_CATEGORY_BASIC
/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
diff --git a/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm
index 9bfe661f47..6353fd5184 100644
--- a/code/modules/mob/living/carbon/human/species_types/ipc.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm
@@ -1,6 +1,6 @@
/datum/species/ipc
name = "I.P.C."
- id = "ipc"
+ id = SPECIES_IPC
say_mod = "beeps"
default_color = "00FF00"
blacklisted = 0
@@ -28,7 +28,7 @@
exotic_bloodtype = "HF"
exotic_blood_color = BLOOD_COLOR_OIL
- species_type = "robotic"
+ species_category = SPECIES_CATEGORY_ROBOT
var/datum/action/innate/monitor_change/screen
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 38f3111a23..58a10fb08e 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -1,7 +1,7 @@
/datum/species/jelly
// Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them.
name = "Xenobiological Jelly Entity"
- id = "jelly"
+ id = SPECIES_JELLY
default_color = "00FF90"
say_mod = "chirps"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR,HAS_FLESH)
@@ -16,7 +16,8 @@
exotic_blood_color = "BLOOD_COLOR_SLIME"
damage_overlay_type = ""
var/datum/action/innate/regenerate_limbs/regenerate_limbs
- var/datum/action/innate/slime_change/slime_change //CIT CHANGE
+ var/datum/action/innate/slime_change/slime_change
+ var/datum/action/innate/slime_puddle/slime_puddle
liked_food = TOXIC | MEAT
disliked_food = null
toxic_food = ANTITOXIC
@@ -28,19 +29,22 @@
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
- species_type = "jelly"
+ species_category = SPECIES_CATEGORY_JELLY
/obj/item/organ/brain/jelly
name = "slime nucleus"
desc = "A slimey membranous mass from a slime person"
icon_state = "brain-slime"
-
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
+ if(slime_puddle && slime_puddle.is_puddle)
+ slime_puddle.Activate()
if(regenerate_limbs)
regenerate_limbs.Remove(C)
- if(slime_change) //CIT CHANGE
- slime_change.Remove(C) //CIT CHANGE
+ if(slime_change)
+ slime_change.Remove(C)
+ if(slime_puddle)
+ slime_puddle.Remove(C)
C.faction -= "slime"
..()
C.faction -= "slime"
@@ -50,8 +54,10 @@
if(ishuman(C))
regenerate_limbs = new
regenerate_limbs.Grant(C)
- slime_change = new //CIT CHANGE
- slime_change.Grant(C) //CIT CHANGE
+ slime_change = new
+ slime_change.Grant(C)
+ slime_puddle = new
+ slime_puddle.Grant(C)
C.faction |= "slime"
/datum/species/jelly/handle_body(mob/living/carbon/human/H)
@@ -59,6 +65,18 @@
//update blood color to body color
exotic_blood_color = "#" + H.dna.features["mcolor"]
+/datum/species/jelly/should_render()
+ if(slime_puddle && slime_puddle.is_puddle)
+ return FALSE
+ else
+ return ..()
+
+/datum/species/jelly/species_pass_check()
+ if(slime_puddle && slime_puddle.is_puddle)
+ return TRUE
+ else
+ return ..()
+
/datum/species/jelly/spec_life(mob/living/carbon/human/H)
if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for blooduskers
return
@@ -140,7 +158,7 @@
/datum/species/jelly/slime
name = "Xenobiological Slime Entity"
- id = "slime"
+ id = SPECIES_SLIME
default_color = "00FFFF"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
say_mod = "says"
@@ -274,7 +292,17 @@
\"steps out\" of [H.p_them()].",
"...and after a moment of disorentation, \
you're besides yourself!")
-
+ if(H != spare && isslimeperson(spare) && isslimeperson(H))
+ // transfer the swap-body ui if it's open
+ var/datum/action/innate/swap_body/this_swap = origin_datum.swap_body
+ var/datum/action/innate/swap_body/other_swap = spare_datum.swap_body
+ var/datum/tgui/ui = SStgui.get_open_ui(H, this_swap, "main") || SStgui.get_open_ui(spare, this_swap, "main")
+ if(ui)
+ SStgui.on_close(ui) // basically removes it from lists is all this proc does.
+ ui.user = spare
+ ui.src_object = other_swap
+ SStgui.on_open(ui) // stick it back on the lists
+ ui.process(force = TRUE)
/datum/action/innate/swap_body
name = "Swap Body"
@@ -327,6 +355,8 @@
stat = "Conscious"
if(UNCONSCIOUS)
stat = "Unconscious"
+ if(SOFT_CRIT)
+ stat = "Barely Conscious"
if(DEAD)
stat = "Dead"
var/occupied
@@ -373,7 +403,6 @@
var/mob/living/carbon/human/selected = locate(params["ref"]) in SS.bodies
if(!can_swap(selected))
return
- SStgui.close_uis(src)
swap_to_dupe(H.mind, selected)
/datum/action/innate/swap_body/proc/can_swap(mob/living/carbon/human/dupe)
@@ -407,6 +436,7 @@
/datum/action/innate/swap_body/proc/swap_to_dupe(datum/mind/M, mob/living/carbon/human/dupe)
if(!can_swap(dupe)) //sanity check
return
+ var/mob/living/carbon/human/old = M.current
if(M.current.stat == CONSCIOUS)
M.current.visible_message("[M.current] \
stops moving and starts staring vacantly into space.",
@@ -418,13 +448,26 @@
dupe.visible_message("[dupe] blinks and looks \
around.",
"...and move this one instead.")
-
+ if(old != M.current && dupe == M.current && isslimeperson(dupe))
+ var/datum/species/jelly/slime/other_spec = dupe.dna.species
+ var/datum/action/innate/swap_body/other_swap = other_spec.swap_body
+ // theoretically the transfer_to proc is supposed to transfer the ui from the mob.
+ // so I try to get the UI from one of the two mobs and schlump it over to the new action button
+ var/datum/tgui/ui = SStgui.get_open_ui(old, src, "main") || SStgui.get_open_ui(dupe, src, "main")
+ if(ui)
+ // transfer the UI over. This code is slightly hacky but it fixes the problem
+ // I'd use SStgui.on_transfer but that doesn't let you transfer the src_object as well s
+ SStgui.on_close(ui) // basically removes it from lists is all this proc does.
+ ui.user = dupe
+ ui.src_object = other_swap
+ SStgui.on_open(ui) // stick it back on the lists
+ ui.process(force = TRUE)
////////////////////////////////////////////////////////Round Start Slimes///////////////////////////////////////////////////////////////////
/datum/species/jelly/roundstartslime
name = "Xenobiological Slime Hybrid"
- id = "slimeperson"
+ id = SPECIES_SLIME_HYBRID
limbs_id = "slime"
default_color = "00FFFF"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
@@ -466,7 +509,7 @@
var/new_color = input(owner, "Choose your skin color:", "Race change","#"+H.dna.features["mcolor"]) as color|null
if(new_color)
var/temp_hsv = RGBtoHSV(new_color)
- if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
+ if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright
H.dna.features["mcolor"] = sanitize_hexcolor(new_color, 6)
H.update_body()
H.update_hair()
@@ -645,6 +688,88 @@
else
return
+/datum/action/innate/slime_puddle
+ name = "Puddle Transformation"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "slimepuddle"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+ required_mobility_flags = MOBILITY_STAND
+ var/is_puddle = FALSE
+ var/in_transformation_duration = 12
+ var/out_transformation_duration = 7
+ var/puddle_into_effect = /obj/effect/temp_visual/slime_puddle
+ var/puddle_from_effect = /obj/effect/temp_visual/slime_puddle/reverse
+ var/puddle_icon = 'icons/mob/mob.dmi'
+ var/puddle_state = "puddle"
+ var/tracked_overlay
+ var/datum/component/squeak/squeak
+ var/transforming = FALSE
+ var/last_use
+
+/datum/action/innate/slime_puddle/IsAvailable()
+ if(!transforming)
+ return ..()
+ else
+ return FALSE
+
+/datum/action/innate/slime_puddle/Activate()
+ if(isjellyperson(owner) && IsAvailable())
+ transforming = TRUE
+ UpdateButtonIcon()
+ var/mob/living/carbon/human/H = owner
+ var/mutcolor = "#" + H.dna.features["mcolor"]
+ if(!is_puddle)
+ if(CHECK_MOBILITY(H, MOBILITY_USE))
+ is_puddle = TRUE
+ owner.cut_overlays()
+ var/obj/effect/puddle_effect = new puddle_into_effect(get_turf(owner), owner.dir)
+ puddle_effect.color = mutcolor
+ H.Stun(in_transformation_duration, ignore_canstun = TRUE)
+ ADD_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT)
+ ADD_TRAIT(H, TRAIT_PARALYSIS_R_ARM, SLIMEPUDDLE_TRAIT)
+ ADD_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT)
+ ADD_TRAIT(H, TRAIT_MOBILITY_NOUSE, SLIMEPUDDLE_TRAIT)
+ ADD_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT)
+ ADD_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT)
+ ADD_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT)
+ H.add_movespeed_modifier(/datum/movespeed_modifier/slime_puddle)
+ H.update_disabled_bodyparts(silent = TRUE)
+ H.layer -= 1 //go one layer down so people go over you
+ ENABLE_BITFIELD(H.pass_flags, PASSMOB)
+ squeak = H.AddComponent(/datum/component/squeak, custom_sounds = list('sound/effects/blobattack.ogg'))
+ sleep(in_transformation_duration)
+ var/mutable_appearance/puddle_overlay = mutable_appearance(icon = puddle_icon, icon_state = puddle_state)
+ puddle_overlay.color = mutcolor
+ tracked_overlay = puddle_overlay
+ owner.add_overlay(puddle_overlay)
+ transforming = FALSE
+ UpdateButtonIcon()
+ else
+ owner.cut_overlay(tracked_overlay)
+ var/obj/effect/puddle_effect = new puddle_from_effect(get_turf(owner), owner.dir)
+ puddle_effect.color = mutcolor
+ H.Stun(out_transformation_duration, ignore_canstun = TRUE)
+ sleep(out_transformation_duration)
+ REMOVE_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT)
+ REMOVE_TRAIT(H, TRAIT_PARALYSIS_R_ARM, SLIMEPUDDLE_TRAIT)
+ REMOVE_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT)
+ REMOVE_TRAIT(H, TRAIT_MOBILITY_NOUSE, SLIMEPUDDLE_TRAIT)
+ REMOVE_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT)
+ REMOVE_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT)
+ REMOVE_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT)
+ H.update_disabled_bodyparts(silent = TRUE)
+ H.remove_movespeed_modifier(/datum/movespeed_modifier/slime_puddle)
+ H.layer += 1 //go one layer back above!
+ DISABLE_BITFIELD(H.pass_flags, PASSMOB)
+ is_puddle = FALSE
+ if(squeak)
+ squeak.RemoveComponent()
+ owner.regenerate_icons()
+ transforming = FALSE
+ UpdateButtonIcon()
+ else
+ to_chat(owner, "You need to be standing up to do this!") //just assume they're a slime because it's such a weird edgecase to have it and not be one (it shouldn't even be possible)
///////////////////////////////////LUMINESCENTS//////////////////////////////////////////
@@ -652,7 +777,7 @@
/datum/species/jelly/luminescent
name = "Luminescent Slime Entity"
- id = "lum"
+ id = SPECIES_SLIME_LUMI
say_mod = "says"
var/glow_intensity = LUMINESCENT_DEFAULT_GLOW
var/obj/effect/dummy/luminescent_glow/glow
@@ -819,7 +944,7 @@
/datum/species/jelly/stargazer
name = "Stargazer Slime Entity"
- id = "stargazer"
+ id = SPECIES_STARGAZER
var/datum/action/innate/project_thought/project_thought
var/datum/action/innate/link_minds/link_minds
var/list/mob/living/linked_mobs = list()
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index a8e3f89957..c37a24a93a 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -1,7 +1,7 @@
/datum/species/lizard
// Reptilian humanoids with scaled skin and tails.
name = "Anthromorphic Lizard"
- id = "lizard"
+ id = SPECIES_LIZARD
say_mod = "hisses"
default_color = "00FF00"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
@@ -28,7 +28,7 @@
tail_type = "tail_lizard"
wagging_type = "waggingtail_lizard"
- species_type = "lizard"
+ species_category = "lizard"
/datum/species/lizard/random_name(gender,unique,lastname)
if(unique)
@@ -46,7 +46,7 @@
*/
/datum/species/lizard/ashwalker
name = "Ash Walker"
- id = "ashlizard"
+ id = SPECIES_ASHWALKER
limbs_id = "lizard"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
inherent_traits = list(TRAIT_CHUNKYFINGERS)
diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
index f91c3518a3..dcbdf91485 100644
--- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
@@ -1,6 +1,6 @@
/datum/species/mush //mush mush codecuck
name = "Anthromorphic Mushroom"
- id = "mush"
+ id = SPECIES_MUSHROOM
mutant_bodyparts = list("caps" = "Round")
fixed_mut_color = "DBBF92"
@@ -21,7 +21,7 @@
burnmod = 1.25
heatmod = 1.5
- species_type = "plant"
+ species_category = SPECIES_CATEGORY_PLANT
mutanteyes = /obj/item/organ/eyes/night_vision/mushroom
var/datum/martial_art/mushpunch/mush
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 8c30adb8f9..12a520b463 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -1,6 +1,6 @@
/datum/species/plasmaman
name = "Plasmaman"
- id = "plasmaman"
+ id = SPECIES_PLASMAMAN
say_mod = "rattles"
sexes = 0
meat = /obj/item/stack/sheet/mineral/plasma
@@ -22,7 +22,7 @@
liked_food = VEGETABLES
outfit_important_for_life = /datum/outfit/plasmaman
- species_type = "skeleton"
+ species_category = SPECIES_CATEGORY_SKELETON
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
var/datum/gas_mixture/environment = H.loc.return_air()
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index 0f62953e6c..fae8ebfb0d 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -1,7 +1,7 @@
/datum/species/pod
// A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness.
name = "Anthromorphic Plant"
- id = "pod"
+ id = SPECIES_POD
default_color = "59CE00"
species_traits = list(MUTCOLORS,EYECOLOR,CAN_SCAR,HAS_FLESH,HAS_BONE)
attack_verb = "slash"
@@ -19,7 +19,7 @@
var/light_burnheal = -1
var/light_bruteheal = -1
- species_type = "plant"
+ species_category = SPECIES_CATEGORY_PLANT
allowed_limb_ids = list("pod","mush")
@@ -66,7 +66,7 @@
/datum/species/pod/pseudo_weak
name = "Anthromorphic Plant"
- id = "podweak"
+ id = SPECIES_POD_WEAK
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS)
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
limbs_id = "pod"
diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
index a7d9ce4473..7dc8083264 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -4,7 +4,7 @@
/datum/species/shadow
// Humans cursed to stay in the darkness, lest their life forces drain. They regain health in shadow and die in light.
name = "???"
- id = "shadow"
+ id = SPECIES_SHADOW
sexes = 0
blacklisted = 1
ignored_by = list(/mob/living/simple_animal/hostile/faithless)
@@ -15,7 +15,7 @@
dangerous_existence = 1
mutanteyes = /obj/item/organ/eyes/night_vision
- species_type = "shadow"
+ species_category = SPECIES_CATEGORY_SHADOW
/datum/species/shadow/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
@@ -32,7 +32,7 @@
/datum/species/shadow/nightmare
name = "Nightmare"
- id = "nightmare"
+ id = SPECIES_NIGHTMARE
limbs_id = "shadow"
burnmod = 1.5
blacklisted = TRUE
diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
index 1b6bef9dc6..b0673a7df4 100644
--- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm
+++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
@@ -1,6 +1,6 @@
/datum/species/skeleton
name = "Skeleton"
- id = "skeleton"
+ id = SPECIES_SKELETON
say_mod = "rattles"
blacklisted = 0
sexes = 0
@@ -15,7 +15,7 @@
brutemod = 1.25
burnmod = 1.25
- species_type = "skeleton" //they have their own category that's disassociated from undead, paired with plasmapeople
+ species_category = SPECIES_CATEGORY_SKELETON //they have their own category that's disassociated from undead, paired with plasmapeople
/datum/species/skeleton/New()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) //skeletons are stronger during the spooky season!
@@ -31,7 +31,7 @@
/datum/species/skeleton/space
name = "Spooky Spacey Skeleton"
- id = "spaceskeleton"
+ id = SPECIES_SKELETON_SPACE
limbs_id = "skeleton"
blacklisted = 1
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT, TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
diff --git a/code/modules/mob/living/carbon/human/species_types/synthliz.dm b/code/modules/mob/living/carbon/human/species_types/synthliz.dm
index b446e3796e..88781532d3 100644
--- a/code/modules/mob/living/carbon/human/species_types/synthliz.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synthliz.dm
@@ -1,6 +1,6 @@
/datum/species/synthliz
name = "Synthetic Lizardperson"
- id = "synthliz"
+ id = SPECIES_SYNTH_LIZARD
say_mod = "beeps"
default_color = "00FF00"
species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE)
@@ -27,4 +27,4 @@
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
- species_type = "robotic"
+ species_category = SPECIES_CATEGORY_ROBOT
diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm
index 3d55ce1027..5d2b6f4c77 100644
--- a/code/modules/mob/living/carbon/human/species_types/synths.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synths.dm
@@ -1,6 +1,6 @@
/datum/species/synth
name = "Synthetic" //inherited from the real species, for health scanners and things
- id = "synth"
+ id = SPECIES_SYNTH
say_mod = "beep boops" //inherited from a user's real species
sexes = 0
species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species
@@ -17,11 +17,11 @@
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
species_language_holder = /datum/language_holder/synthetic
- species_type = "robotic"
+ species_category = SPECIES_CATEGORY_ROBOT
/datum/species/synth/military
name = "Military Synth"
- id = "military_synth"
+ id = SPECIES_SYNTH_MIL
armor = 25
punchdamagelow = 10
punchdamagehigh = 19
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 857fb6d8ed..4125d3beab 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -1,6 +1,6 @@
/datum/species/vampire
name = "Vampire"
- id = "vampire"
+ id = SPECIES_VAMPIRE
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
@@ -14,7 +14,7 @@
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
var/info_text = "You are a Vampire. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability."
- species_type = "undead"
+ species_category = SPECIES_CATEGORY_UNDEAD
/datum/species/vampire/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
diff --git a/code/modules/mob/living/carbon/human/species_types/xeno.dm b/code/modules/mob/living/carbon/human/species_types/xeno.dm
index ddd1c86f0a..2757c624e7 100644
--- a/code/modules/mob/living/carbon/human/species_types/xeno.dm
+++ b/code/modules/mob/living/carbon/human/species_types/xeno.dm
@@ -1,7 +1,7 @@
/datum/species/xeno
// A cloning mistake, crossing human and xenomorph DNA
name = "Xenomorph Hybrid"
- id = "xeno"
+ id = SPECIES_XENOHYBRID
say_mod = "hisses"
default_color = "00FF00"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR)
@@ -15,4 +15,4 @@
exotic_bloodtype = "X*"
damage_overlay_type = "xeno"
liked_food = MEAT
- species_type = "alien"
+ species_category = SPECIES_CATEGORY_ALIEN
diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm
index 8d86ad2fa9..f1c0b8e7c0 100644
--- a/code/modules/mob/living/carbon/human/species_types/zombies.dm
+++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm
@@ -15,7 +15,7 @@
var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg')
disliked_food = NONE
liked_food = GROSS | MEAT | RAW
- species_type = "undead"
+ species_category = SPECIES_CATEGORY_UNDEAD
/datum/species/zombie/notspaceproof
id = "notspaceproofzombie"
@@ -98,7 +98,7 @@
// Your skin falls off
/datum/species/krokodil_addict
- name = "Human"
+ name = SPECIES_HUMAN
id = "goofzombies"
limbs_id = "zombie" //They look like zombies
sexes = 0
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index cfb35fbb00..71833d22a3 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -50,19 +50,21 @@ There are several things that need to be remembered:
//HAIR OVERLAY
/mob/living/carbon/human/update_hair()
- dna.species.handle_hair(src)
+ if(dna.species.should_render())
+ dna.species.handle_hair(src)
//used when putting/removing clothes that hide certain mutant body parts to just update those and not update the whole body.
/mob/living/carbon/human/proc/update_mutant_bodyparts()
- dna.species.handle_mutant_bodyparts(src)
-
+ if(dna.species.should_render())
+ dna.species.handle_mutant_bodyparts(src)
/mob/living/carbon/human/update_body(update_genitals = FALSE)
- remove_overlay(BODY_LAYER)
- dna.species.handle_body(src)
- ..()
- if(update_genitals)
- update_genitals()
+ if(dna.species.should_render())
+ remove_overlay(BODY_LAYER)
+ dna.species.handle_body(src)
+ ..()
+ if(update_genitals)
+ update_genitals()
/mob/living/carbon/human/update_fire()
..((fire_stacks > 3) ? "Standing" : "Generic_mob_burning")
@@ -71,381 +73,385 @@ There are several things that need to be remembered:
/* --------------------------------------- */
//For legacy support.
/mob/living/carbon/human/regenerate_icons()
-
- if(!..())
- icon_render_key = null //invalidate bodyparts cache
- update_body(TRUE)
- update_hair()
- update_inv_w_uniform()
- update_inv_wear_id()
- update_inv_gloves()
- update_inv_glasses()
- update_inv_ears()
- update_inv_shoes()
- update_inv_s_store()
- update_inv_wear_mask()
- update_inv_head()
- update_inv_belt()
- update_inv_back()
- update_inv_wear_suit()
- update_inv_pockets()
- update_inv_neck()
- update_transform()
- //mutations
- update_mutations_overlay()
- //damage overlays
- update_damage_overlays()
+ if(dna.species.should_render())
+ if(!..())
+ icon_render_key = null //invalidate bodyparts cache
+ update_body(TRUE)
+ update_hair()
+ update_inv_w_uniform()
+ update_inv_wear_id()
+ update_inv_gloves()
+ update_inv_glasses()
+ update_inv_ears()
+ update_inv_shoes()
+ update_inv_s_store()
+ update_inv_wear_mask()
+ update_inv_head()
+ update_inv_belt()
+ update_inv_back()
+ update_inv_wear_suit()
+ update_inv_pockets()
+ update_inv_neck()
+ update_transform()
+ //mutations
+ update_mutations_overlay()
+ //damage overlays
+ update_damage_overlays()
/* --------------------------------------- */
//vvvvvv UPDATE_INV PROCS vvvvvv
/mob/living/carbon/human/update_inv_w_uniform()
- remove_overlay(UNIFORM_LAYER)
+ if(dna.species.should_render())
+ remove_overlay(UNIFORM_LAYER)
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_W_UNIFORM]
- inv.update_icon()
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_W_UNIFORM]
+ inv.update_icon()
- if(istype(w_uniform, /obj/item/clothing/under))
- var/obj/item/clothing/under/U = w_uniform
- U.screen_loc = ui_iclothing
- if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown)
- client.screen += w_uniform
- update_observer_view(w_uniform,1)
+ if(istype(w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/U = w_uniform
+ U.screen_loc = ui_iclothing
+ if(client && hud_used && hud_used.hud_shown)
+ if(hud_used.inventory_shown)
+ client.screen += w_uniform
+ update_observer_view(w_uniform,1)
- if(wear_suit && (wear_suit.flags_inv & HIDEJUMPSUIT))
- return
+ if(wear_suit && (wear_suit.flags_inv & HIDEJUMPSUIT))
+ return
- var/target_overlay = U.icon_state
- if(U.adjusted == ALT_STYLE)
- target_overlay = "[target_overlay]_d"
+ var/target_overlay = U.icon_state
+ if(U.adjusted == ALT_STYLE)
+ target_overlay = "[target_overlay]_d"
- var/alt_worn = U.mob_overlay_icon || 'icons/mob/clothing/uniform.dmi'
- var/variant_flag = NONE
+ var/alt_worn = U.mob_overlay_icon || 'icons/mob/clothing/uniform.dmi'
+ var/variant_flag = NONE
- if((DIGITIGRADE in dna.species.species_traits) && U.mutantrace_variation & STYLE_DIGITIGRADE && !(U.mutantrace_variation & STYLE_NO_ANTHRO_ICON))
- alt_worn = U.anthro_mob_worn_overlay || 'icons/mob/clothing/uniform_digi.dmi'
- variant_flag |= STYLE_DIGITIGRADE
+ if((DIGITIGRADE in dna.species.species_traits) && U.mutantrace_variation & STYLE_DIGITIGRADE && !(U.mutantrace_variation & STYLE_NO_ANTHRO_ICON))
+ alt_worn = U.anthro_mob_worn_overlay || 'icons/mob/clothing/uniform_digi.dmi'
+ variant_flag |= STYLE_DIGITIGRADE
- var/mask
- if(dna.species.mutant_bodyparts["taur"])
- var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
- var/clip_flag = U.mutantrace_variation & T?.hide_legs
- if(clip_flag)
- variant_flag |= clip_flag
- mask = T.alpha_mask_state
+ var/mask
+ if(dna.species.mutant_bodyparts["taur"])
+ var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
+ var/clip_flag = U.mutantrace_variation & T?.hide_legs
+ if(clip_flag)
+ variant_flag |= clip_flag
+ mask = T.alpha_mask_state
- var/mutable_appearance/uniform_overlay
+ var/mutable_appearance/uniform_overlay
- var/gendered = (dna?.species.sexes && dna.features["body_model"] == FEMALE) ? U.fitted : NO_FEMALE_UNIFORM
- uniform_overlay = U.build_worn_icon( UNIFORM_LAYER, alt_worn, FALSE, gendered, target_overlay, variant_flag, FALSE, mask)
+ var/gendered = (dna?.species.sexes && dna.features["body_model"] == FEMALE) ? U.fitted : NO_FEMALE_UNIFORM
+ uniform_overlay = U.build_worn_icon( UNIFORM_LAYER, alt_worn, FALSE, gendered, target_overlay, variant_flag, FALSE, mask)
- if(OFFSET_UNIFORM in dna.species.offset_features)
- uniform_overlay.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1]
- uniform_overlay.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2]
- overlays_standing[UNIFORM_LAYER] = uniform_overlay
-
- apply_overlay(UNIFORM_LAYER)
- update_mutant_bodyparts()
+ if(OFFSET_UNIFORM in dna.species.offset_features)
+ uniform_overlay.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1]
+ uniform_overlay.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2]
+ overlays_standing[UNIFORM_LAYER] = uniform_overlay
+ apply_overlay(UNIFORM_LAYER)
+ update_mutant_bodyparts()
/mob/living/carbon/human/update_inv_wear_id()
- remove_overlay(ID_LAYER)
+ if(dna.species.should_render())
+ remove_overlay(ID_LAYER)
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_ID]
- inv.update_icon()
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_ID]
+ inv.update_icon()
- var/mutable_appearance/id_overlay = overlays_standing[ID_LAYER]
+ var/mutable_appearance/id_overlay = overlays_standing[ID_LAYER]
- if(wear_id)
- wear_id.screen_loc = ui_id
- if(client && hud_used && hud_used.hud_shown)
- client.screen += wear_id
- update_observer_view(wear_id)
+ if(wear_id)
+ wear_id.screen_loc = ui_id
+ if(client && hud_used && hud_used.hud_shown)
+ client.screen += wear_id
+ update_observer_view(wear_id)
- //TODO: add an icon file for ID slot stuff, so it's less snowflakey
- id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = 'icons/mob/mob.dmi', override_state = wear_id.item_state)
- if(OFFSET_ID in dna.species.offset_features)
- id_overlay.pixel_x += dna.species.offset_features[OFFSET_ID][1]
- id_overlay.pixel_y += dna.species.offset_features[OFFSET_ID][2]
- overlays_standing[ID_LAYER] = id_overlay
- apply_overlay(ID_LAYER)
+ //TODO: add an icon file for ID slot stuff, so it's less snowflakey
+ id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = 'icons/mob/mob.dmi', override_state = wear_id.item_state)
+ if(OFFSET_ID in dna.species.offset_features)
+ id_overlay.pixel_x += dna.species.offset_features[OFFSET_ID][1]
+ id_overlay.pixel_y += dna.species.offset_features[OFFSET_ID][2]
+ overlays_standing[ID_LAYER] = id_overlay
+ apply_overlay(ID_LAYER)
/mob/living/carbon/human/update_inv_gloves()
- remove_overlay(GLOVES_LAYER)
+ if(dna.species.should_render())
+ remove_overlay(GLOVES_LAYER)
- if(client && hud_used && hud_used.inv_slots[SLOT_GLOVES])
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_GLOVES]
- inv.update_icon()
+ if(client && hud_used && hud_used.inv_slots[SLOT_GLOVES])
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_GLOVES]
+ inv.update_icon()
- if(!gloves && bloody_hands)
- var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER, color = blood_DNA_to_color())
- if(get_num_arms(FALSE) < 2)
- if(has_left_hand(FALSE))
- bloody_overlay.icon_state = "bloodyhands_left"
- else if(has_right_hand(FALSE))
- bloody_overlay.icon_state = "bloodyhands_right"
+ if(!gloves && bloody_hands)
+ var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER, color = blood_DNA_to_color())
+ if(get_num_arms(FALSE) < 2)
+ if(has_left_hand(FALSE))
+ bloody_overlay.icon_state = "bloodyhands_left"
+ else if(has_right_hand(FALSE))
+ bloody_overlay.icon_state = "bloodyhands_right"
- overlays_standing[GLOVES_LAYER] = bloody_overlay
+ overlays_standing[GLOVES_LAYER] = bloody_overlay
- var/mutable_appearance/gloves_overlay = overlays_standing[GLOVES_LAYER]
- if(gloves)
- gloves.screen_loc = ui_gloves
- if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown)
- client.screen += gloves
- update_observer_view(gloves,1)
- overlays_standing[GLOVES_LAYER] = gloves.build_worn_icon(default_layer = GLOVES_LAYER, default_icon_file = 'icons/mob/clothing/hands.dmi')
- gloves_overlay = overlays_standing[GLOVES_LAYER]
- if(OFFSET_GLOVES in dna.species.offset_features)
- gloves_overlay.pixel_x += dna.species.offset_features[OFFSET_GLOVES][1]
- gloves_overlay.pixel_y += dna.species.offset_features[OFFSET_GLOVES][2]
- overlays_standing[GLOVES_LAYER] = gloves_overlay
- apply_overlay(GLOVES_LAYER)
+ var/mutable_appearance/gloves_overlay = overlays_standing[GLOVES_LAYER]
+ if(gloves)
+ gloves.screen_loc = ui_gloves
+ if(client && hud_used && hud_used.hud_shown)
+ if(hud_used.inventory_shown)
+ client.screen += gloves
+ update_observer_view(gloves,1)
+ overlays_standing[GLOVES_LAYER] = gloves.build_worn_icon(default_layer = GLOVES_LAYER, default_icon_file = 'icons/mob/clothing/hands.dmi')
+ gloves_overlay = overlays_standing[GLOVES_LAYER]
+ if(OFFSET_GLOVES in dna.species.offset_features)
+ gloves_overlay.pixel_x += dna.species.offset_features[OFFSET_GLOVES][1]
+ gloves_overlay.pixel_y += dna.species.offset_features[OFFSET_GLOVES][2]
+ overlays_standing[GLOVES_LAYER] = gloves_overlay
+ apply_overlay(GLOVES_LAYER)
/mob/living/carbon/human/update_inv_glasses()
- remove_overlay(GLASSES_LAYER)
+ if(dna.species.should_render())
+ remove_overlay(GLASSES_LAYER)
- if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated
- return
-
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_GLASSES]
- inv.update_icon()
-
- if(glasses)
- glasses.screen_loc = ui_glasses //...draw the item in the inventory screen
- if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown) //if the inventory is open ...
- client.screen += glasses //Either way, add the item to the HUD
- update_observer_view(glasses,1)
- if(!(head && (head.flags_inv & HIDEEYES)) && !(wear_mask && (wear_mask.flags_inv & HIDEEYES)))
- overlays_standing[GLASSES_LAYER] = glasses.build_worn_icon(default_layer = GLASSES_LAYER, default_icon_file = 'icons/mob/clothing/eyes.dmi', override_state = glasses.icon_state)
- var/mutable_appearance/glasses_overlay = overlays_standing[GLASSES_LAYER]
- if(glasses_overlay)
- if(OFFSET_GLASSES in dna.species.offset_features)
- glasses_overlay.pixel_x += dna.species.offset_features[OFFSET_GLASSES][1]
- glasses_overlay.pixel_y += dna.species.offset_features[OFFSET_GLASSES][2]
- overlays_standing[GLASSES_LAYER] = glasses_overlay
- apply_overlay(GLASSES_LAYER)
-
-
-/mob/living/carbon/human/update_inv_ears()
- remove_overlay(EARS_LAYER)
-
- if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated
- return
-
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_EARS]
- inv.update_icon()
-
- if(ears)
- ears.screen_loc = ui_ears //move the item to the appropriate screen loc
- if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown) //if the inventory is open
- client.screen += ears //add it to the client's screen
- update_observer_view(ears,1)
-
- overlays_standing[EARS_LAYER] = ears.build_worn_icon(default_layer = EARS_LAYER, default_icon_file = 'icons/mob/ears.dmi')
- var/mutable_appearance/ears_overlay = overlays_standing[EARS_LAYER]
- if(OFFSET_EARS in dna.species.offset_features)
- ears_overlay.pixel_x += dna.species.offset_features[OFFSET_EARS][1]
- ears_overlay.pixel_y += dna.species.offset_features[OFFSET_EARS][2]
- overlays_standing[EARS_LAYER] = ears_overlay
- apply_overlay(EARS_LAYER)
-
-
-/mob/living/carbon/human/update_inv_shoes()
- remove_overlay(SHOES_LAYER)
-
- if(get_num_legs(FALSE) <2)
- return
-
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_SHOES]
- inv.update_icon()
-
- if(dna.species.mutant_bodyparts["taur"])
- var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
- if(T?.hide_legs) //If only they actually made shoes unwearable. Please don't making cosmetics, guys.
+ if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated
return
- if(shoes)
- var/obj/item/clothing/shoes/S = shoes
- shoes.screen_loc = ui_shoes //move the item to the appropriate screen loc
- if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown) //if the inventory is open
- client.screen += shoes //add it to client's screen
- update_observer_view(shoes,1)
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_GLASSES]
+ inv.update_icon()
- var/alt_icon = S.mob_overlay_icon || 'icons/mob/clothing/feet.dmi'
- var/variation_flag = NONE
- if((DIGITIGRADE in dna.species.species_traits) && S.mutantrace_variation & STYLE_DIGITIGRADE && !(S.mutantrace_variation & STYLE_NO_ANTHRO_ICON))
- alt_icon = S.anthro_mob_worn_overlay || 'icons/mob/clothing/feet_digi.dmi'
- variation_flag |= STYLE_DIGITIGRADE
+ if(glasses)
+ glasses.screen_loc = ui_glasses //...draw the item in the inventory screen
+ if(client && hud_used && hud_used.hud_shown)
+ if(hud_used.inventory_shown) //if the inventory is open ...
+ client.screen += glasses //Either way, add the item to the HUD
+ update_observer_view(glasses,1)
+ if(!(head && (head.flags_inv & HIDEEYES)) && !(wear_mask && (wear_mask.flags_inv & HIDEEYES)))
+ overlays_standing[GLASSES_LAYER] = glasses.build_worn_icon(default_layer = GLASSES_LAYER, default_icon_file = 'icons/mob/clothing/eyes.dmi', override_state = glasses.icon_state)
+ var/mutable_appearance/glasses_overlay = overlays_standing[GLASSES_LAYER]
+ if(glasses_overlay)
+ if(OFFSET_GLASSES in dna.species.offset_features)
+ glasses_overlay.pixel_x += dna.species.offset_features[OFFSET_GLASSES][1]
+ glasses_overlay.pixel_y += dna.species.offset_features[OFFSET_GLASSES][2]
+ overlays_standing[GLASSES_LAYER] = glasses_overlay
+ apply_overlay(GLASSES_LAYER)
- overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(SHOES_LAYER, alt_icon, FALSE, NO_FEMALE_UNIFORM, S.icon_state, variation_flag, FALSE)
- var/mutable_appearance/shoes_overlay = overlays_standing[SHOES_LAYER]
- if(OFFSET_SHOES in dna.species.offset_features)
- shoes_overlay.pixel_x += dna.species.offset_features[OFFSET_SHOES][1]
- shoes_overlay.pixel_y += dna.species.offset_features[OFFSET_SHOES][2]
- overlays_standing[SHOES_LAYER] = shoes_overlay
- apply_overlay(SHOES_LAYER)
+/mob/living/carbon/human/update_inv_ears()
+ if(dna.species.should_render())
+ remove_overlay(EARS_LAYER)
-/mob/living/carbon/human/update_inv_s_store()
- remove_overlay(SUIT_STORE_LAYER)
+ if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated
+ return
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_S_STORE]
- inv.update_icon()
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_EARS]
+ inv.update_icon()
- if(s_store)
- s_store.screen_loc = ui_sstore1
- if(client && hud_used && hud_used.hud_shown)
- client.screen += s_store
- update_observer_view(s_store)
- var/t_state = s_store.item_state
- if(!t_state)
- t_state = s_store.icon_state
- overlays_standing[SUIT_STORE_LAYER] = mutable_appearance(((s_store.mob_overlay_icon) ? s_store.mob_overlay_icon : 'icons/mob/clothing/belt_mirror.dmi'), t_state, -SUIT_STORE_LAYER)
- var/mutable_appearance/s_store_overlay = overlays_standing[SUIT_STORE_LAYER]
- if(OFFSET_S_STORE in dna.species.offset_features)
- s_store_overlay.pixel_x += dna.species.offset_features[OFFSET_S_STORE][1]
- s_store_overlay.pixel_y += dna.species.offset_features[OFFSET_S_STORE][2]
- overlays_standing[SUIT_STORE_LAYER] = s_store_overlay
- apply_overlay(SUIT_STORE_LAYER)
+ if(ears)
+ ears.screen_loc = ui_ears //move the item to the appropriate screen loc
+ if(client && hud_used && hud_used.hud_shown)
+ if(hud_used.inventory_shown) //if the inventory is open
+ client.screen += ears //add it to the client's screen
+ update_observer_view(ears,1)
+ overlays_standing[EARS_LAYER] = ears.build_worn_icon(default_layer = EARS_LAYER, default_icon_file = 'icons/mob/ears.dmi')
+ var/mutable_appearance/ears_overlay = overlays_standing[EARS_LAYER]
+ if(OFFSET_EARS in dna.species.offset_features)
+ ears_overlay.pixel_x += dna.species.offset_features[OFFSET_EARS][1]
+ ears_overlay.pixel_y += dna.species.offset_features[OFFSET_EARS][2]
+ overlays_standing[EARS_LAYER] = ears_overlay
+ apply_overlay(EARS_LAYER)
-/mob/living/carbon/human/update_inv_head()
- remove_overlay(HEAD_LAYER)
+/mob/living/carbon/human/update_inv_shoes()
+ if(dna.species.should_render())
+ remove_overlay(SHOES_LAYER)
- if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
- return
+ if(get_num_legs(FALSE) <2)
+ return
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_HEAD]
- inv.update_icon()
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_SHOES]
+ inv.update_icon()
- if(head)
- head.screen_loc = ui_head
- if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown)
- client.screen += head
- update_observer_view(head,1)
- remove_overlay(HEAD_LAYER)
- var/obj/item/clothing/head/H = head
- var/alt_icon = H.mob_overlay_icon || 'icons/mob/clothing/head.dmi'
- var/muzzled = FALSE
- var/variation_flag = NONE
- if(dna.species.mutant_bodyparts["mam_snouts"] && dna.features["mam_snouts"] != "None")
- muzzled = TRUE
- else if(dna.species.mutant_bodyparts["snout"] && dna.features["snout"] != "None")
- muzzled = TRUE
- if(muzzled && H.mutantrace_variation & STYLE_MUZZLE && !(H.mutantrace_variation & STYLE_NO_ANTHRO_ICON))
- alt_icon = H.anthro_mob_worn_overlay || 'icons/mob/clothing/head_muzzled.dmi'
- variation_flag |= STYLE_MUZZLE
-
- overlays_standing[HEAD_LAYER] = H.build_worn_icon(HEAD_LAYER, alt_icon, FALSE, NO_FEMALE_UNIFORM, H.icon_state, variation_flag, FALSE)
- var/mutable_appearance/head_overlay = overlays_standing[HEAD_LAYER]
-
- if(OFFSET_HEAD in dna.species.offset_features)
- head_overlay.pixel_x += dna.species.offset_features[OFFSET_HEAD][1]
- head_overlay.pixel_y += dna.species.offset_features[OFFSET_HEAD][2]
- overlays_standing[HEAD_LAYER] = head_overlay
- apply_overlay(HEAD_LAYER)
- update_mutant_bodyparts()
-
-/mob/living/carbon/human/update_inv_belt()
- remove_overlay(BELT_LAYER)
-
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_BELT]
- inv.update_icon()
-
- if(belt)
- belt.screen_loc = ui_belt
- if(client && hud_used && hud_used.hud_shown)
- client.screen += belt
- update_observer_view(belt)
-
- overlays_standing[BELT_LAYER] = belt.build_worn_icon(default_layer = BELT_LAYER, default_icon_file = 'icons/mob/clothing/belt.dmi')
- var/mutable_appearance/belt_overlay = overlays_standing[BELT_LAYER]
- if(OFFSET_BELT in dna.species.offset_features)
- belt_overlay.pixel_x += dna.species.offset_features[OFFSET_BELT][1]
- belt_overlay.pixel_y += dna.species.offset_features[OFFSET_BELT][2]
- overlays_standing[BELT_LAYER] = belt_overlay
- apply_overlay(BELT_LAYER)
-
-
-/mob/living/carbon/human/update_inv_wear_suit()
- remove_overlay(SUIT_LAYER)
-
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_SUIT]
- inv.update_icon()
-
- if(wear_suit)
- var/obj/item/clothing/suit/S = wear_suit
- wear_suit.screen_loc = ui_oclothing
- if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown)
- client.screen += wear_suit
- update_observer_view(wear_suit,1)
-
- var/worn_icon = wear_suit.mob_overlay_icon || 'icons/mob/clothing/suit.dmi'
- var/worn_state = wear_suit.icon_state
- var/center = FALSE
- var/dimension_x = 32
- var/dimension_y = 32
- var/variation_flag = NONE
- var/datum/sprite_accessory/taur/T
if(dna.species.mutant_bodyparts["taur"])
- T = GLOB.taur_list[dna.features["taur"]]
+ var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
+ if(T?.hide_legs) //If only they actually made shoes unwearable. Please don't making cosmetics, guys.
+ return
- if(S.mutantrace_variation)
+ if(shoes)
+ var/obj/item/clothing/shoes/S = shoes
+ shoes.screen_loc = ui_shoes //move the item to the appropriate screen loc
+ if(client && hud_used && hud_used.hud_shown)
+ if(hud_used.inventory_shown) //if the inventory is open
+ client.screen += shoes //add it to client's screen
+ update_observer_view(shoes,1)
- if(T?.taur_mode)
- var/init_worn_icon = worn_icon
- variation_flag |= S.mutantrace_variation & T.taur_mode || S.mutantrace_variation & T.alt_taur_mode
- switch(variation_flag)
- if(STYLE_HOOF_TAURIC)
- worn_icon = 'icons/mob/clothing/taur_hooved.dmi'
- if(STYLE_SNEK_TAURIC)
- worn_icon = 'icons/mob/clothing/taur_naga.dmi'
- if(STYLE_PAW_TAURIC)
- worn_icon = 'icons/mob/clothing/taur_canine.dmi'
- if(worn_icon != init_worn_icon) //worn icon sprite was changed, taur offsets will have to be applied.
- if(S.taur_mob_worn_overlay) //not going to make several new variables for all taur types. Nope.
- var/static/list/icon_to_state = list('icons/mob/clothing/taur_hooved.dmi' = "_hooved", 'icons/mob/clothing/taur_naga.dmi' = "_naga", 'icons/mob/clothing/taur_canine.dmi' = "_paws")
- worn_state += icon_to_state[worn_icon]
- worn_icon = S.taur_mob_worn_overlay
- center = T.center
- dimension_x = T.dimension_x
- dimension_y = T.dimension_y
-
- else if((DIGITIGRADE in dna.species.species_traits) && S.mutantrace_variation & STYLE_DIGITIGRADE && !(S.mutantrace_variation & STYLE_NO_ANTHRO_ICON)) //not a taur, but digitigrade legs.
- worn_icon = S.anthro_mob_worn_overlay || 'icons/mob/clothing/suit_digi.dmi'
+ var/alt_icon = S.mob_overlay_icon || 'icons/mob/clothing/feet.dmi'
+ var/variation_flag = NONE
+ if((DIGITIGRADE in dna.species.species_traits) && S.mutantrace_variation & STYLE_DIGITIGRADE && !(S.mutantrace_variation & STYLE_NO_ANTHRO_ICON))
+ alt_icon = S.anthro_mob_worn_overlay || 'icons/mob/clothing/feet_digi.dmi'
variation_flag |= STYLE_DIGITIGRADE
- overlays_standing[SUIT_LAYER] = S.build_worn_icon(SUIT_LAYER, worn_icon, FALSE, NO_FEMALE_UNIFORM, worn_state, variation_flag, FALSE)
- var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER]
- if(OFFSET_SUIT in dna.species.offset_features)
- suit_overlay.pixel_x += dna.species.offset_features[OFFSET_SUIT][1]
- suit_overlay.pixel_y += dna.species.offset_features[OFFSET_SUIT][2]
- if(center)
- suit_overlay = center_image(suit_overlay, dimension_x, dimension_y)
- overlays_standing[SUIT_LAYER] = suit_overlay
- update_hair()
- update_mutant_bodyparts()
+ overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(SHOES_LAYER, alt_icon, FALSE, NO_FEMALE_UNIFORM, S.icon_state, variation_flag, FALSE)
+ var/mutable_appearance/shoes_overlay = overlays_standing[SHOES_LAYER]
+ if(OFFSET_SHOES in dna.species.offset_features)
+ shoes_overlay.pixel_x += dna.species.offset_features[OFFSET_SHOES][1]
+ shoes_overlay.pixel_y += dna.species.offset_features[OFFSET_SHOES][2]
+ overlays_standing[SHOES_LAYER] = shoes_overlay
+ apply_overlay(SHOES_LAYER)
- apply_overlay(SUIT_LAYER)
+/mob/living/carbon/human/update_inv_s_store()
+ if(dna.species.should_render())
+ remove_overlay(SUIT_STORE_LAYER)
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_S_STORE]
+ inv.update_icon()
+
+ if(s_store)
+ s_store.screen_loc = ui_sstore1
+ if(client && hud_used && hud_used.hud_shown)
+ client.screen += s_store
+ update_observer_view(s_store)
+ var/t_state = s_store.item_state
+ if(!t_state)
+ t_state = s_store.icon_state
+ overlays_standing[SUIT_STORE_LAYER] = mutable_appearance(((s_store.mob_overlay_icon) ? s_store.mob_overlay_icon : 'icons/mob/clothing/belt_mirror.dmi'), t_state, -SUIT_STORE_LAYER)
+ var/mutable_appearance/s_store_overlay = overlays_standing[SUIT_STORE_LAYER]
+ if(OFFSET_S_STORE in dna.species.offset_features)
+ s_store_overlay.pixel_x += dna.species.offset_features[OFFSET_S_STORE][1]
+ s_store_overlay.pixel_y += dna.species.offset_features[OFFSET_S_STORE][2]
+ overlays_standing[SUIT_STORE_LAYER] = s_store_overlay
+ apply_overlay(SUIT_STORE_LAYER)
+
+/mob/living/carbon/human/update_inv_head()
+ if(dna.species.should_render())
+ remove_overlay(HEAD_LAYER)
+
+ if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
+ return
+
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_HEAD]
+ inv.update_icon()
+
+ if(head)
+ head.screen_loc = ui_head
+ if(client && hud_used && hud_used.hud_shown)
+ if(hud_used.inventory_shown)
+ client.screen += head
+ update_observer_view(head,1)
+ remove_overlay(HEAD_LAYER)
+ var/obj/item/clothing/head/H = head
+ var/alt_icon = H.mob_overlay_icon || 'icons/mob/clothing/head.dmi'
+ var/muzzled = FALSE
+ var/variation_flag = NONE
+ if(dna.species.mutant_bodyparts["mam_snouts"] && dna.features["mam_snouts"] != "None")
+ muzzled = TRUE
+ else if(dna.species.mutant_bodyparts["snout"] && dna.features["snout"] != "None")
+ muzzled = TRUE
+ if(muzzled && H.mutantrace_variation & STYLE_MUZZLE && !(H.mutantrace_variation & STYLE_NO_ANTHRO_ICON))
+ alt_icon = H.anthro_mob_worn_overlay || 'icons/mob/clothing/head_muzzled.dmi'
+ variation_flag |= STYLE_MUZZLE
+
+ overlays_standing[HEAD_LAYER] = H.build_worn_icon(HEAD_LAYER, alt_icon, FALSE, NO_FEMALE_UNIFORM, H.icon_state, variation_flag, FALSE)
+ var/mutable_appearance/head_overlay = overlays_standing[HEAD_LAYER]
+
+ if(OFFSET_HEAD in dna.species.offset_features)
+ head_overlay.pixel_x += dna.species.offset_features[OFFSET_HEAD][1]
+ head_overlay.pixel_y += dna.species.offset_features[OFFSET_HEAD][2]
+ overlays_standing[HEAD_LAYER] = head_overlay
+ apply_overlay(HEAD_LAYER)
+ update_mutant_bodyparts()
+
+/mob/living/carbon/human/update_inv_belt()
+ if(dna.species.should_render())
+ remove_overlay(BELT_LAYER)
+
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_BELT]
+ inv.update_icon()
+
+ if(belt)
+ belt.screen_loc = ui_belt
+ if(client && hud_used && hud_used.hud_shown)
+ client.screen += belt
+ update_observer_view(belt)
+
+ overlays_standing[BELT_LAYER] = belt.build_worn_icon(default_layer = BELT_LAYER, default_icon_file = 'icons/mob/clothing/belt.dmi')
+ var/mutable_appearance/belt_overlay = overlays_standing[BELT_LAYER]
+ if(OFFSET_BELT in dna.species.offset_features)
+ belt_overlay.pixel_x += dna.species.offset_features[OFFSET_BELT][1]
+ belt_overlay.pixel_y += dna.species.offset_features[OFFSET_BELT][2]
+ overlays_standing[BELT_LAYER] = belt_overlay
+ apply_overlay(BELT_LAYER)
+
+/mob/living/carbon/human/update_inv_wear_suit()
+ if(dna.species.should_render())
+ remove_overlay(SUIT_LAYER)
+
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_SUIT]
+ inv.update_icon()
+
+ if(wear_suit)
+ var/obj/item/clothing/suit/S = wear_suit
+ wear_suit.screen_loc = ui_oclothing
+ if(client && hud_used && hud_used.hud_shown)
+ if(hud_used.inventory_shown)
+ client.screen += wear_suit
+ update_observer_view(wear_suit,1)
+
+ var/worn_icon = wear_suit.mob_overlay_icon || 'icons/mob/clothing/suit.dmi'
+ var/worn_state = wear_suit.icon_state
+ var/center = FALSE
+ var/dimension_x = 32
+ var/dimension_y = 32
+ var/variation_flag = NONE
+ var/datum/sprite_accessory/taur/T
+ if(dna.species.mutant_bodyparts["taur"])
+ T = GLOB.taur_list[dna.features["taur"]]
+
+ if(S.mutantrace_variation)
+
+ if(T?.taur_mode)
+ var/init_worn_icon = worn_icon
+ variation_flag |= S.mutantrace_variation & T.taur_mode || S.mutantrace_variation & T.alt_taur_mode
+ switch(variation_flag)
+ if(STYLE_HOOF_TAURIC)
+ worn_icon = 'icons/mob/clothing/taur_hooved.dmi'
+ if(STYLE_SNEK_TAURIC)
+ worn_icon = 'icons/mob/clothing/taur_naga.dmi'
+ if(STYLE_PAW_TAURIC)
+ worn_icon = 'icons/mob/clothing/taur_canine.dmi'
+ if(worn_icon != init_worn_icon) //worn icon sprite was changed, taur offsets will have to be applied.
+ if(S.taur_mob_worn_overlay) //not going to make several new variables for all taur types. Nope.
+ var/static/list/icon_to_state = list('icons/mob/clothing/taur_hooved.dmi' = "_hooved", 'icons/mob/clothing/taur_naga.dmi' = "_naga", 'icons/mob/clothing/taur_canine.dmi' = "_paws")
+ worn_state += icon_to_state[worn_icon]
+ worn_icon = S.taur_mob_worn_overlay
+ center = T.center
+ dimension_x = T.dimension_x
+ dimension_y = T.dimension_y
+
+ else if((DIGITIGRADE in dna.species.species_traits) && S.mutantrace_variation & STYLE_DIGITIGRADE && !(S.mutantrace_variation & STYLE_NO_ANTHRO_ICON)) //not a taur, but digitigrade legs.
+ worn_icon = S.anthro_mob_worn_overlay || 'icons/mob/clothing/suit_digi.dmi'
+ variation_flag |= STYLE_DIGITIGRADE
+
+ overlays_standing[SUIT_LAYER] = S.build_worn_icon(SUIT_LAYER, worn_icon, FALSE, NO_FEMALE_UNIFORM, worn_state, variation_flag, FALSE)
+ var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER]
+ if(OFFSET_SUIT in dna.species.offset_features)
+ suit_overlay.pixel_x += dna.species.offset_features[OFFSET_SUIT][1]
+ suit_overlay.pixel_y += dna.species.offset_features[OFFSET_SUIT][2]
+ if(center)
+ suit_overlay = center_image(suit_overlay, dimension_x, dimension_y)
+ overlays_standing[SUIT_LAYER] = suit_overlay
+ update_hair()
+ update_mutant_bodyparts()
+
+ apply_overlay(SUIT_LAYER)
/mob/living/carbon/human/update_inv_pockets()
if(client && hud_used)
@@ -471,55 +477,57 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_wear_mask()
- remove_overlay(FACEMASK_LAYER)
-
- if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
- return
-
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_MASK]
- inv.update_icon()
-
- if(wear_mask)
- wear_mask.screen_loc = ui_mask
- if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown)
- client.screen += wear_mask
- update_observer_view(wear_mask,1)
- var/obj/item/clothing/mask/M = wear_mask
+ if(dna.species.should_render())
remove_overlay(FACEMASK_LAYER)
- var/alt_icon = M.mob_overlay_icon || 'icons/mob/clothing/mask.dmi'
- var/muzzled = FALSE
- var/variation_flag = NONE
- if(head && (head.flags_inv & HIDEMASK))
+
+ if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
return
- if(dna.species.mutant_bodyparts["mam_snouts"] && dna.features["mam_snouts"] != "None")
- muzzled = TRUE
- else if(dna.species.mutant_bodyparts["snout"] && dna.features["snout"] != "None")
- muzzled = TRUE
- if(muzzled && M.mutantrace_variation & STYLE_MUZZLE && !(M.mutantrace_variation & STYLE_NO_ANTHRO_ICON))
- alt_icon = M.anthro_mob_worn_overlay || 'icons/mob/clothing/mask_muzzled.dmi'
- variation_flag |= STYLE_MUZZLE
- var/mutable_appearance/mask_overlay = M.build_worn_icon(FACEMASK_LAYER, alt_icon, FALSE, NO_FEMALE_UNIFORM, wear_mask.icon_state, variation_flag, FALSE)
+ if(client && hud_used)
+ var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_MASK]
+ inv.update_icon()
- if(OFFSET_FACEMASK in dna.species.offset_features)
- mask_overlay.pixel_x += dna.species.offset_features[OFFSET_FACEMASK][1]
- mask_overlay.pixel_y += dna.species.offset_features[OFFSET_FACEMASK][2]
- overlays_standing[FACEMASK_LAYER] = mask_overlay
- apply_overlay(FACEMASK_LAYER)
- update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout
+ if(wear_mask)
+ wear_mask.screen_loc = ui_mask
+ if(client && hud_used && hud_used.hud_shown)
+ if(hud_used.inventory_shown)
+ client.screen += wear_mask
+ update_observer_view(wear_mask,1)
+ var/obj/item/clothing/mask/M = wear_mask
+ remove_overlay(FACEMASK_LAYER)
+ var/alt_icon = M.mob_overlay_icon || 'icons/mob/clothing/mask.dmi'
+ var/muzzled = FALSE
+ var/variation_flag = NONE
+ if(head && (head.flags_inv & HIDEMASK))
+ return
+ if(dna.species.mutant_bodyparts["mam_snouts"] && dna.features["mam_snouts"] != "None")
+ muzzled = TRUE
+ else if(dna.species.mutant_bodyparts["snout"] && dna.features["snout"] != "None")
+ muzzled = TRUE
+ if(muzzled && M.mutantrace_variation & STYLE_MUZZLE && !(M.mutantrace_variation & STYLE_NO_ANTHRO_ICON))
+ alt_icon = M.anthro_mob_worn_overlay || 'icons/mob/clothing/mask_muzzled.dmi'
+ variation_flag |= STYLE_MUZZLE
+
+ var/mutable_appearance/mask_overlay = M.build_worn_icon(FACEMASK_LAYER, alt_icon, FALSE, NO_FEMALE_UNIFORM, wear_mask.icon_state, variation_flag, FALSE)
+
+ if(OFFSET_FACEMASK in dna.species.offset_features)
+ mask_overlay.pixel_x += dna.species.offset_features[OFFSET_FACEMASK][1]
+ mask_overlay.pixel_y += dna.species.offset_features[OFFSET_FACEMASK][2]
+ overlays_standing[FACEMASK_LAYER] = mask_overlay
+ apply_overlay(FACEMASK_LAYER)
+ update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout
/mob/living/carbon/human/update_inv_back()
- ..()
- var/mutable_appearance/back_overlay = overlays_standing[BACK_LAYER]
- if(back_overlay)
- remove_overlay(BACK_LAYER)
- if(OFFSET_BACK in dna.species.offset_features)
- back_overlay.pixel_x += dna.species.offset_features[OFFSET_BACK][1]
- back_overlay.pixel_y += dna.species.offset_features[OFFSET_BACK][2]
- overlays_standing[BACK_LAYER] = back_overlay
- apply_overlay(BACK_LAYER)
+ if(dna.species.should_render())
+ ..()
+ var/mutable_appearance/back_overlay = overlays_standing[BACK_LAYER]
+ if(back_overlay)
+ remove_overlay(BACK_LAYER)
+ if(OFFSET_BACK in dna.species.offset_features)
+ back_overlay.pixel_x += dna.species.offset_features[OFFSET_BACK][1]
+ back_overlay.pixel_y += dna.species.offset_features[OFFSET_BACK][2]
+ overlays_standing[BACK_LAYER] = back_overlay
+ apply_overlay(BACK_LAYER)
/proc/wear_alpha_masked_version(state, icon, layer, female, alpha_mask)
var/mask = "-[alpha_mask]"
@@ -710,8 +718,6 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
..()
update_hair()
-
-
/mob/living/carbon/human/proc/update_observer_view(obj/item/I, inventory)
if(observers && observers.len)
for(var/M in observers)
@@ -729,15 +735,17 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
// Only renders the head of the human
/mob/living/carbon/human/proc/update_body_parts_head_only()
- if (!dna)
+ if(!dna)
return
- if (!dna.species)
+ if(!dna.species)
+ return
+
+ if(dna.species.should_render())
return
var/obj/item/bodypart/HD = get_bodypart("head")
-
- if (!istype(HD))
+ if(!istype(HD))
return
HD.update_limb()
@@ -748,7 +756,7 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
if(HD && !(HAS_TRAIT(src, TRAIT_HUSK)))
// lipstick
if(lip_style && (LIPS in dna.species.species_traits))
- var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[lip_style]", -BODY_LAYER)
+ var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/lips.dmi', "lips_[lip_style]", -BODY_LAYER)
lip_overlay.color = lip_color
if(OFFSET_LIPS in dna.species.offset_features)
lip_overlay.pixel_x += dna.species.offset_features[OFFSET_LIPS][1]
@@ -759,10 +767,17 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
if(!(NOEYES in dna.species.species_traits))
var/has_eyes = getorganslot(ORGAN_SLOT_EYES)
if(!has_eyes)
- add_overlay(mutable_appearance('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER))
+ add_overlay(mutable_appearance('icons/mob/eyes.dmi', "eyes_missing", -BODY_LAYER))
else
- var/mutable_appearance/left_eye = mutable_appearance('icons/mob/human_face.dmi', "left_eye", -BODY_LAYER)
- var/mutable_appearance/right_eye = mutable_appearance('icons/mob/human_face.dmi', "right_eye", -BODY_LAYER)
+ var/left_state = DEFAULT_LEFT_EYE_STATE
+ var/right_state = DEFAULT_RIGHT_EYE_STATE
+ if(dna.species)
+ var/eye_type = dna.species.eye_type
+ if(GLOB.eye_types[eye_type])
+ left_state = eye_type + "_left_eye"
+ right_state = eye_type + "_right_eye"
+ var/mutable_appearance/left_eye = mutable_appearance('icons/mob/eyes.dmi', left_state, -BODY_LAYER)
+ var/mutable_appearance/right_eye = mutable_appearance('icons/mob/eyes.dmi', right_state, -BODY_LAYER)
if((EYECOLOR in dna.species.species_traits) && has_eyes)
left_eye.color = "#" + left_eye_color
right_eye.color = "#" + right_eye_color
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 8f181d47fd..30785a0103 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -502,19 +502,14 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
//this updates all special effects: stun, sleeping, knockdown, druggy, stuttering, etc..
/mob/living/carbon/handle_status_effects()
..()
- if(getStaminaLoss() && !SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //CIT CHANGE - prevents stamina regen while combat mode is active
- adjustStaminaLoss(!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL)
+ var/combat_mode = SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)
+ if(getStaminaLoss() && !HAS_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION))
+ adjustStaminaLoss((!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL) * (combat_mode? 0.25 : 1))
if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && incomingstammult != 1)
incomingstammult = max(0.01, incomingstammult)
incomingstammult = min(1, incomingstammult*2)
- //CIT CHANGES START HERE. STAMINA BUFFER STUFF
- if(bufferedstam && world.time > stambufferregentime)
- var/drainrate = max((bufferedstam*(bufferedstam/(5)))*0.1,1)
- bufferedstam = max(bufferedstam - drainrate, 0)
- //END OF CIT CHANGES
-
var/restingpwr = 1 + 4 * !CHECK_MOBILITY(src, MOBILITY_STAND)
//Dizziness
diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm
index 1e00815f24..bfe04c8622 100644
--- a/code/modules/mob/living/carbon/monkey/update_icons.dm
+++ b/code/modules/mob/living/carbon/monkey/update_icons.dm
@@ -34,7 +34,7 @@
hair_hidden = 1
if(!hair_hidden)
if(!getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain
- overlays_standing[HAIR_LAYER] = mutable_appearance('icons/mob/human_face.dmi', "debrained", -HAIR_LAYER)
+ overlays_standing[HAIR_LAYER] = mutable_appearance('icons/mob/human_parts.dmi', "debrained", -HAIR_LAYER)
apply_overlay(HAIR_LAYER)
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 1d78979cbd..4ee52a08a6 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -562,7 +562,7 @@
if(. && iscarbon(user))
var/mob/living/carbon/C = user
if(isjellyperson(C))
- pick(playsound(C, 'sound/effects/attackblob.ogg', 50, 1),playsound(C, 'sound/effects/blobattack.ogg', 50, 1))
+ playsound(C, 'sound/effects/attackblob.ogg', 50, 1)
/datum/emote/living/audio_emote/blurp
key = "blurp"
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 8dac56a8c9..57d688bde3 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -8,6 +8,8 @@
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
faction += "[REF(src)]"
+ stamina_buffer = INFINITY
+ UpdateStaminaBuffer()
GLOB.mob_living_list += src
/mob/living/prepare_huds()
@@ -842,12 +844,12 @@
return
var/strip_mod = 1
var/strip_silence = FALSE
- if (ishuman(src)) //carbon doesn't actually wear gloves
+ if(ishuman(src)) //carbon doesn't actually wear gloves
var/mob/living/carbon/C = src
- var/obj/item/clothing/gloves/g = C.gloves
- if (istype(g))
- strip_mod = g.strip_mod
- strip_silence = g.strip_silence
+ var/obj/item/clothing/gloves/G = C.gloves
+ if(istype(G))
+ strip_mod = G.strip_mod
+ strip_silence = G.strip_silence
if (!strip_silence)
who.visible_message("[src] tries to remove [who]'s [what.name].", \
"[src] tries to remove your [what.name].", target = src,
@@ -1257,7 +1259,7 @@
SetUnconscious(clamp_unconscious_to)
HealAllImmobilityUpTo(clamp_immobility_to)
adjustStaminaLoss(min(0, -stamina_boost))
- adjustStaminaLossBuffered(min(0, -stamina_buffer_boost))
+ RechargeStaminaBuffer(stamina_buffer_boost) // this MUST GO AFTER ADJUSTSTAMINALOSS.
if(scale_stamina_loss_recovery)
adjustStaminaLoss(min(-((getStaminaLoss() - stamina_loss_recovery_bypass) * scale_stamina_loss_recovery), 0))
if(put_on_feet)
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index 2493509e16..db472df388 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -8,6 +8,8 @@
active_block_item = null
REMOVE_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT)
REMOVE_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION, ACTIVE_BLOCK_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION, ACTIVE_BLOCK_TRAIT)
remove_movespeed_modifier(/datum/movespeed_modifier/active_block)
var/datum/block_parry_data/data = I.get_block_parry_data()
DelayNextAction(data.block_end_click_cd_add)
@@ -27,6 +29,10 @@
ADD_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT) //probably should be something else at some point
if(data.block_lock_sprinting)
ADD_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT)
+ if(data.block_no_stamina_regeneration)
+ ADD_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION, ACTIVE_BLOCK_TRAIT)
+ if(data.block_no_stambuffer_regeneration)
+ ADD_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION, ACTIVE_BLOCK_TRAIT)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/active_block, multiplicative_slowdown = data.block_slowdown)
active_block_effect_start()
return TRUE
@@ -192,7 +198,7 @@
var/held_index = C.get_held_index_of_item(src)
var/obj/item/bodypart/BP = C.hand_bodyparts[held_index]
if(!BP?.body_zone)
- return C.adjustStaminaLossBuffered(stamina_amount) //nah
+ return C.adjustStaminaLoss(stamina_amount) //nah
var/zone = BP.body_zone
var/stamina_to_zone = data.block_stamina_limb_ratio * stamina_amount
var/stamina_to_chest = stamina_amount - stamina_to_zone
@@ -200,9 +206,9 @@
stamina_to_chest -= stamina_buffered
C.apply_damage(stamina_to_zone, STAMINA, zone)
C.apply_damage(stamina_to_chest, STAMINA, BODY_ZONE_CHEST)
- C.adjustStaminaLossBuffered(stamina_buffered)
+ C.adjustStaminaLoss(stamina_buffered)
else
- owner.adjustStaminaLossBuffered(stamina_amount)
+ owner.adjustStaminaLoss(stamina_amount)
/obj/item/proc/on_active_block(mob/living/owner, atom/object, damage, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction)
return
@@ -231,6 +237,7 @@
active_block_do_stamina_damage(owner, object, stamina_cost, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED] = damage - final_damage
block_return[BLOCK_RETURN_SET_DAMAGE_TO] = final_damage
+ block_return[BLOCK_RETURN_MITIGATION_PERCENT] = clamp(1 - (final_damage / damage), 0, 1)
. = BLOCK_SHOULD_CHANGE_DAMAGE
if((final_damage <= 0) || (damage <= 0))
. |= BLOCK_SUCCESS //full block
diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm
index b6706d0548..7353add745 100644
--- a/code/modules/mob/living/living_active_parry.dm
+++ b/code/modules/mob/living/living_active_parry.dm
@@ -68,12 +68,13 @@
// can always implement it later, whatever.
if((data.parry_respect_clickdelay && !CheckActionCooldown()) || ((parry_end_time_last + data.parry_cooldown) > world.time))
to_chat(src, "You are not ready to parry (again)!")
- return
+ return FALSE
// Point of no return, make sure everything is set.
parrying = method
if(method == ITEM_PARRY)
active_parry_item = using_item
- adjustStaminaLossBuffered(data.parry_stamina_cost)
+ if(!UseStaminaBuffer(data.parry_stamina_cost, TRUE))
+ return FALSE
parry_start_time = world.time
successful_parries = list()
addtimer(CALLBACK(src, .proc/end_parry_sequence), full_parry_duration)
@@ -244,7 +245,14 @@
if((return_list[BLOCK_RETURN_MITIGATION_PERCENT] >= 100) || (damage <= 0))
. |= BLOCK_SUCCESS
var/list/effect_text
- if(efficiency >= data.parry_efficiency_to_counterattack)
+ var/pacifist_counter_check = TRUE
+ if(HAS_TRAIT(src, TRAIT_PACIFISM))
+ switch(parrying)
+ if(ITEM_PARRY)
+ pacifist_counter_check = (!active_parry_item.force || active_parry_item.damtype == STAMINA)
+ else
+ pacifist_counter_check = FALSE //Both martial and unarmed counter attacks generally are harmful, so no need to have the same line twice.
+ if(efficiency >= data.parry_efficiency_to_counterattack && pacifist_counter_check)
effect_text = run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency)
if(data.parry_flags & PARRY_DEFAULT_HANDLE_FEEDBACK)
handle_parry_feedback(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, effect_text)
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 47dae8849d..08ef674b33 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -74,8 +74,12 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Ratio of stamina incurred by chest (so after [block_stamina_limb_ratio] runs) that is buffered.
var/block_stamina_buffer_ratio = 1
- /// Stamina dealt directly via adjustStaminaLossBuffered() per SECOND of block.
+ /// Stamina dealt directly via UseStaminaBuffer() per SECOND of block.
var/block_stamina_cost_per_second = 1.5
+ /// Prevent stamina buffer regeneration while block?
+ var/block_no_stambuffer_regeneration = TRUE
+ /// Prevent stamina regeneration while block?
+ var/block_no_stamina_regeneration = FALSE
/// Bitfield for attack types that we can block while down. This will work in any direction.
var/block_resting_attack_types_anydir = ATTACK_TYPE_MELEE | ATTACK_TYPE_UNARMED | ATTACK_TYPE_TACKLE
@@ -307,7 +311,7 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/mob/living/proc/handle_block_parry(seconds = 1)
if(combat_flags & COMBAT_FLAG_ACTIVE_BLOCKING)
var/datum/block_parry_data/data = return_block_parry_datum(active_block_item.block_parry_data)
- adjustStaminaLossBuffered(data.block_stamina_cost_per_second * seconds)
+ UseStaminaBuffer(data.block_stamina_cost_per_second * seconds)
/mob/living/on_item_dropped(obj/item/I)
if(I == active_block_item)
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 5495d37297..5621fab9c1 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -53,6 +53,7 @@
var/hallucination = 0 //Directly affects how long a mob will hallucinate for
+ var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
var/timeofdeath = 0
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
@@ -148,9 +149,6 @@
var/combatmessagecooldown = 0
var/incomingstammult = 1
- var/bufferedstam = 0
- var/stambuffer = 20
- var/stambufferregentime
//Sprint buffer---
var/sprint_buffer = 42 //Tiles
@@ -159,3 +157,13 @@
var/sprint_buffer_regen_last = 0 //last world.time this was regen'd for math.
var/sprint_stamina_cost = 0.70 //stamina loss per tile while insufficient sprint buffer.
//---End
+
+ // Stamina Buffer---
+ /// Our stamina buffer
+ var/stamina_buffer
+ /// Stamina buffer regen modifier
+ var/stamina_buffer_regen_mod = 1
+ /// Last time stamina buffer regen was done
+ var/stamina_buffer_regen_last = 0
+ /// Last time we used stamina buffer
+ var/stamina_buffer_last_use = 0
diff --git a/code/modules/mob/living/living_mobility.dm b/code/modules/mob/living/living_mobility.dm
index 654a979445..8c6cf9d207 100644
--- a/code/modules/mob/living/living_mobility.dm
+++ b/code/modules/mob/living/living_mobility.dm
@@ -5,12 +5,15 @@
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOMOVE), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOPICKUP), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOUSE), .proc/update_mobility)
+ RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOREST), .proc/update_mobility)
//Stuff like mobility flag updates, resting updates, etc.
//Force-set resting variable, without needing to resist/etc.
/mob/living/proc/set_resting(new_resting, silent = FALSE, updating = TRUE)
if(new_resting != resting)
+ if(resting && HAS_TRAIT(src, TRAIT_MOBILITY_NOREST)) //forcibly block resting from all sources - BE CAREFUL WITH THIS TRAIT
+ return
resting = new_resting
if(!silent)
to_chat(src, "You are now [resting? "resting" : "getting up"].")
@@ -87,7 +90,7 @@
var/canstand_involuntary = conscious && !stat_softcrit && !knockdown && !chokehold && !paralyze && (ignore_legs || has_legs) && !(buckled && buckled.buckle_lying) && !(combat_flags & COMBAT_FLAG_HARD_STAMCRIT)
var/canstand = canstand_involuntary && !resting
- var/should_be_lying = !canstand
+ var/should_be_lying = !canstand && !HAS_TRAIT(src, TRAIT_MOBILITY_NOREST)
if(buckled)
if(buckled.buckle_lying != -1)
should_be_lying = buckled.buckle_lying
@@ -173,4 +176,6 @@
else
remove_movespeed_modifier(/datum/movespeed_modifier/limbless)
+ update_movespeed()
+
return mobility_flags
diff --git a/code/modules/mob/living/living_sprint.dm b/code/modules/mob/living/living_sprint.dm
index dc0f6d2767..3ef67c9edd 100644
--- a/code/modules/mob/living/living_sprint.dm
+++ b/code/modules/mob/living/living_sprint.dm
@@ -29,6 +29,7 @@
if(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE)
return
ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE)
+ add_movespeed_modifier(/datum/movespeed_modifier/sprinting)
if(update_icon)
update_sprint_icon()
@@ -36,6 +37,7 @@
if(!(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) || (combat_flags & COMBAT_FLAG_SPRINT_FORCED))
return
DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE)
+ remove_movespeed_modifier(/datum/movespeed_modifier/sprinting)
if(update_icon)
update_sprint_icon()
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 66c2cd96c7..4c03e74d70 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -82,6 +82,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return new_msg
/mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
+ set waitfor = FALSE
var/static/list/crit_allowed_modes = list(MODE_WHISPER = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
var/talk_key = get_key(message)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 6143bde602..83df3ffba5 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -454,10 +454,12 @@
if(U.action(src))
to_chat(user, "You apply the upgrade to [src].")
if(U.one_use)
+ U.afterInstall(src)
qdel(U)
else
U.forceMove(src)
upgrades += U
+ U.afterInstall(src)
else
to_chat(user, "Upgrade error.")
U.forceMove(drop_location())
@@ -1130,10 +1132,6 @@
bellyup = 1
update_icons()
-/mob/living/silicon/robot/adjustStaminaLossBuffered(amount, updating_health = 1)
- if(istype(cell))
- cell.charge -= amount * 5
-
/mob/living/silicon/robot/verb/viewmanifest()
set category = "Robot Commands"
set name = "View Crew Manifest"
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 3f28fd6e01..8375d621d4 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -236,7 +236,7 @@ Auto Patrol[]"},
if(targets.len>0)
var/mob/living/carbon/t = pick(targets)
if((t.stat!=2) && (t.lying != 1) && (!t.handcuffed)) //we don't shoot people who are dead, cuffed or lying down.
- shootAt(t)
+ INVOKE_ASYNC(src, .proc/shootAt, t)
switch(mode)
if(BOT_IDLE) // idle
@@ -254,7 +254,7 @@ Auto Patrol[]"},
if(target) // make sure target exists
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
- stun_attack(target)
+ INVOKE_ASYNC(src, .proc/stun_attack, target)
mode = BOT_PREP_ARREST
anchored = TRUE
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index 954e968bd7..ae045dbd26 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -22,7 +22,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
icon_state = "magicbase"
icon_living = "magicbase"
icon_dead = "magicbase"
- speed = 0
+ speed = -0.5
blood_volume = 0
a_intent = INTENT_HARM
stop_automated_movement = 1
@@ -511,7 +511,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
var/used_message = "All the cards seem to be blank now."
var/failure_message = "..And draw a card! It's...blank? Maybe you should try again later."
var/ling_failure = "The deck refuses to respond to a souless creature such as you."
- var/list/possible_guardians = list("Assassin", "Chaos", "Charger", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
+ var/list/possible_guardians = list("Assassin", "Chaos", "Gravitokinetic", "Charger", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
var/random = TRUE
var/allowmultiple = FALSE
var/allowling = TRUE
@@ -559,6 +559,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
if("Chaos")
pickedtype = /mob/living/simple_animal/hostile/guardian/fire
+ if("Gravitokinetic")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/gravitokinetic
+
if("Standard")
pickedtype = /mob/living/simple_animal/hostile/guardian/punch
@@ -615,10 +618,10 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
random = FALSE
/obj/item/guardiancreator/choose/dextrous
- possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
+ possible_guardians = list("Assassin", "Chaos", "Gravitokinetic", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
/obj/item/guardiancreator/choose/wizard
- possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard")
+ possible_guardians = list("Assassin", "Chaos", "Gravitokinetic", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard")
allowmultiple = TRUE
/obj/item/guardiancreator/tech
@@ -634,7 +637,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
ling_failure = "The holoparasites recoil in horror. They want nothing to do with a creature like you."
/obj/item/guardiancreator/tech/choose/traitor
- possible_guardians = list("Assassin", "Chaos", "Charger", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
+ possible_guardians = list("Assassin", "Chaos", "Gravitokinetic", "Charger", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
allowling = FALSE
/obj/item/guardiancreator/tech/choose/traitor/check_uplink_validity()
@@ -644,10 +647,10 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
random = FALSE
/obj/item/guardiancreator/tech/choose/dextrous
- possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
+ possible_guardians = list("Assassin", "Chaos", "Gravitokinetic", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support")
/obj/item/guardiancreator/tech/choose/nukie // lacks support and protector as encouraging nukies to play turtle isnt fun and dextrous is epic
- possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Ranged", "Standard")
+ possible_guardians = list("Assassin", "Chaos", "Gravitokinetic", "Charger", "Dextrous", "Explosive", "Lightning", "Ranged", "Standard")
/obj/item/guardiancreator/tech/choose/nukie/check_uplink_validity()
return !used
@@ -666,6 +669,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
Explosive: High damage resist and medium power attack that may explosively teleport targets. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay.
+ Gravitokinetic: Attacks will apply crushing gravity to the target. Can target the ground as well to slow targets advancing on you, but this will affect the user.
+
Lightning: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.
Protector: Causes you to teleport to it when out of range, unlike other parasites. Has two modes; Combat, where it does and takes medium damage, and Protection, where it does and takes almost no damage but moves slightly slower.
@@ -695,6 +700,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
Explosive: High damage resist and medium power attack that may explosively teleport targets. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay.
+ Gravitokinetic: Attacks will apply crushing gravity to the target. Can target the ground as well to slow targets advancing on you, but this will affect the user.
+
Lightning: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.
Protector: Causes you to teleport to it when out of range, unlike other parasites. Has two modes; Combat, where it does and takes medium damage, and Protection, where it does and takes almost no damage but moves slightly slower.
@@ -720,6 +727,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
Explosive: High damage resist and medium power attack that may explosively teleport targets. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay.
+ Gravitokinetic: Attacks will apply crushing gravity to the target. Can target the ground as well to slow targets advancing on you, but this will affect the user.
+
Lightning: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.
Ranged: Has two modes. Ranged; which fires a constant stream of weak, armor-ignoring projectiles. Scout; Cannot attack, but can move through walls and is quite hard to see. Can lay surveillance snares, which alert it when crossed, in either mode.
diff --git a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
index 3bc079f6d5..b5bb91d34f 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
@@ -1,5 +1,7 @@
//Assassin
/mob/living/simple_animal/hostile/guardian/assassin
+ melee_damage_lower = 15
+ melee_damage_upper = 15
attack_verb_continuous = "slashes"
attack_verb_simple = "slash"
attack_sound = 'sound/weapons/bladeslice.ogg'
diff --git a/code/modules/mob/living/simple_animal/guardian/types/charger.dm b/code/modules/mob/living/simple_animal/guardian/types/charger.dm
index 0b4952aa9e..9060350df4 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/charger.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/charger.dm
@@ -1,8 +1,11 @@
//Charger
/mob/living/simple_animal/hostile/guardian/charger
+ melee_damage_lower = 15
+ melee_damage_upper = 15
ranged = 1 //technically
ranged_message = "charges"
ranged_cooldown_time = 20
+ speed = -1
damage_coeff = list(BRUTE = 0.2, BURN = 0.5, TOX = 0.5, CLONE = 0.5, STAMINA = 0, OXY = 0.5)
playstyle_string = "As a charger type you do medium damage, take half damage, have near immunity to brute damage, move very fast, and can charge at a location, damaging any target hit and forcing them to drop any items they are holding."
magic_fluff_string = "..And draw the Hunter, an alien master of rapid assault."
diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
index b9037ff4a4..39a7bfaebd 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
@@ -1,5 +1,7 @@
//Bomb
/mob/living/simple_animal/hostile/guardian/bomb
+ melee_damage_lower = 15
+ melee_damage_upper = 15
damage_coeff = list(BRUTE = 0.6, BURN = 0.6, TOX = 0.6, CLONE = 0.6, STAMINA = 0, OXY = 0.6)
playstyle_string = "As an explosive type, you have moderate close combat abilities, take half damage, may explosively teleport targets on attack, and are capable of converting nearby items and objects into disguised bombs via alt click."
magic_fluff_string = "..And draw the Scientist, master of explosive death."
diff --git a/code/modules/mob/living/simple_animal/guardian/types/gravitokinetic.dm b/code/modules/mob/living/simple_animal/guardian/types/gravitokinetic.dm
new file mode 100644
index 0000000000..34948d3e0c
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/guardian/types/gravitokinetic.dm
@@ -0,0 +1,73 @@
+//gravitokinetic
+/mob/living/simple_animal/hostile/guardian/gravitokinetic
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75)
+ playstyle_string = "As a gravitokinetic type, you can alt click to make the gravity on the ground stronger, and punching applies this effect to a target."
+ magic_fluff_string = "..And draw the Singularity, an anomalous force of terror."
+ tech_fluff_string = "Boot sequence complete. Gravitokinetic modules loaded. Holoparasite swarm online."
+ carp_fluff_string = "CARP CARP CARP! Caught one! It's a gravitokinetic carp! Now do you understand the gravity of the situation?"
+ var/list/gravito_targets = list()
+ var/gravity_power_range = 10 //how close the stand must stay to the target to keep the heavy gravity
+
+///Removes gravity from affected mobs upon guardian death to prevent permanent effects
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/death()
+ . = ..()
+ for(var/i in gravito_targets)
+ remove_gravity(i)
+
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/AttackingTarget()
+ . = ..()
+ if(isliving(target) && target != src && target != summoner)
+ to_chat(src, "Your punch has applied heavy gravity to [target]!")
+ add_gravity(target, 5)
+ to_chat(target, "Everything feels really heavy!")
+
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/AltClickOn(atom/A)
+ if(isopenturf(A) && is_deployed() && stat != DEAD && in_range(src, A) && !incapacitated())
+ var/turf/T = A
+ if(isspaceturf(T))
+ to_chat(src, "You cannot add gravity to space!")
+ return
+ visible_message("[src] slams their fist into the [T]!", "You modify the gravity of the [T].")
+ do_attack_animation(T)
+ add_gravity(T, 3)
+ return
+ return ..()
+
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/Recall(forced)
+ . = ..()
+ to_chat(src, "You have released your gravitokinetic powers!")
+ for(var/i in gravito_targets)
+ remove_gravity(i)
+
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/Manifest(forced)
+ . = ..()
+ //just make sure to reapply a gravity immunity wherever you summon. it can be overridden but not by you at least
+ summoner.AddElement(/datum/element/forced_gravity, 1)
+ AddElement(/datum/element/forced_gravity, 1)
+
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/Moved(oldLoc, dir)
+ . = ..()
+ for(var/i in gravito_targets)
+ if(get_dist(src, i) > gravity_power_range)
+ remove_gravity(i)
+
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/add_gravity(atom/A, new_gravity = 3)
+ if(gravito_targets[A])
+ return
+ A.AddElement(/datum/element/forced_gravity, new_gravity)
+ gravito_targets[A] = new_gravity
+ RegisterSignal(A, COMSIG_MOVABLE_MOVED, .proc/__distance_check)
+ playsound(src, 'sound/effects/gravhit.ogg', 100, TRUE)
+
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/remove_gravity(atom/target)
+ if(isnull(gravito_targets[target]))
+ return
+ UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
+ target.RemoveElement(/datum/element/forced_gravity, gravito_targets[target])
+ gravito_targets -= target
+
+/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/__distance_check(atom/movable/AM, OldLoc, Dir, Forced)
+ if(get_dist(src, AM) > gravity_power_range)
+ remove_gravity(AM)
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/guardian/types/protector.dm b/code/modules/mob/living/simple_animal/guardian/types/protector.dm
index cf6bd3cdb5..99272a6d3f 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/protector.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/protector.dm
@@ -1,5 +1,7 @@
//Protector
/mob/living/simple_animal/hostile/guardian/protector
+ melee_damage_lower = 15
+ melee_damage_upper = 15
range = 15 //worse for it due to how it leashes
damage_coeff = list(BRUTE = 0.4, BURN = 0.4, TOX = 0.4, CLONE = 0.4, STAMINA = 0, OXY = 0.4)
playstyle_string = "As a protector type you cause your summoner to leash to you instead of you leashing to them and have two modes; Combat Mode, where you do and take medium damage, and Protection Mode, where you do and take almost no damage, but move slightly slower."
@@ -31,9 +33,10 @@
cooldown = world.time + 10
if(toggle)
cut_overlays()
- melee_damage_lower = 15
- melee_damage_upper = 15
- speed = 0
+ add_overlay(cooloverlay) //readd the guardian's colors
+ melee_damage_lower = initial(melee_damage_lower)
+ melee_damage_upper = initial(melee_damage_upper)
+ speed = initial(speed)
damage_coeff = list(BRUTE = 0.4, BURN = 0.4, TOX = 0.4, CLONE = 0.4, STAMINA = 0, OXY = 0.4)
to_chat(src, "You switch to combat mode.")
toggle = FALSE
diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm
index eee3eb0cdb..b51552acd2 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/support.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm
@@ -4,6 +4,8 @@
friendly_verb_continuous = "heals"
friendly_verb_simple = "heal"
damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7)
+ melee_damage_lower = 15
+ melee_damage_upper = 15
playstyle_string = "As a support type, you have 30% damage reduction and may toggle your basic attacks to a healing mode. In addition, Alt-Clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay."
magic_fluff_string = "..And draw the CMO, a potent force of life... and death."
carp_fluff_string = "CARP CARP CARP! You caught a support carp. It's a kleptocarp!"
@@ -43,15 +45,15 @@
if(src.loc == summoner)
if(toggle)
a_intent = INTENT_HARM
- speed = 0
+ speed = initial(speed)
damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7)
- melee_damage_lower = 15
- melee_damage_upper = 15
+ melee_damage_lower = initial(melee_damage_lower)
+ melee_damage_upper = initial(melee_damage_upper)
to_chat(src, "You switch to combat mode.")
toggle = FALSE
else
a_intent = INTENT_HELP
- speed = 1
+ speed = initial(speed)
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
melee_damage_lower = 0
melee_damage_upper = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 186fe36a10..37eb9b7f67 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -52,6 +52,19 @@
var/lose_patience_timer_id //id for a timer to call LoseTarget(), used to stop mobs fixating on a target they can't reach
var/lose_patience_timeout = 300 //30 seconds by default, so there's no major changes to AI behaviour, beyond actually bailing if stuck forever
+ ///When a target is found, will the mob attempt to charge at it's target?
+ var/charger = FALSE
+ ///Tracks if the target is actively charging.
+ var/charge_state = FALSE
+ ///In a charge, how many tiles will the charger travel?
+ var/charge_distance = 3
+ ///How often can the charging mob actually charge? Effects the cooldown between charges.
+ var/charge_frequency = 6 SECONDS
+ ///If the mob is charging, how long will it stun it's target on success, and itself on failure?
+ var/knockdown_time = 3 SECONDS
+ ///Declares a cooldown for potential charges right off the bat.
+ COOLDOWN_DECLARE(charge_cooldown)
+
/mob/living/simple_animal/hostile/Initialize()
. = ..()
@@ -292,6 +305,9 @@
if(ranged) //We ranged? Shoot at em
if(!target.Adjacent(targets_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
OpenFire(target)
+ if(charger && (target_distance > minimum_distance) && (target_distance <= charge_distance))//Attempt to close the distance with a charge.
+ enter_charge(target)
+ return TRUE
if(!Process_Spacemove()) //Drifting
walk(src,0)
return 1
@@ -599,3 +615,64 @@ mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with mega
. += M
else if (M.loc.type in hostile_machines)
. += M.loc
+
+
+/**
+ * Proc that handles a charge attack windup for a mob.
+ */
+/mob/living/simple_animal/hostile/proc/enter_charge(var/atom/target)
+ if((mobility_flags & (MOBILITY_MOVE | MOBILITY_STAND)) != (MOBILITY_MOVE | MOBILITY_STAND) || charge_state)
+ return FALSE
+
+ if(!(COOLDOWN_FINISHED(src, charge_cooldown)) || !has_gravity() || !target.has_gravity())
+ return FALSE
+ Shake(15, 15, 1 SECONDS)
+ addtimer(CALLBACK(src, .proc/handle_charge_target, target), 1.5 SECONDS, TIMER_STOPPABLE)
+
+/**
+ * Proc that throws the mob at the target after the windup.
+ */
+/mob/living/simple_animal/hostile/proc/handle_charge_target(var/atom/target)
+ charge_state = TRUE
+ throw_at(target, charge_distance, 1, src, FALSE, TRUE, callback = CALLBACK(src, .proc/charge_end))
+ COOLDOWN_START(src, charge_cooldown, charge_frequency)
+ return TRUE
+
+/**
+ * Proc that handles a charge attack after it's concluded.
+ */
+/mob/living/simple_animal/hostile/proc/charge_end()
+ charge_state = FALSE
+
+/**
+ * Proc that handles the charge impact of the charging mob.
+ */
+/mob/living/simple_animal/hostile/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ if(!charge_state)
+ return ..()
+
+ if(hit_atom)
+ if(isliving(hit_atom))
+ var/mob/living/L = hit_atom
+ var/blocked = FALSE
+ if(ishuman(hit_atom))
+ var/mob/living/carbon/human/H = hit_atom
+ var/list/return_list = list()
+ if(H.mob_run_block(src, 0, "the [name]", ATTACK_TYPE_TACKLE, 0, src, null, return_list) & BLOCK_SUCCESS)
+ blocked = TRUE
+ if(!blocked)
+ blocked = return_list[BLOCK_RETURN_MITIGATION_PERCENT]
+ if(!blocked)
+ L.visible_message("[src] charges on [L]!", "[src] charges into you!")
+ L.Knockdown(knockdown_time)
+ else
+ Stun((knockdown_time * 2), 1, 1)
+ charge_end()
+ else if(hit_atom.density && !hit_atom.CanPass(src))
+ visible_message("[src] smashes into [hit_atom]!")
+ Stun((knockdown_time * 2), 1, 1)
+
+ if(charge_state)
+ charge_state = FALSE
+ update_icons()
+ update_mobility()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/lobsterosity.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/lobsterosity.dm
new file mode 100644
index 0000000000..140042024d
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/lobsterosity.dm
@@ -0,0 +1,42 @@
+/**
+ * Lobstrosities, the poster boy of charging AI mobs. Drops crab meat and bones.
+ * Outside of charging, it's intended behavior is that it is generally slow moving, but makes up for that with a knockdown attack to score additional hits.
+ */
+/mob/living/simple_animal/hostile/asteroid/lobstrosity
+ name = "arctic lobstrosity"
+ desc = "A marvel of evolution gone wrong, the frosty ice produces underground lakes where these ill tempered seafood gather. Beware its charge."
+ icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
+ icon_state = "arctic_lobstrosity"
+ icon_living = "arctic_lobstrosity"
+ icon_dead = "arctic_lobstrosity_dead"
+ mob_biotypes = MOB_ORGANIC|MOB_BEAST
+ mouse_opacity = MOUSE_OPACITY_ICON
+ friendly_verb_continuous = "chitters at"
+ friendly_verb_simple = "chits at"
+ speak_emote = list("chitters")
+ speed = 3
+ move_to_delay = 20
+ maxHealth = 150
+ health = 150
+ obj_damage = 15
+ melee_damage_lower = 15
+ melee_damage_upper = 19
+ attack_verb_continuous = "snips"
+ attack_verb_simple = "snip"
+ attack_sound = 'sound/weapons/bite.ogg'
+ weather_immunities = list("snow")
+ vision_range = 5
+ aggro_vision_range = 7
+ charger = TRUE
+ charge_distance = 4
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/crab = 2, /obj/item/stack/sheet/bone = 2)
+ robust_searching = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
+ gold_core_spawnable = HOSTILE_SPAWN
+
+/mob/living/simple_animal/hostile/asteroid/lobstrosity/lava
+ name = "tropical lobstrosity"
+ desc = "A marvel of evolution gone wrong, the sulfur lakes of lavaland have given them a vibrant, red hued shell. Beware its charge."
+ icon_state = "lobstrosity"
+ icon_living = "lobstrosity"
+ icon_dead = "lobstrosity_dead"
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm
index 2c94739180..f6ab2a1a9e 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm
@@ -59,12 +59,12 @@
/mob/living/simple_animal/hostile/retaliate/ghost/proc/give_hair()
if(ghost_hair_style != null)
- ghost_hair = mutable_appearance('icons/mob/human_face.dmi', "hair_[ghost_hair_style]", -HAIR_LAYER)
+ ghost_hair = mutable_appearance('icons/mob/hair.dmi', "hair_[ghost_hair_style]", -HAIR_LAYER)
ghost_hair.alpha = 200
ghost_hair.color = ghost_hair_color
add_overlay(ghost_hair)
if(ghost_facial_hair_style != null)
- ghost_facial_hair = mutable_appearance('icons/mob/human_face.dmi', "facial_[ghost_facial_hair_style]", -HAIR_LAYER)
+ ghost_facial_hair = mutable_appearance('icons/mob/hair.dmi', "facial_[ghost_facial_hair_style]", -HAIR_LAYER)
ghost_facial_hair.alpha = 200
ghost_facial_hair.color = ghost_facial_hair_color
add_overlay(ghost_facial_hair)
diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm
index b3523fc42c..59bd67e42a 100644
--- a/code/modules/mob/living/simple_animal/hostile/wizard.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm
@@ -62,6 +62,9 @@
/mob/living/simple_animal/hostile/wizard/handle_automated_action()
. = ..()
+ INVOKE_ASYNC(src, .proc/AutomatedCast)
+
+/mob/living/simple_animal/hostile/wizard/proc/AutomatedCast()
if(target && next_cast < world.time)
if((get_dir(src,target) in list(SOUTH,EAST,WEST,NORTH)) && fireball.cast_check(0,src)) //Lined up for fireball
src.setDir(get_dir(src,target))
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 3ca29b6746..1ff7e2f799 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -436,12 +436,7 @@
newspeak.Add(possible_phrase)
speak = newspeak
- //Search for item to steal
- parrot_interest = search_for_item()
- if(parrot_interest)
- emote("me", EMOTE_VISIBLE, "looks in [parrot_interest]'s direction and takes flight.")
- parrot_state = PARROT_SWOOP | PARROT_STEAL
- icon_state = icon_living
+ INVOKE_ASYNC(src, .proc/attempt_item_theft)
return
//-----WANDERING - This is basically a 'I dont know what to do yet' state
@@ -620,6 +615,14 @@
parrot_lastmove = src.loc
return 0
+/mob/living/simple_animal/parrot/proc/attempt_item_theft()
+ //Search for item to steal
+ search_for_item()
+ if(parrot_interest)
+ emote("me", EMOTE_VISIBLE, "looks in [parrot_interest]'s direction and takes flight.")
+ parrot_state = PARROT_SWOOP | PARROT_STEAL
+ icon_state = icon_living
+
/mob/living/simple_animal/parrot/proc/search_for_item()
var/item
for(var/atom/movable/AM in view(src))
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index b192182c71..5fa6a0c22d 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -6,6 +6,7 @@
gender = PLURAL //placeholder
///How much blud it has for bloodsucking
blood_volume = 550
+ rad_flags = RAD_NO_CONTAMINATE
status_flags = CANPUSH
diff --git a/code/modules/mob/living/stamina_buffer.dm b/code/modules/mob/living/stamina_buffer.dm
new file mode 100644
index 0000000000..a410df582b
--- /dev/null
+++ b/code/modules/mob/living/stamina_buffer.dm
@@ -0,0 +1,56 @@
+/**
+ * Attempts to use an amount of stamina from our stamina buffer.
+ * Does not use anything if we don't have enough.
+ *
+ * Returns TRUE or FALSE based on if we have it.
+ */
+/mob/living/proc/UseStaminaBuffer(amount, warn = FALSE, considered_action = TRUE)
+ if(!(combat_flags & COMBAT_FLAG_STAMINA_BUFFER))
+ return TRUE
+ if(stamina_buffer < amount)
+ var/stamina_health = getStaminaLoss()
+ if(stamina_health > STAMINA_NO_OVERDRAW_THRESHOLD)
+ if(warn)
+ to_chat(src, "You do not have enough action stamina to do that!")
+ return FALSE
+ adjustStaminaLoss(amount * CONFIG_GET(number/stamina_combat/overdraw_penalty_factor))
+ else
+ stamina_buffer -= amount
+ if(considered_action)
+ stamina_buffer_last_use = world.time
+ UpdateStaminaBuffer()
+ return TRUE
+
+/**
+ * Updates our stamina buffer amount.
+ */
+/mob/living/proc/UpdateStaminaBuffer(updating_hud = TRUE)
+ var/time = world.time - stamina_buffer_regen_last
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max)
+ stamina_buffer_regen_last = world.time
+ if((stamina_buffer >= buffer_max) || !(combat_flags & COMBAT_FLAG_STAMINA_BUFFER))
+ stamina_buffer = buffer_max
+ return
+ else if(!time || HAS_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION))
+ return
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/out_of_combat_timer, out_of_combat_timer)
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/base_regeneration, base_regeneration)
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/combat_regeneration, combat_regeneration)
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/percent_regeneration_out_of_combat, percent_regeneration_out_of_combat)
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/post_action_penalty_delay, post_action_penalty_delay)
+ CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/post_action_penalty_factor, post_action_penalty_factor)
+ var/base_regen = (SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))? base_regeneration : combat_regeneration
+ var/time_since_last_action = world.time - stamina_buffer_last_use
+ var/action_penalty = ((time_since_last_action) < (post_action_penalty_delay * 10))? post_action_penalty_factor : 1
+ var/out_of_combat_bonus = (time_since_last_action < (out_of_combat_timer * 10))? 0 : ((buffer_max * percent_regeneration_out_of_combat * 0.01))
+ var/regen = ((base_regen * action_penalty) + out_of_combat_bonus) * time * 0.1 * stamina_buffer_regen_mod
+ stamina_buffer += min((buffer_max - stamina_buffer), regen)
+ if(updating_hud)
+ hud_used?.staminabuffer?.mark_dirty()
+
+/**
+ * Boosts our stamina buffer by this much.
+ */
+/mob/living/proc/RechargeStaminaBuffer(amount)
+ stamina_buffer += abs(amount)
+ UpdateStaminaBuffer()
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 0d4afd0915..2ed0bfa9d2 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -39,8 +39,7 @@
update_client_colour()
update_mouse_pointer()
if(client)
- client.change_view(CONFIG_GET(string/default_view)) // Resets the client.view in case it was changed.
-
+ client.view_size?.resetToDefault()
if(client.player_details && istype(client.player_details))
if(client.player_details.player_actions.len)
for(var/datum/action/A in client.player_details.player_actions)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 7e14224e0d..ab2556abb5 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -39,6 +39,7 @@
. = ..()
update_config_movespeed()
update_movespeed(TRUE)
+ initialize_actionspeed()
hook_vr("mob_new",list(src))
/mob/GenerateTag()
@@ -491,7 +492,6 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
client.prefs.chat_toggles ^= CHAT_OOC
if (!(client.prefs.chat_toggles & CHAT_OOC) && isdead(new_mob))
client.prefs.chat_toggles ^= CHAT_OOC
- client.change_view(CONFIG_GET(string/default_view))
new_mob.ckey = ckey
if(send_signal)
SEND_SIGNAL(src, COMSIG_MOB_KEY_CHANGE, new_mob, src)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 03a3ab1001..8c6b722140 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -58,6 +58,13 @@
var/list/movespeed_mod_immunities //Lazy list, see mob_movespeed.dm
/// The calculated mob speed slowdown based on the modifiers list
var/cached_multiplicative_slowdown
+ /// List of action speed modifiers applying to this mob
+ var/list/actionspeed_modification //Lazy list, see mob_movespeed.dm
+ /// List of action speed modifiers ignored by this mob. List -> List (id) -> List (sources)
+ var/list/actionspeed_mod_immunities //Lazy list, see mob_movespeed.dm
+ /// The calculated mob action speed slowdown based on the modifiers list
+ var/cached_multiplicative_actions_slowdown
+
/////////////////
var/name_archive //For admin things like possession
diff --git a/code/modules/movespeed/_movespeed_modifier.dm b/code/modules/movespeed/_movespeed_modifier.dm
index 3bc4463531..9c8036bd55 100644
--- a/code/modules/movespeed/_movespeed_modifier.dm
+++ b/code/modules/movespeed/_movespeed_modifier.dm
@@ -38,6 +38,12 @@ Key procs
/// Multiplicative slowdown
var/multiplicative_slowdown = 0
+ /// Next two variables depend on this: Should we do advanced calculations?
+ var/complex_calculation = FALSE
+ /// Absolute max tiles we can boost to
+ var/absolute_max_tiles_per_second
+ /// Max tiles per second we can boost
+ var/max_tiles_per_second_boost
/// Movetypes this applies to
var/movetypes = ALL
@@ -53,6 +59,16 @@ Key procs
if(!id)
id = "[type]" //We turn the path into a string.
+/**
+ * Returns new multiplicative movespeed after modification.
+ */
+/datum/movespeed_modifier/proc/apply_multiplicative(existing, mob/target)
+ if(!complex_calculation || (multiplicative_slowdown > 0)) // we aren't limiting how much things can slowdown.. yet.
+ return existing + multiplicative_slowdown
+ var/current_tiles = 10 / max(existing, world.tick_lag)
+ var/minimum_speed = 10 / min(current_tiles + max_tiles_per_second_boost, max(current_tiles, absolute_max_tiles_per_second))
+ return max(minimum_speed, existing + multiplicative_slowdown)
+
GLOBAL_LIST_EMPTY(movespeed_modification_cache)
/// Grabs a STATIC MODIFIER datum from cache. YOU MUST NEVER EDIT THESE DATUMS, OR IT WILL AFFECT ANYTHING ELSE USING IT TOO!
@@ -171,13 +187,15 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache)
/// Set or update the global movespeed config on a mob
/mob/proc/update_config_movespeed()
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/mob_config_speedmod, multiplicative_slowdown = get_config_multiplicative_speed())
+ add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/mob_config_speedmod_floating, multiplicative_slowdown = get_config_multiplicative_speed(TRUE))
/// Get the global config movespeed of a mob by type
-/mob/proc/get_config_multiplicative_speed()
- if(!islist(GLOB.mob_config_movespeed_type_lookup) || !GLOB.mob_config_movespeed_type_lookup[type])
+/mob/proc/get_config_multiplicative_speed(floating = FALSE)
+ var/list/read = floating? GLOB.mob_config_movespeed_type_lookup_floating : GLOB.mob_config_movespeed_type_lookup
+ if(!islist(read) || !read[type])
return 0
else
- return GLOB.mob_config_movespeed_type_lookup[type]
+ return read[type]
/// Go through the list of movespeed modifiers and calculate a final movespeed. ANY ADD/REMOVE DONE IN UPDATE_MOVESPEED MUST HAVE THE UPDATE ARGUMENT SET AS FALSE!
/mob/proc/update_movespeed()
@@ -198,7 +216,7 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache)
conflict_tracker[conflict] = amt
else
continue
- . += amt
+ . = M.apply_multiplicative(., src)
var/old = cached_multiplicative_slowdown // CITAEDL EDIT - To make things a bit less jarring, when in situations where
// your delay decreases, "give" the delay back to the client
cached_multiplicative_slowdown = .
@@ -220,6 +238,13 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache)
var/datum/movespeed_modifier/M = movespeed_modification[id]
. += M.multiplicative_slowdown
+/**
+ * Gets the movespeed modifier datum of a modifier on a mob. Returns null if not found.
+ * DANGER: IT IS UP TO THE PERSON USING THIS TO MAKE SURE THE MODIFIER IS NOT MODIFIED IF IT HAPPENS TO BE GLOBAL/CACHED.
+ */
+/mob/proc/get_movespeed_modifier_datum(id)
+ return movespeed_modification[id]
+
/// Checks if a move speed modifier is valid and not missing any data
/proc/movespeed_data_null_check(datum/movespeed_modifier/M) //Determines if a data list is not meaningful and should be discarded.
. = TRUE
diff --git a/code/modules/movespeed/modifiers/innate.dm b/code/modules/movespeed/modifiers/innate.dm
index a0357ddf0f..946d93e96b 100644
--- a/code/modules/movespeed/modifiers/innate.dm
+++ b/code/modules/movespeed/modifiers/innate.dm
@@ -18,3 +18,7 @@
blacklisted_movetypes = (FLOATING|CRAWLING)
variable = TRUE
flags = IGNORE_NOSLOW
+
+/datum/movespeed_modifier/slime_puddle
+ multiplicative_slowdown = 2
+ flags = IGNORE_NOSLOW
diff --git a/code/modules/movespeed/modifiers/items.dm b/code/modules/movespeed/modifiers/items.dm
index 94dc2a1553..a8510ecd86 100644
--- a/code/modules/movespeed/modifiers/items.dm
+++ b/code/modules/movespeed/modifiers/items.dm
@@ -1,12 +1,13 @@
/datum/movespeed_modifier/jetpack
conflicts_with = MOVE_CONFLICT_JETPACK
movetypes = FLOATING
+ multiplicative_slowdown = -1
/datum/movespeed_modifier/jetpack/cybernetic
- multiplicative_slowdown = -0.5
+ multiplicative_slowdown = -1.25
/datum/movespeed_modifier/jetpack/fullspeed
- multiplicative_slowdown = -2
+ multiplicative_slowdown = -1.5
/datum/movespeed_modifier/die_of_fate
multiplicative_slowdown = 1
diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm
index d17767bb1f..f6cf84eb83 100644
--- a/code/modules/movespeed/modifiers/mobs.dm
+++ b/code/modules/movespeed/modifiers/mobs.dm
@@ -111,6 +111,12 @@
/datum/movespeed_modifier/mob_config_speedmod
variable = TRUE
+ blacklisted_movetypes = FLOATING
+ flags = IGNORE_NOSLOW
+
+/datum/movespeed_modifier/mob_config_speedmod_floating
+ variable = TRUE
+ movetypes = FLOATING
flags = IGNORE_NOSLOW
/datum/movespeed_modifier/liver_cirrhosis
@@ -120,3 +126,30 @@
/datum/movespeed_modifier/active_block
variable = TRUE
flags = IGNORE_NOSLOW
+
+/datum/movespeed_modifier/sprinting
+ flags = IGNORE_NOSLOW
+ blacklisted_movetypes = FLOATING
+ priority = 100
+
+/// for speed reasons this is sorta copypasty.
+/datum/movespeed_modifier/sprinting/apply_multiplicative(existing, mob/target)
+ . = existing
+ if(target.m_intent != MOVE_INTENT_RUN)
+ return
+ if(isliving(target))
+ var/mob/living/L = target
+ if(!(L.mobility_flags & MOBILITY_STAND))
+ return
+ var/static/datum/config_entry/number/movedelay/sprint_max_tiles_increase/SMTI
+ if(!SMTI)
+ SMTI = CONFIG_GET_ENTRY(number/movedelay/sprint_max_tiles_increase)
+ var/static/datum/config_entry/number/movedelay/sprint_speed_increase/SSI
+ if(!SSI)
+ SSI = CONFIG_GET_ENTRY(number/movedelay/sprint_speed_increase)
+ var/static/datum/config_entry/number/movedelay/sprint_absolute_max_tiles/SAMT
+ if(!SAMT)
+ SAMT = CONFIG_GET_ENTRY(number/movedelay/sprint_absolute_max_tiles)
+ var/current_tiles = 10 / max(existing, world.tick_lag)
+ var/minimum_speed = 10 / min(max(SAMT.config_entry_value, current_tiles), current_tiles + SMTI.config_entry_value)
+ . = min(., max(minimum_speed, existing - SSI.config_entry_value))
diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm
index 0e553ced35..25b5cfb51b 100644
--- a/code/modules/paperwork/ticketmachine.dm
+++ b/code/modules/paperwork/ticketmachine.dm
@@ -160,8 +160,7 @@
/obj/machinery/ticket_machine/proc/reset_cooldown()
ready = TRUE
-/obj/machinery/ticket_machine/attack_hand(mob/living/carbon/user)
- . = ..()
+/obj/machinery/ticket_machine/on_attack_hand(mob/living/carbon/user)
INVOKE_ASYNC(src, .proc/attempt_ticket, user)
/obj/machinery/ticket_machine/proc/attempt_ticket(mob/living/carbon/user)
diff --git a/code/modules/plumbing/plumbers/autohydro.dm b/code/modules/plumbing/plumbers/autohydro.dm
index 20b8e6012a..9c358d8d6e 100644
--- a/code/modules/plumbing/plumbers/autohydro.dm
+++ b/code/modules/plumbing/plumbers/autohydro.dm
@@ -30,20 +30,8 @@
. = ..()
START_PROCESSING(SSobj, src)
create_reagents(100 , AMOUNT_VISIBLE)
- AddComponent(/datum/component/plumbing/simple_demand)
-
-/obj/machinery/hydroponics/constructable/automagic/ComponentInitialize()
- . = ..()
- AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated))
-
-
-/obj/machinery/hydroponics/constructable/proc/can_be_rotated(mob/user, rotation_type)
- return !anchored
/obj/machinery/hydroponics/constructable/automagic/process()
- if(reagents)
- reagents.add_reagent(reagents)
- reagents.clear_reagents()
if(dead)
dead = 0
qdel(myseed)
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index fe05365dd9..a4daeb6a33 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -407,3 +407,10 @@
/obj/item/stock_parts/cell/toymagburst
name = "toy mag burst rifle power supply"
maxcharge = 4000
+
+/obj/item/stock_parts/cell/family
+ name = "broken power cell"
+ desc = "An old faulty power cell. You can see your family name faintly etched onto it."
+ maxcharge = 100
+ self_recharge = -5 //it loses power over time instead of gaining
+ rating = 1
diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm
index b558031fab..c19927e84c 100644
--- a/code/modules/power/rtg.dm
+++ b/code/modules/power/rtg.dm
@@ -53,6 +53,33 @@
power_gen = 1250 // 2500 on T1, 10000 on T4.
circuit = /obj/item/circuitboard/machine/rtg/advanced
+/obj/machinery/power/rtg/advanced/fullupgrade //fully ugpraded stock parts
+ desc = "An advanced RTG capable of moderating isotope decay, increasing power output but reducing lifetime. It uses plasma-fueled radiation collectors to increase output even further. This model is fully upgraded with the latest tech available in this quadrant."
+
+/obj/machinery/power/rtg/advanced/fullupgrade/Initialize()
+ . = ..()
+ //This looks terrifying. And apparently instancing vars and modifying the amount variable causes runtime errors. Guess we're sticking to copy pasta, thanks, byond.
+ component_parts = list()
+ component_parts += new /obj/item/circuitboard/machine/rtg/advanced(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/uranium(null)
+ component_parts += new /obj/item/stack/sheet/mineral/plasma(null)
+ component_parts += new /obj/item/stack/sheet/mineral/plasma(null)
+ component_parts += new /obj/item/stack/sheet/mineral/plasma(null)
+ component_parts += new /obj/item/stack/sheet/mineral/plasma(null)
+ component_parts += new /obj/item/stack/sheet/mineral/plasma(null)
+ component_parts += new /obj/item/stock_parts/capacitor/quadratic(null)
+ component_parts += new /obj/item/stock_parts/micro_laser/quadultra(null)
+ RefreshParts()
+
// Void Core, power source for Abductor ships and bases.
// Provides a lot of power, but tends to explode when mistreated.
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 50dae7d6bb..6961ec54bb 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -364,7 +364,7 @@
icon_state_on = "protoemitter_+a"
can_buckle = TRUE
buckle_lying = FALSE
- var/view_range = 12
+ var/view_range = 4.5
var/datum/action/innate/protoemitter/firing/auto
//BUCKLE HOOKS
@@ -379,7 +379,7 @@
buckled_mob.pixel_x = 0
buckled_mob.pixel_y = 0
if(buckled_mob.client)
- buckled_mob.client.change_view(CONFIG_GET(string/default_view))
+ buckled_mob.client.view_size.resetToDefault()
auto.Remove(buckled_mob)
. = ..()
@@ -395,7 +395,7 @@
M.pixel_y = 14
layer = 4.1
if(M.client)
- M.client.change_view(view_range)
+ M.client.view_size.setTo(view_range)
if(!auto)
auto = new()
auto.Grant(M, src)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index e3fdbd3654..f385b640aa 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -928,8 +928,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/mob/living/user = AM
if(user.status_flags & GODMODE)
return
- message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)].")
- investigate_log("has consumed [key_name(user)].", INVESTIGATE_SUPERMATTER)
+ var/add
+ if(user.mind?.assigned_role == "Clown")
+ var/denergy = rand(-1000, 1000)
+ var/ddamage = rand(-150, clamp(150, 0, (explosion_point - damage) + 150))
+ power += denergy
+ damage += ddamage
+ add = ", adding [denergy] energy and [ddamage] damage to the crystal"
+ message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)][add].")
+ investigate_log("has consumed [key_name(user)][add].", INVESTIGATE_SUPERMATTER)
user.dust(force = TRUE)
if(power_changes)
matter_power += 200
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 8cddd5d02f..1c3a0d230f 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -134,7 +134,7 @@
/obj/item/gun/equipped(mob/living/user, slot)
. = ..()
if(zoomed && user.get_active_held_item() != src)
- zoom(user, FALSE) //we can only stay zoomed in if it's in our hands //yeah and we only unzoom if we're actually zoomed using the gun!!
+ zoom(user, user.dir, FALSE) //we can only stay zoomed in if it's in our hands //yeah and we only unzoom if we're actually zoomed using the gun!!
//called after the gun has successfully fired its chambered ammo.
/obj/item/gun/proc/process_chamber(mob/living/user)
@@ -154,8 +154,8 @@
shake_camera(user, recoil + 1, recoil)
if(stam_cost) //CIT CHANGE - makes gun recoil cause staminaloss
- var/safe_cost = clamp(stam_cost, 0, STAMINA_NEAR_CRIT - user.getStaminaLoss())*(firing && burst_size >= 2 ? 1/burst_size : 1)
- user.adjustStaminaLossBuffered(safe_cost) //CIT CHANGE - ditto
+ var/safe_cost = clamp(stam_cost, 0, user.stamina_buffer)*(firing && burst_size >= 2 ? 1/burst_size : 1)
+ user.UseStaminaBuffer(safe_cost)
if(suppressed)
playsound(user, fire_sound, 10, 1)
@@ -439,7 +439,7 @@
/obj/item/gun/ui_action_click(mob/user, action)
if(istype(action, /datum/action/item_action/toggle_scope_zoom))
- zoom(user)
+ zoom(user, user.dir)
else if(istype(action, alight))
toggle_gunlight()
@@ -554,14 +554,19 @@
. = ..()
if(!.)
var/obj/item/gun/G = target
- G.zoom(owner, FALSE)
+ G.zoom(owner, owner.dir)
/datum/action/item_action/toggle_scope_zoom/Remove(mob/living/L)
var/obj/item/gun/G = target
- G.zoom(L, FALSE)
+ G.zoom(L, L.dir)
return ..()
-/obj/item/gun/proc/zoom(mob/living/user, forced_zoom)
+/obj/item/gun/proc/rotate(atom/thing, old_dir, new_dir)
+ if(ismob(thing))
+ var/mob/lad = thing
+ lad.client.view_size.zoomOut(zoom_out_amt, zoom_amt, new_dir)
+
+/obj/item/gun/proc/zoom(mob/living/user, direct, forced_zoom)
if(!(user?.client))
return
@@ -573,25 +578,11 @@
zoomed = !zoomed
if(zoomed)
- var/_x = 0
- var/_y = 0
- switch(user.dir)
- if(NORTH)
- _y = zoom_amt
- if(EAST)
- _x = zoom_amt
- if(SOUTH)
- _y = -zoom_amt
- if(WEST)
- _x = -zoom_amt
-
- user.client.change_view(zoom_out_amt)
- user.client.pixel_x = world.icon_size*_x
- user.client.pixel_y = world.icon_size*_y
+ RegisterSignal(user, COMSIG_ATOM_DIR_CHANGE, .proc/rotate)
+ user.client.view_size.zoomOut(zoom_out_amt, zoom_amt, direct)
else
- user.client.change_view(CONFIG_GET(string/default_view))
- user.client.pixel_x = 0
- user.client.pixel_y = 0
+ UnregisterSignal(user, COMSIG_ATOM_DIR_CHANGE)
+ user.client.view_size.zoomIn()
/obj/item/gun/handle_atom_del(atom/A)
if(A == chambered)
@@ -599,6 +590,9 @@
update_icon()
/obj/item/gun/proc/getinaccuracy(mob/living/user, bonus_spread, stamloss)
+ return 0 // Replacement TBD: Exponential curved aim instability system.
+
+/*
if(inaccuracy_modifier == 0)
return bonus_spread
var/base_inaccuracy = weapon_weight * 25 * inaccuracy_modifier
@@ -621,6 +615,7 @@
if(mult < 0) //accurate weapons should provide a proper bonus with negative inaccuracy. the opposite is true too.
mult *= 1/inaccuracy_modifier
return max(bonus_spread + (base_inaccuracy * mult), 0) //no negative spread.
+*/
/obj/item/gun/proc/getstamcost(mob/living/carbon/user)
. = recoil
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index 9210e66f22..00e59d09f8 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -374,7 +374,7 @@
inaccuracy_modifier = 0.5
zoomable = TRUE
zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you.
- zoom_out_amt = 13
+ zoom_out_amt = 5
slot_flags = ITEM_SLOT_BACK
automatic_burst_overlay = FALSE
actions_types = list()
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index a26f05d553..0026a612e0 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -85,9 +85,14 @@
. += "[get_ammo(0,0)] of those are live rounds."
/obj/item/gun/ballistic/revolver/syndicate
+ obj_flags = UNIQUE_RENAME
unique_reskin = list("Default" = "revolver",
"Silver" = "russianrevolver",
- "Robust" = "revolvercit")
+ "Robust" = "revolvercit",
+ "Bulky" = "revolverhakita",
+ "Polished" = "revolvertoriate",
+ "Soulless" = "revolveroldflip",
+ "Soul" = "revolverold")
/obj/item/gun/ballistic/revolver/detective
name = "\improper .38 Mars Special"
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index ecf6e538b8..7b3ac36ef6 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -44,10 +44,9 @@
if(HAS_TRAIT(user, TRAIT_FAST_PUMP))
recentpump = world.time + 2
else
+ if(!user.UseStaminaBuffer(2, warn = TRUE))
+ return
recentpump = world.time + 10
- if(istype(user))//CIT CHANGE - makes pumping shotguns cost a lil bit of stamina.
- user.adjustStaminaLossBuffered(2) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added
- return
/obj/item/gun/ballistic/shotgun/blow_up(mob/user)
. = 0
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index c1f47ccd1a..438c000a1e 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -105,10 +105,20 @@
holds_charge = TRUE
unique_frequency = TRUE
+/obj/item/gun/energy/kinetic_accelerator/cyborg/Destroy()
+ for(var/obj/item/borg/upgrade/modkit/M in modkits)
+ M.uninstall(src)
+ return ..()
+
/obj/item/gun/energy/kinetic_accelerator/premiumka/cyborg
holds_charge = TRUE
unique_frequency = TRUE
+/obj/item/gun/energy/kinetic_accelerator/premiumka/cyborg/Destroy()
+ for(var/obj/item/borg/upgrade/modkit/M in modkits)
+ M.uninstall(src)
+ return ..()
+
/obj/item/gun/energy/kinetic_accelerator/minebot
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
overheat_time = 20
@@ -284,11 +294,11 @@
else
..()
-/obj/item/borg/upgrade/modkit/action(mob/living/silicon/robot/R)
- . = ..()
- if (.)
- for(var/obj/item/gun/energy/kinetic_accelerator/cyborg/H in R.module.modules)
- return install(H, usr)
+/obj/item/borg/upgrade/modkit/afterInstall(mob/living/silicon/robot/R)
+ for(var/obj/item/gun/energy/kinetic_accelerator/H in R.module.modules)
+ if(install(H, R)) //It worked
+ return
+ to_chat(R, "Upgrade error - Aborting Kinetic Accelerator linking.") //No applicable KA found, insufficient capacity, or some other problem.
/obj/item/borg/upgrade/modkit/proc/install(obj/item/gun/energy/kinetic_accelerator/KA, mob/user)
. = TRUE
@@ -323,12 +333,6 @@
to_chat(user, "You don't have room([KA.get_remaining_mod_capacity()]% remaining, [cost]% needed) to install this modkit. Use a crowbar to remove existing modkits.")
. = FALSE
-/obj/item/borg/upgrade/modkit/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- for(var/obj/item/gun/energy/kinetic_accelerator/cyborg/KA in R.module.modules)
- uninstall(KA)
-
/obj/item/borg/upgrade/modkit/proc/uninstall(obj/item/gun/energy/kinetic_accelerator/KA, forcemove = TRUE)
KA.modkits -= src
if(forcemove)
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 19ca42022d..cd91a7670d 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -233,7 +233,7 @@
p_blue.link_portal(p_orange)
/obj/item/gun/energy/wormhole_projector/proc/create_portal(obj/item/projectile/beam/wormhole/W, turf/target)
- var/obj/effect/portal/P = new /obj/effect/portal(target, src, 300, null, FALSE, null, atmos_link)
+ var/obj/effect/portal/P = new /obj/effect/portal(target, 300, null, FALSE, null, atmos_link)
if(istype(W, /obj/item/projectile/beam/wormhole/orange))
qdel(p_orange)
p_orange = P
diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm
index 5e250d44e2..9d9f6aeb83 100644
--- a/code/modules/projectiles/guns/misc/beam_rifle.dm
+++ b/code/modules/projectiles/guns/misc/beam_rifle.dm
@@ -69,7 +69,8 @@
//ZOOMING
var/zoom_current_view_increase = 0
- var/zoom_target_view_increase = 10
+ ///The radius you want to zoom by
+ var/zoom_target_view_increase = 9.5
var/zooming = FALSE
var/zoom_lock = ZOOM_LOCK_OFF
var/zooming_angle
@@ -133,7 +134,7 @@
if(zoom_lock == ZOOM_LOCK_OFF)
return
zooming = TRUE
- current_user.client.change_view(world.view + zoom_target_view_increase)
+ current_user.client.view_size.setTo(zoom_target_view_increase)
zoom_current_view_increase = zoom_target_view_increase
/obj/item/gun/energy/beam_rifle/proc/stop_zooming(mob/user)
@@ -146,9 +147,8 @@
user = current_user
if(!user || !user.client)
return FALSE
- animate(user.client, pixel_x = 0, pixel_y = 0, 0, FALSE, LINEAR_EASING, ANIMATION_END_NOW)
+ user.client.view_size.zoomIn()
zoom_current_view_increase = 0
- user.client.change_view(CONFIG_GET(string/default_view))
zooming_angle = 0
current_zoom_x = 0
current_zoom_y = 0
diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm
index df417ad734..b3737a8388 100644
--- a/code/modules/projectiles/projectile/special/rocket.dm
+++ b/code/modules/projectiles/projectile/special/rocket.dm
@@ -73,4 +73,4 @@
explosion(target, 0, 1, 1, 2)
return BULLET_ACT_HIT
//if(istype(target, /turf/closed) || ismecha(target))
- new /obj/item/broken_missile(get_turf(src), 1)
\ No newline at end of file
+ new /obj/item/broken_missile(get_turf(src), 1)
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index cd21723e64..bbc44730b6 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -2283,7 +2283,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
boozepwr = 50
/datum/reagent/consumable/ethanol/species_drink/on_mob_life(mob/living/carbon/C)
- if(C.dna.species && C.dna.species.species_type == species_required) //species have a species_type variable that refers to one of the drinks
+ if(C.dna.species && C.dna.species.species_category == species_required) //species have a species_category variable that refers to one of the drinks
quality = RACE_DRINK
else
C.adjust_disgust(disgust)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index f62391886c..e64647028c 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -565,7 +565,7 @@
var/diff_len = length(GLOB.skin_tones - GLOB.nonstandard_skin_tones)
H.skin_tone = GLOB.skin_tones[min(diff_len, GLOB.skin_tones.Find(H.skin_tone) + 1)]
else
- H.skin_tone = H.dna.skin_tone_override = tan_mutant_color(H.dna.skin_tone_override, "#202020")
+ H.skin_tone = H.dna.skin_tone_override = tan_mutant_color(H.dna.skin_tone_override, MINIMUM_MUTANT_COLOR)
if(MUTCOLORS in H.dna.species.species_traits) //take current alien color and darken it slightly
H.dna.features["mcolor"] = tan_mutant_color(H.dna.features["mcolor"])
H.update_body()
@@ -576,7 +576,7 @@
return ..()
-/datum/reagent/spraytan/proc/tan_mutant_color(color, limit = "#7F7F7F")
+/datum/reagent/spraytan/proc/tan_mutant_color(color, limit = MINIMUM_MUTANT_COLOR)
var/newcolor = ""
var/len = length(color)
var/char = ""
@@ -1984,6 +1984,11 @@
color = "#363636"
carpet_type = /turf/open/floor/carpet/black
+/datum/reagent/carpet/arcade
+ name = "Liquid Arcade Carpet"
+ color = "#b51d05"
+ carpet_type = /turf/open/floor/carpet/arcade
+
/datum/reagent/carpet/blackred
name = "Liquid Red Black Carpet"
color = "#342125"
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index 585b33b189..019394e3c8 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -763,6 +763,12 @@
results = list(/datum/reagent/carpet/black = 2)
required_reagents = list(/datum/reagent/carpet = 1, /datum/reagent/carbon = 1)
+/datum/chemical_reaction/carpet/arcade
+ name = "liquid arcade carpet"
+ id = /datum/reagent/carpet/arcade
+ results = list(/datum/reagent/carpet/arcade = 2)
+ required_reagents = list(/datum/reagent/carpet = 1, /datum/reagent/consumable/pwr_game = 1)
+
/datum/chemical_reaction/carpet/blackred
name = "liquid red black carpet"
id = /datum/reagent/carpet/blackred
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 86464aceea..070d5cb269 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -484,12 +484,12 @@
return FALSE
var/list/D = holder.get_data("blood")
if(D && D["changeling_loudness"])
- return (D["changeling_loudness"] >= 4 ? D["changeling_loudness"] : FALSE)
+ return (D["changeling_loudness"] >= LINGBLOOD_DETECTION_THRESHOLD ? D["changeling_loudness"] : FALSE)
else
return FALSE
/datum/chemical_reaction/reagent_explosion/lingblood/on_reaction(datum/reagents/holder, multiplier, specialreact)
- if(specialreact >= 10)
+ if(specialreact > LINGBLOOD_EXPLOSION_THRESHOLD)
return ..()
else
return FALSE
diff --git a/code/modules/research/designs/biogenerator_designs.dm b/code/modules/research/designs/biogenerator_designs.dm
index bdaf39732f..ed12d4945e 100644
--- a/code/modules/research/designs/biogenerator_designs.dm
+++ b/code/modules/research/designs/biogenerator_designs.dm
@@ -181,6 +181,14 @@
build_path = /obj/item/storage/belt/janitor
category = list("initial","Organic Materials")
+/datum/design/plantbelt
+ name = "Botanical Belt"
+ id = "plantbelt"
+ build_type = BIOGENERATOR
+ materials = list(/datum/material/biomass= 300)
+ build_path = /obj/item/storage/belt/plant
+ category = list("initial","Organic Materials")
+
/datum/design/s_holster
name = "Shoulder Holster"
id = "s_holster"
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 7013412e6d..b178f936b7 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -32,7 +32,7 @@
materials = list(/datum/material/glass = 3000, /datum/material/plasma = 3000, /datum/material/diamond = 250, /datum/material/bluespace = 250)
build_path = /obj/item/reagent_containers/glass/beaker/bluespace
category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_SERVICE
/datum/design/noreactbeaker
name = "Cryostasis Beaker"
@@ -973,6 +973,10 @@
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/////////////////////////////////////////
+//////////// Plumbing //////////
+/////////////////////////////////////////
+
/datum/design/acclimator
name = "Plumbing Acclimator"
desc = "A heating and cooling device for pipes!"
@@ -1126,3 +1130,14 @@
build_path = /obj/item/construction/plumbing
category = list("Misc","Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/rplunger
+ name = "Reinforced Plunger"
+ desc = "A plunger designed for heavy duty clogs."
+ id = "rplunger"
+ build_type = PROTOLATHE
+ materials = list(/datum/material/plasma = 1000, /datum/material/iron = 1000, /datum/material/glass = 1000)
+ construction_time = 15
+ build_path = /obj/item/plunger/reinforced
+ category = list ("Misc","Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_CARGO
diff --git a/code/modules/research/techweb/nodes/medical_nodes.dm b/code/modules/research/techweb/nodes/medical_nodes.dm
index 150e420c09..7b9b2f2923 100644
--- a/code/modules/research/techweb/nodes/medical_nodes.dm
+++ b/code/modules/research/techweb/nodes/medical_nodes.dm
@@ -38,7 +38,7 @@
display_name = "Advanced Plumbing Technology"
description = "Plumbing RCD."
prereq_ids = list("plumbing", "adv_engi")
- design_ids = list("plumb_rcd", "autohydrotray")
+ design_ids = list("plumb_rcd", "autohydrotray", "rplunger")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
//////////////////////Cybernetics/////////////////////
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index ed43576a61..cbfbbe2a36 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -335,15 +335,11 @@ datum/status_effect/rebreathing/tick()
duration = 600
/datum/status_effect/timecookie/on_apply()
- if(ishuman(owner))
- var/mob/living/carbon/human/H
- H.physiology.do_after_speed *= 0.95
+ owner.add_actionspeed_modifier(/datum/actionspeed_modifier/timecookie)
return ..()
/datum/status_effect/timecookie/on_remove()
- if(ishuman(owner))
- var/mob/living/carbon/human/H
- H.physiology.do_after_speed /= 0.95
+ owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/timecookie)
return ..()
/datum/status_effect/lovecookie
diff --git a/code/modules/ruins/spaceruin_code/caravanambush.dm b/code/modules/ruins/spaceruin_code/caravanambush.dm
index a7d89f3324..740850524c 100644
--- a/code/modules/ruins/spaceruin_code/caravanambush.dm
+++ b/code/modules/ruins/spaceruin_code/caravanambush.dm
@@ -68,7 +68,7 @@
lock_override = NONE
shuttlePortId = "caravantrade1_custom"
jumpto_ports = list("whiteship_away" = 1, "whiteship_home" = 1, "whiteship_z4" = 1, "caravantrade1_ambush" = 1)
- view_range = 14
+ view_range = 6.5
x_offset = -5
y_offset = -5
designate_time = 100
@@ -92,7 +92,7 @@
lock_override = NONE
shuttlePortId = "caravanpirate_custom"
jumpto_ports = list("caravanpirate_ambush" = 1)
- view_range = 14
+ view_range = 6.5
x_offset = 3
y_offset = -6
@@ -116,7 +116,7 @@
lock_override = NONE
shuttlePortId = "caravansyndicate1_custom"
jumpto_ports = list("caravansyndicate1_ambush" = 1, "caravansyndicate1_listeningpost" = 1)
- view_range = 7
+ view_range = 0
x_offset = 2
y_offset = 0
@@ -140,7 +140,7 @@
lock_override = NONE
shuttlePortId = "caravansyndicate2_custom"
jumpto_ports = list("caravansyndicate2_ambush" = 1, "caravansyndicate1_listeningpost" = 1)
- view_range = 7
+ view_range = 0
x_offset = 0
y_offset = 2
@@ -164,6 +164,6 @@
lock_override = NONE
shuttlePortId = "caravansyndicate3_custom"
jumpto_ports = list("caravansyndicate3_ambush" = 1, "caravansyndicate3_listeningpost" = 1)
- view_range = 10
+ view_range = 2.5
x_offset = -1
y_offset = -3
diff --git a/code/modules/ruins/spaceruin_code/skelter.dm b/code/modules/ruins/spaceruin_code/skelter.dm
new file mode 100644
index 0000000000..526277cf56
--- /dev/null
+++ b/code/modules/ruins/spaceruin_code/skelter.dm
@@ -0,0 +1,4 @@
+/////////// skelter items
+
+/obj/item/paper/fluff/ruins/skelter/cloner
+ info = "You may be wondering why your pay has been cut, but rest assured - it's because we're investing in YOU! Should you meet your untimely demise, this machine can bring you back to life with as little as your brain! It also means death is no longer an acceptable excuse for neglecting your duties, so get back to work!
\n
\n-HQ"
diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index 195e87720c..21a9c6c5d7 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -2,6 +2,7 @@
name = "navigation computer"
desc = "Used to designate a precise transit location for a spacecraft."
jump_action = null
+ should_supress_view_changes = FALSE
var/datum/action/innate/shuttledocker_rotate/rotate_action = new
var/datum/action/innate/shuttledocker_place/place_action = new
var/shuttleId = ""
@@ -10,7 +11,7 @@
var/list/jumpto_ports = list() //hashset of ports to jump to and ignore for collision purposes
var/obj/docking_port/stationary/my_port //the custom docking port placed by this console
var/obj/docking_port/mobile/shuttle_port //the mobile docking port of the connected shuttle
- var/view_range = 7
+ var/view_range = 0
var/x_offset = 0
var/y_offset = 0
var/list/whitelist_turfs = list(/turf/open/space, /turf/open/floor/plating, /turf/open/lava)
@@ -88,7 +89,7 @@
to_add += SSshuttle.hidden_shuttle_turf_images
user.client.images += to_add
- user.client.change_view(view_range)
+ user.client.view_size.setTo(view_range)
/obj/machinery/computer/camera_advanced/shuttle_docker/remove_eye_control(mob/living/user)
..()
@@ -101,7 +102,7 @@
to_remove += SSshuttle.hidden_shuttle_turf_images
user.client.images -= to_remove
- user.client.change_view(CONFIG_GET(string/default_view))
+ user.client.view_size.resetToDefault()
/obj/machinery/computer/camera_advanced/shuttle_docker/proc/placeLandingSpot()
if(designating_target_loc || !current_user)
diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm
index bdbdc08c6f..794f2bcd44 100644
--- a/code/modules/shuttle/syndicate.dm
+++ b/code/modules/shuttle/syndicate.dm
@@ -60,7 +60,7 @@
lock_override = CAMERA_LOCK_STATION
shuttlePortId = "syndicate_custom"
jumpto_ports = list("syndicate_ne" = 1, "syndicate_nw" = 1, "syndicate_n" = 1, "syndicate_se" = 1, "syndicate_sw" = 1, "syndicate_s" = 1)
- view_range = 13
+ view_range = 5.5
x_offset = -7
y_offset = -1
space_turfs_only = FALSE
diff --git a/code/modules/shuttle/white_ship.dm b/code/modules/shuttle/white_ship.dm
index f25fe30f36..66146edea1 100644
--- a/code/modules/shuttle/white_ship.dm
+++ b/code/modules/shuttle/white_ship.dm
@@ -25,7 +25,7 @@
lock_override = NONE
shuttlePortId = "whiteship_custom"
jumpto_ports = list("whiteship_away" = 1, "whiteship_home" = 1, "whiteship_z4" = 1)
- view_range = 18
+ view_range = 10
x_offset = -6
y_offset = -10
designate_time = 100
@@ -36,7 +36,7 @@
shuttleId = "whiteship_pod"
shuttlePortId = "whiteship_pod_custom"
jumpto_ports = list("whiteship_pod_home" = 1)
- view_range = 7
+ view_range = 0
x_offset = -2
y_offset = 0
designate_time = 0
diff --git a/code/modules/smithing/anvil.dm b/code/modules/smithing/anvil.dm
index 19d48119e6..b796edabbf 100644
--- a/code/modules/smithing/anvil.dm
+++ b/code/modules/smithing/anvil.dm
@@ -36,6 +36,7 @@
icon_state = "anvil"
density = TRUE
anchored = TRUE
+ var/busy = FALSE //If someone is already interacting with this anvil
var/workpiece_state = FALSE
var/datum/material/workpiece_material
var/anvilquality = 0
@@ -84,7 +85,7 @@
currentquality = anvilquality
var/skillmod = 0
if(user.mind.skill_holder)
- skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/2
+ skillmod = user.mind.get_skill_level(/datum/skill/level/dwarfy/blacksmithing)/2
currentquality += skillmod
qdel(notsword)
else
@@ -93,12 +94,14 @@
return
else if(istype(I, /obj/item/melee/smith/hammer))
var/obj/item/melee/smith/hammer/hammertime = I
- if(workpiece_state == WORKPIECE_PRESENT || workpiece_state == WORKPIECE_INPROGRESS)
- do_shaping(user, hammertime.qualitymod)
- return
- else
- to_chat(user, "You can't work an empty anvil!")
- return FALSE
+ if(!(workpiece_state == WORKPIECE_PRESENT || workpiece_state == WORKPIECE_INPROGRESS))
+ to_chat(user, "You can't work an empty anvil!")
+ return FALSE
+ if(busy)
+ to_chat(user, "This anvil is already being worked!")
+ return FALSE
+ do_shaping(user, hammertime.qualitymod)
+ return
return ..()
/obj/structure/anvil/wrench_act(mob/living/user, obj/item/I)
@@ -108,16 +111,18 @@
/obj/structure/anvil/proc/do_shaping(mob/user, var/qualitychange)
+ busy = TRUE
currentquality += qualitychange
var/list/shapingsteps = list("weak hit", "strong hit", "heavy hit", "fold", "draw", "shrink", "bend", "punch", "upset") //weak/strong/heavy hit affect strength. All the other steps shape.
workpiece_state = WORKPIECE_INPROGRESS
var/stepdone = input(user, "How would you like to work the metal?") in shapingsteps
var/steptime = 50
if(user.mind.skill_holder)
- var/skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/10 + 1
+ var/skillmod = user.mind.get_skill_level(/datum/skill/level/dwarfy/blacksmithing)/10 + 1
steptime = 50 / skillmod
playsound(src, 'sound/effects/clang2.ogg',40, 2)
if(!do_after(user, steptime, target = src))
+ busy = FALSE
return FALSE
switch(stepdone)
if("weak hit")
@@ -162,16 +167,17 @@
addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, src, 'sound/effects/clang2.ogg', 40, 2), 15)
if(length(stepsdone) >= 3)
tryfinish(user)
+ busy = FALSE
/obj/structure/anvil/proc/tryfinish(mob/user)
var/artifactchance = 0
if(!artifactrolled)
- artifactchance = (1+(user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/4))/2500
+ artifactchance = (1+(user.mind.get_skill_level(/datum/skill/level/dwarfy/blacksmithing)/4))/2500
artifactrolled = TRUE
var/artifact = max(prob(artifactchance), debug)
var/finalfailchance = outrightfailchance
if(user.mind.skill_holder)
- var/skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/10 + 1
+ var/skillmod = user.mind.get_skill_level(/datum/skill/level/dwarfy/blacksmithing)/10 + 1
finalfailchance = max(0, finalfailchance / skillmod) //lv 2 gives 20% less to fail, 3 30%, etc
if((currentsteps > 10 || (rng && prob(finalfailchance))) && !artifact)
to_chat(user, "You overwork the metal, causing it to turn into useless slag!")
@@ -184,7 +190,7 @@
outrightfailchance = 1
artifactrolled = FALSE
if(user.mind.skill_holder)
- user.mind.auto_gain_experience(/datum/skill/level/dorfy/blacksmithing, 25, 400, silent = FALSE)
+ user.mind.auto_gain_experience(/datum/skill/level/dwarfy/blacksmithing, 25, 400, silent = FALSE)
for(var/i in smithrecipes)
if(i == stepsdone)
var/turf/T = get_turf(user)
@@ -217,7 +223,7 @@
outrightfailchance = 1
artifactrolled = FALSE
if(user.mind.skill_holder)
- user.mind.auto_gain_experience(/datum/skill/level/dorfy/blacksmithing, 50, 10000000, silent = FALSE)
+ user.mind.auto_gain_experience(/datum/skill/level/dwarfy/blacksmithing, 50, 10000000, silent = FALSE)
break
/obj/structure/anvil/debugsuper
diff --git a/code/modules/smithing/smithed_items.dm b/code/modules/smithing/smithed_items.dm
index 6d10d33a75..e514fd5c9a 100644
--- a/code/modules/smithing/smithed_items.dm
+++ b/code/modules/smithing/smithed_items.dm
@@ -35,7 +35,7 @@
if(G.max_heat_protection_temperature)
prot = (G.max_heat_protection_temperature > 360)
else
- prot = 1
+ prot = 0
if(prot > 0 || HAS_TRAIT(user, TRAIT_RESISTHEAT) || HAS_TRAIT(user, TRAIT_RESISTHEATHANDS))
to_chat(user, "You pick up the [src].")
return ..()
diff --git a/code/modules/spells/spell_types/devil_boons.dm b/code/modules/spells/spell_types/devil_boons.dm
index 8ba106d77b..cf11466d19 100644
--- a/code/modules/spells/spell_types/devil_boons.dm
+++ b/code/modules/spells/spell_types/devil_boons.dm
@@ -43,7 +43,7 @@
for(var/mob/C in targets)
if(!C.client)
continue
- C.client.change_view(input("Select view range:", "Range", 4) in ranges)
+ C.client.view_size.setTo((input("Select view range:", "Range", 4) in ranges) - 7)
/obj/effect/proc_holder/spell/targeted/summon_friend
name = "Summon Friend"
diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
index b3a82ea0e7..704dbffe51 100644
--- a/code/modules/surgery/bodyparts/_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -483,12 +483,12 @@
//Checks disabled status thresholds
//Checks disabled status thresholds
-/obj/item/bodypart/proc/update_disabled()
+/obj/item/bodypart/proc/update_disabled(silent = FALSE)
if(!owner)
return
- set_disabled(is_disabled())
+ set_disabled(is_disabled(silent), silent)
-/obj/item/bodypart/proc/is_disabled()
+/obj/item/bodypart/proc/is_disabled(silent = FALSE)
if(!owner)
return
if(HAS_TRAIT(owner, TRAIT_PARALYSIS))
@@ -500,7 +500,7 @@
if(can_dismember() && !HAS_TRAIT(owner, TRAIT_NODISMEMBER))
. = disabled //inertia, to avoid limbs healing 0.1 damage and being re-enabled
if(get_damage(TRUE) >= max_damage * (HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE) ? 0.6 : 1)) //Easy limb disable disables the limb at 40% health instead of 0%
- if(!last_maxed)
+ if(!last_maxed && !silent)
owner.emote("scream")
last_maxed = TRUE
if(!is_organic_limb() || stamina_dam >= max_damage)
@@ -581,7 +581,7 @@
C = owner
no_update = FALSE
- if(HAS_TRAIT(C, TRAIT_HUSK) && is_organic_limb())
+ if(HAS_TRAIT(C, TRAIT_HUSK) && (is_organic_limb() || render_like_organic))
species_id = "husk" //overrides species_id
dmg_overlay_type = "" //no damage overlay shown when husked
should_draw_gender = FALSE
@@ -619,7 +619,10 @@
skin_tone = ""
body_gender = H.dna.features["body_model"]
- should_draw_gender = S.sexes
+ if(GLOB.nongendered_limb_types[species_id])
+ should_draw_gender = FALSE
+ else
+ should_draw_gender = S.sexes
var/mut_colors = (MUTCOLORS in S.species_traits)
if(mut_colors)
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index fa003e3f3c..481bafbb3d 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -435,4 +435,7 @@
var/datum/wound/loss/phantom_loss = new // stolen valor, really
scaries.generate(L, phantom_loss)
L.attach_limb(src, 1)
+ if(ROBOTIC_LIMBS in dna.species.species_traits) //Snowflake trait moment, but needed.
+ L.render_like_organic = TRUE
+ L.change_bodypart_status(BODYPART_ROBOTIC, FALSE, TRUE) //Haha what if IPC-lings actually regenerated the right limbs instead of organic ones? That'd be pretty cool, right?
return TRUE
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index b6a0a387e2..8b1473fed2 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -161,7 +161,7 @@
debrain_overlay.icon = 'icons/mob/animal_parts.dmi'
debrain_overlay.icon_state = "debrained_larva"
else if(!(NOBLOOD in species_flags_list))
- debrain_overlay.icon = 'icons/mob/human_face.dmi'
+ debrain_overlay.icon = 'icons/mob/human_parts.dmi'
debrain_overlay.icon_state = "debrained"
. += debrain_overlay
else
@@ -175,21 +175,31 @@
// lipstick
if(lip_style)
- var/image/lips_overlay = image('icons/mob/human_face.dmi', "lips_[lip_style]", -BODY_LAYER, SOUTH)
+ var/image/lips_overlay = image('icons/mob/lips.dmi', "lips_[lip_style]", -BODY_LAYER, SOUTH)
lips_overlay.color = lip_color
. += lips_overlay
// eyes
if(eyes)
- var/image/left_eye = image('icons/mob/human_face.dmi', "left_eye", -BODY_LAYER, SOUTH)
- var/image/right_eye = image('icons/mob/human_face.dmi', "right_eye", -BODY_LAYER, SOUTH)
- if(eyes.left_eye_color && eyes.right_eye_color)
- left_eye.color = "#" + eyes.left_eye_color
- right_eye.color = "#" + eyes.right_eye_color
- . += left_eye
- . += right_eye
+ var/left_state = DEFAULT_LEFT_EYE_STATE
+ var/right_state = DEFAULT_RIGHT_EYE_STATE
+ if(owner && owner.dna.species)
+ var/eye_type = owner.dna.species.eye_type
+ if(GLOB.eye_types[eye_type])
+ left_state = eye_type + "_left_eye"
+ right_state = eye_type + "_right_eye"
+ if(left_state != DEFAULT_NO_EYE_STATE)
+ var/image/left_eye = image('icons/mob/hair.dmi', left_state, -BODY_LAYER, SOUTH)
+ if(eyes.left_eye_color)
+ left_eye.color = "#" + eyes.left_eye_color
+ . += left_eye
+ if(right_state != DEFAULT_NO_EYE_STATE)
+ var/image/right_eye = image('icons/mob/hair.dmi', right_state, -BODY_LAYER, SOUTH)
+ if(eyes.right_eye_color)
+ right_eye.color = "#" + eyes.right_eye_color
+ . += right_eye
else
- var/eyes_overlay = image('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER, SOUTH)
+ var/eyes_overlay = image('icons/mob/hair.dmi', "eyes_missing", -BODY_LAYER, SOUTH)
. += eyes_overlay
/obj/item/bodypart/head/monkey
diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm
index 5a887ee6b7..86288564ae 100644
--- a/code/modules/surgery/bodyparts/parts.dm
+++ b/code/modules/surgery/bodyparts/parts.dm
@@ -75,11 +75,11 @@
return BODYPART_DISABLED_PARALYSIS
return ..()
-/obj/item/bodypart/l_arm/set_disabled(new_disabled)
+/obj/item/bodypart/l_arm/set_disabled(new_disabled, silent = FALSE)
. = ..()
if(!.)
return
- if(owner.stat < UNCONSCIOUS)
+ if(owner.stat < UNCONSCIOUS && !silent)
switch(disabled)
if(BODYPART_DISABLED_DAMAGE)
owner.emote("scream")
@@ -136,11 +136,11 @@
return BODYPART_DISABLED_PARALYSIS
return ..()
-/obj/item/bodypart/r_arm/set_disabled(new_disabled)
+/obj/item/bodypart/r_arm/set_disabled(new_disabled, silent = FALSE)
. = ..()
if(!.)
return
- if(owner.stat < UNCONSCIOUS)
+ if(owner.stat < UNCONSCIOUS && !silent)
switch(disabled)
if(BODYPART_DISABLED_DAMAGE)
owner.emote("scream")
@@ -196,16 +196,17 @@
return BODYPART_DISABLED_PARALYSIS
return ..()
-/obj/item/bodypart/l_leg/set_disabled(new_disabled)
+/obj/item/bodypart/l_leg/set_disabled(new_disabled, silent = FALSE)
. = ..()
if(!. || owner.stat >= UNCONSCIOUS)
return
- switch(disabled)
- if(BODYPART_DISABLED_DAMAGE)
- owner.emote("scream")
- to_chat(owner, "Your [name] is too damaged to function!")
- if(BODYPART_DISABLED_PARALYSIS)
- to_chat(owner, "You can't feel your [name]!")
+ if(!silent)
+ switch(disabled)
+ if(BODYPART_DISABLED_DAMAGE)
+ owner.emote("scream")
+ to_chat(owner, "Your [name] is too damaged to function!")
+ if(BODYPART_DISABLED_PARALYSIS)
+ to_chat(owner, "You can't feel your [name]!")
/obj/item/bodypart/l_leg/digitigrade
name = "left digitigrade leg"
@@ -253,16 +254,17 @@
return BODYPART_DISABLED_PARALYSIS
return ..()
-/obj/item/bodypart/r_leg/set_disabled(new_disabled)
+/obj/item/bodypart/r_leg/set_disabled(new_disabled, silent = FALSE)
. = ..()
if(!. || owner.stat >= UNCONSCIOUS)
return
- switch(disabled)
- if(BODYPART_DISABLED_DAMAGE)
- owner.emote("scream")
- to_chat(owner, "Your [name] is too damaged to function!")
- if(BODYPART_DISABLED_PARALYSIS)
- to_chat(owner, "You can't feel your [name]!")
+ if(!silent)
+ switch(disabled)
+ if(BODYPART_DISABLED_DAMAGE)
+ owner.emote("scream")
+ to_chat(owner, "Your [name] is too damaged to function!")
+ if(BODYPART_DISABLED_PARALYSIS)
+ to_chat(owner, "You can't feel your [name]!")
/obj/item/bodypart/r_leg/digitigrade
name = "right digitigrade leg"
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index a088eb2e4f..794823448f 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -248,7 +248,7 @@
/obj/item/organ/eyes/robotic/glow/Initialize()
. = ..()
- mob_overlay = image('icons/mob/human_face.dmi', "eyes_glow_gs")
+ mob_overlay = image('icons/mob/eyes.dmi', "eyes_glow_gs")
/obj/item/organ/eyes/robotic/glow/Destroy()
terminate_effects()
diff --git a/code/modules/tooltip/tooltip.html b/code/modules/tooltip/tooltip.html
index 3cab68da6a..60bd358031 100644
--- a/code/modules/tooltip/tooltip.html
+++ b/code/modules/tooltip/tooltip.html
@@ -120,12 +120,17 @@
window.location = 'byond://winset?id='+tooltip.control+';anchor1=0,0;size=999x999';
//Get the real icon size according to the client view
+ //FYI, this bit is even more borrowed from goon, our widescreen broke tooltips so I took a look at how they do it
+ //To improve our code. Thanks gooncoders, very cool
var mapWidth = map['view-size'].x,
mapHeight = map['view-size'].y,
- tilesShown = tooltip.client_view_h
- realIconSize = mapHeight / tilesShown,
- resizeRatio = realIconSize / tooltip.tileSize,
- //Calculate letterboxing offsets
+ tilesShownX = tooltip.client_view_w
+ tilesShownY = tooltip.client_view_h
+ realIconSizeX = mapWidth / tilesShownX,
+ realIconSizeY = mapHeight / tilesShownY,
+ resizeRatioX = realIconSizeX / tooltip.tileSize,
+ resizeRatioY = realIconSizeY / tooltip.tileSize,
+ //Calculate letterboxing offsets
leftOffset = (map.size.x - mapWidth) / 2,
topOffset = (map.size.y - mapHeight) / 2;
@@ -168,7 +173,7 @@
if ((iconX + westOffset) !== enteredX) { //Cursor entered on the offset tile
left = left + (westOffset < 0 ? 1 : -1);
}
- leftOffset = leftOffset + (westOffset * resizeRatio);
+ leftOffset = leftOffset + (westOffset * resizeRatioX);
}
}
@@ -179,13 +184,13 @@
if (northOffset !== 0) {
if ((iconY + northOffset) === enteredY) { //Cursor entered on the original tile
top--;
- topOffset = topOffset - ((tooltip.tileSize + northOffset) * resizeRatio);
+ topOffset = topOffset - ((tooltip.tileSize + northOffset) * resizeRatioY);
} else { //Cursor entered on the offset tile
if (northOffset < 0) { //Offset southwards
- topOffset = topOffset - ((tooltip.tileSize + northOffset) * resizeRatio);
+ topOffset = topOffset - ((tooltip.tileSize + northOffset) * resizeRatioY);
} else { //Offset northwards
top--;
- topOffset = topOffset - (northOffset * resizeRatio);
+ topOffset = topOffset - (northOffset * resizeRatioY);
}
}
}
@@ -198,12 +203,12 @@
}
//Clamp values
- left = (left < 0 ? 0 : (left > tilesShown ? tilesShown : left));
- top = (top < 0 ? 0 : (top > tilesShown ? tilesShown : top));
+ left = (left < 0 ? 0 : (left > tilesShownX ? tilesShownX : left));
+ top = (top < 0 ? 0 : (top > tilesShownY ? tilesShownY : top));
//Calculate where on the screen the popup should appear (below the hovered tile)
- var posX = Math.round(((left - 1) * realIconSize) + leftOffset + tooltip.padding); //-1 to position at the left of the target tile
- var posY = Math.round(((tilesShown - top + 1) * realIconSize) + topOffset + tooltip.padding); //+1 to position at the bottom of the target tile
+ var posX = Math.round(((left - 1) * realIconSizeX) + leftOffset + tooltip.padding); //-1 to position at the left of the target tile
+ var posY = Math.round(((tilesShownY - top + 1) * realIconSizeY) + topOffset + tooltip.padding); //+1 to position at the bottom of the target tile
//alert(mapWidth+' | '+mapHeight+' | '+tilesShown+' | '+realIconSize+' | '+leftOffset+' | '+topOffset+' | '+left+' | '+top+' | '+posX+' | '+posY); //DEBUG
@@ -221,7 +226,7 @@
docHeight = $wrap.outerHeight();
if (posY + docHeight > map.size.y) { //Is the bottom edge below the window? Snap it up if so
- posY = (posY - docHeight) - realIconSize - tooltip.padding;
+ posY = (posY - docHeight) - realIconSizeY - tooltip.padding;
}
//Actually size, move and show the tooltip box
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index e758a43589..3229304c13 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -2,13 +2,41 @@
//Keep this sorted alphabetically
#ifdef UNIT_TESTS
+/// Asserts that a condition is true
+/// If the condition is not true, fails the test
+#define TEST_ASSERT(assertion, reason) if (!(assertion)) { return Fail("Assertion failed: [reason || "No reason"]") }
+
+/// Asserts that the two parameters passed are equal, fails otherwise
+/// Optionally allows an additional message in the case of a failure
+#define TEST_ASSERT_EQUAL(a, b, message) if ((a) != (b)) { return Fail("Expected [isnull(a) ? "null" : a] to be equal to [isnull(b) ? "null" : b].[message ? " [message]" : ""]") }
+
#include "anchored_mobs.dm"
+#include "bespoke_id.dm"
+// #include "binary_insert.dm"
+// #include "card_mismatch.dm" shame we don't have this!
+#include "chain_pull_through_space.dm"
#include "character_saving.dm"
#include "component_tests.dm"
+// #include "confusion.dm"
+// #include "keybinding_init.dm"
+#include "machine_disassembly.dm"
+#include "medical_wounds.dm"
+// #include "metabolizing.dm"
+// #include "outfit_sanity.dm"
+// #include "plantgrowth_tests.dm"
+// #include "quick_swap_sanity.dm" - we don't have quick swap yet
#include "reagent_id_typos.dm"
#include "reagent_recipe_collisions.dm"
+#include "resist.dm"
+// #include "say.dm" //no saymods, someone update saycode please.
+// #include "siunit.dm"
#include "spawn_humans.dm"
+// #include "species_whitelists.dm"
#include "subsystem_init.dm"
+#include "surgeries.dm"
#include "timer_sanity.dm"
#include "unit_test.dm"
+
+#undef TEST_ASSERT
+#undef TEST_ASSERT_EQUAL
#endif
diff --git a/code/modules/unit_tests/anchored_mobs.dm b/code/modules/unit_tests/anchored_mobs.dm
index 5324179bb7..103b97e7a9 100644
--- a/code/modules/unit_tests/anchored_mobs.dm
+++ b/code/modules/unit_tests/anchored_mobs.dm
@@ -6,4 +6,4 @@
L += "[i]"
if(!L.len)
return //passed!
- Fail("The following mobs are defined as anchored. This is incompatible with the new move force/resist system and needs to be revised.: [L.Join(" ")]")
\ No newline at end of file
+ Fail("The following mobs are defined as anchored. This is incompatible with the new move force/resist system and needs to be revised.: [L.Join(" ")]")
diff --git a/code/modules/unit_tests/bespoke_id.dm b/code/modules/unit_tests/bespoke_id.dm
new file mode 100644
index 0000000000..06676c626c
--- /dev/null
+++ b/code/modules/unit_tests/bespoke_id.dm
@@ -0,0 +1,8 @@
+/datum/unit_test/bespoke_id/Run()
+ var/datum/element/base = /datum/element
+ var/base_index = initial(base.id_arg_index)
+
+ for(var/i in subtypesof(/datum/element))
+ var/datum/element/faketype = i
+ if((initial(faketype.element_flags) & ELEMENT_BESPOKE) && initial(faketype.id_arg_index) == base_index)
+ Fail("A bespoke element was not configured with a proper id_arg_index: [faketype]")
diff --git a/code/modules/unit_tests/binary_insert.dm b/code/modules/unit_tests/binary_insert.dm
new file mode 100644
index 0000000000..ac7f58208e
--- /dev/null
+++ b/code/modules/unit_tests/binary_insert.dm
@@ -0,0 +1,26 @@
+/// A test to ensure the sanity of BINARY_INSERT
+/datum/unit_test/binary_insert/Run()
+ var/list/datum/binary_insert_node/nodes = list()
+
+ var/datum/binary_insert_node/node_a = new /datum/binary_insert_node(10)
+ BINARY_INSERT(node_a, nodes, /datum/binary_insert_node, node_a, x, COMPARE_KEY)
+ TEST_ASSERT_EQUAL(nodes.len, 1, "List should have one node")
+
+ var/datum/binary_insert_node/node_b = new /datum/binary_insert_node(5)
+ BINARY_INSERT(node_b, nodes, /datum/binary_insert_node, node_b, x, COMPARE_KEY)
+ TEST_ASSERT_EQUAL(nodes.len, 2, "List should have two nodes")
+ TEST_ASSERT_EQUAL(nodes[1].x, 5, "The first node should be the one with 5")
+ TEST_ASSERT_EQUAL(nodes[2].x, 10, "The second node should be the one with 10")
+
+ var/datum/binary_insert_node/node_c = new /datum/binary_insert_node(15)
+ BINARY_INSERT(node_c, nodes, /datum/binary_insert_node, node_c, x, COMPARE_KEY)
+ TEST_ASSERT_EQUAL(nodes.len, 3, "List should have three nodes")
+ TEST_ASSERT_EQUAL(nodes[1].x, 5, "The first node should be the one with 5")
+ TEST_ASSERT_EQUAL(nodes[2].x, 10, "The second node should be the one with 10")
+ TEST_ASSERT_EQUAL(nodes[3].x, 15, "The third node should be the one with 15")
+
+/datum/binary_insert_node
+ var/x
+
+/datum/binary_insert_node/New(_x)
+ x = _x
diff --git a/code/modules/unit_tests/chain_pull_through_space.dm b/code/modules/unit_tests/chain_pull_through_space.dm
new file mode 100644
index 0000000000..ffdd1bf7c9
--- /dev/null
+++ b/code/modules/unit_tests/chain_pull_through_space.dm
@@ -0,0 +1,62 @@
+/datum/unit_test/chain_pull_through_space
+ var/turf/open/space/space_tile
+ var/turf/claimed_tile
+ var/mob/living/carbon/human/alice
+ var/mob/living/carbon/human/bob
+ var/mob/living/carbon/human/charlie
+
+/datum/unit_test/chain_pull_through_space/New()
+ ..()
+
+ // Create a space tile that goes to another z-level
+ claimed_tile = run_loc_bottom_left
+
+ space_tile = new(locate(run_loc_bottom_left.x, run_loc_bottom_left.y, run_loc_bottom_left.z))
+ space_tile.destination_x = 100
+ space_tile.destination_y = 100
+ space_tile.destination_z = 5
+
+ // Create our list of humans, all adjacent to one another
+ alice = new(locate(run_loc_bottom_left.x + 2, run_loc_bottom_left.y, run_loc_bottom_left.z))
+ alice.name = "Alice"
+
+ bob = new(locate(run_loc_bottom_left.x + 3, run_loc_bottom_left.y, run_loc_bottom_left.z))
+ bob.name = "Bob"
+
+ charlie = new(locate(run_loc_bottom_left.x + 4, run_loc_bottom_left.y, run_loc_bottom_left.z))
+ charlie.name = "Charlie"
+
+/datum/unit_test/chain_pull_through_space/Destroy()
+ space_tile.copyTurf(claimed_tile)
+ qdel(alice)
+ qdel(bob)
+ qdel(charlie)
+ return ..()
+
+/datum/unit_test/chain_pull_through_space/Run()
+ // Alice pulls Bob, who pulls Charlie
+ // Normally, when Alice moves forward, the rest follow
+ alice.start_pulling(bob)
+ bob.start_pulling(charlie)
+
+ // Walk normally to the left, make sure we're still a chain
+ alice.Move(locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z))
+ if (bob.x != run_loc_bottom_left.x + 2)
+ return Fail("During normal move, Bob was not at the correct x ([bob.x])")
+ if (charlie.x != run_loc_bottom_left.x + 3)
+ return Fail("During normal move, Charlie was not at the correct x ([charlie.x])")
+
+ // We're going through the space turf now that should teleport us
+ alice.Move(run_loc_bottom_left)
+ if (alice.z != space_tile.destination_z)
+ return Fail("Alice did not teleport to the destination z-level. Current location: ([alice.x], [alice.y], [alice.z])")
+
+ if (bob.z != space_tile.destination_z)
+ return Fail("Bob did not teleport to the destination z-level. Current location: ([bob.x], [bob.y], [bob.z])")
+ if (!bob.Adjacent(alice))
+ return Fail("Bob is not adjacent to Alice. Bob is at [bob.x], Alice is at [alice.x]")
+
+ if (charlie.z != space_tile.destination_z)
+ return Fail("Charlie did not teleport to the destination z-level. Current location: ([charlie.x], [charlie.y], [charlie.z])")
+ if (!charlie.Adjacent(bob))
+ return Fail("Charlie is not adjacent to Bob. Charlie is at [charlie.x], Bob is at [bob.x]")
diff --git a/code/modules/unit_tests/component_tests.dm b/code/modules/unit_tests/component_tests.dm
index 409d7f4322..0099d7508c 100644
--- a/code/modules/unit_tests/component_tests.dm
+++ b/code/modules/unit_tests/component_tests.dm
@@ -9,4 +9,4 @@
if(dupe_type && !ispath(dupe_type))
bad_dts += t
if(length(bad_dms) || length(bad_dts))
- Fail("Components with invalid dupe modes: ([bad_dms.Join(",")]) ||| Components with invalid dupe types: ([bad_dts.Join(",")])")
\ No newline at end of file
+ Fail("Components with invalid dupe modes: ([bad_dms.Join(",")]) ||| Components with invalid dupe types: ([bad_dts.Join(",")])")
diff --git a/code/modules/unit_tests/machine_disassembly.dm b/code/modules/unit_tests/machine_disassembly.dm
new file mode 100644
index 0000000000..bcc769bcf2
--- /dev/null
+++ b/code/modules/unit_tests/machine_disassembly.dm
@@ -0,0 +1,13 @@
+/// Ensures that when disassembling a machine, all the parts are given back
+/datum/unit_test/machine_disassembly/Run()
+ var/obj/machinery/freezer = allocate(/obj/machinery/atmospherics/components/unary/thermomachine/freezer)
+
+ var/turf/freezer_location = freezer.loc
+ freezer_location.ChangeTurf(/turf/open/floor/plasteel)
+ freezer.deconstruct()
+
+ // Check that the components are created
+ TEST_ASSERT(locate(/obj/item/stock_parts/micro_laser) in freezer_location, "Couldn't find micro-laser when disassembling freezer")
+
+ // Check that the circuit board itself is created
+ TEST_ASSERT(locate(/obj/item/circuitboard/machine/thermomachine/freezer) in freezer_location, "Couldn't find the circuit board when disassembling freezer")
diff --git a/code/modules/unit_tests/medical_wounds.dm b/code/modules/unit_tests/medical_wounds.dm
new file mode 100644
index 0000000000..75c08931f1
--- /dev/null
+++ b/code/modules/unit_tests/medical_wounds.dm
@@ -0,0 +1,87 @@
+/// This test is used to make sure a flesh-and-bone base human can suffer all the types of wounds, and that suffering more severe wounds removes and replaces the lesser wound. Also tests that [/mob/living/carbon/proc/fully_heal] removes all wounds
+/datum/unit_test/test_human_base/Run()
+ var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human)
+
+ /// the limbs have no wound resistance like the chest and head do, so let's go with the r_arm
+ var/obj/item/bodypart/tested_part = victim.get_bodypart(BODY_ZONE_R_ARM)
+ /// In order of the wound types we're trying to inflict, what sharpness do we need to deal them?
+ var/list/sharps = list(SHARP_NONE, SHARP_EDGED, SHARP_POINTY, SHARP_NONE)
+ /// Since burn wounds need burn damage, duh
+ var/list/dam_types = list(BRUTE, BRUTE, BRUTE, BURN)
+
+ var/i = 1
+ var/list/iter_test_wound_list
+
+ for(iter_test_wound_list in list(list(/datum/wound/blunt/moderate, /datum/wound/blunt/severe, /datum/wound/blunt/critical),\
+ list(/datum/wound/slash/moderate, /datum/wound/slash/severe, /datum/wound/slash/critical),\
+ list(/datum/wound/pierce/moderate, /datum/wound/pierce/severe, /datum/wound/pierce/critical),\
+ list(/datum/wound/burn/moderate, /datum/wound/burn/severe, /datum/wound/burn/critical)))
+
+ TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test")
+ var/datum/wound/iter_test_wound
+ var/threshold_penalty = 0
+
+ for(iter_test_wound in iter_test_wound_list)
+ var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty
+ if(dam_types[i] == BRUTE)
+ tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i])
+ else if(dam_types[i] == BURN)
+ tested_part.receive_damage(0, WOUND_MINIMUM_DAMAGE, wound_bonus = threshold, sharpness=sharps[i])
+
+ TEST_ASSERT(length(victim.all_wounds), "Patient has no wounds when one wound is expected. Severity: [initial(iter_test_wound.severity)]")
+ TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]")
+ var/datum/wound/actual_wound = victim.all_wounds[1]
+ TEST_ASSERT_EQUAL(actual_wound.type, iter_test_wound, "Patient has wound of incorrect severity. Expected: [initial(iter_test_wound.name)] Got: [actual_wound]")
+ threshold_penalty = actual_wound.threshold_penalty
+ i++
+ victim.fully_heal(TRUE) // should clear all wounds between types
+
+
+/// This test is used for making sure species with bones but no flesh (skeletons, plasmamen) can only suffer BONE_WOUNDS, and nothing tagged with FLESH_WOUND (it's possible to require both)
+/datum/unit_test/test_human_bone/Run()
+ var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human)
+
+ /// the limbs have no wound resistance like the chest and head do, so let's go with the r_arm
+ var/obj/item/bodypart/tested_part = victim.get_bodypart(BODY_ZONE_R_ARM)
+ /// In order of the wound types we're trying to inflict, what sharpness do we need to deal them?
+ var/list/sharps = list(SHARP_NONE, SHARP_EDGED, SHARP_POINTY, SHARP_NONE)
+ /// Since burn wounds need burn damage, duh
+ var/list/dam_types = list(BRUTE, BRUTE, BRUTE, BURN)
+
+ var/i = 1
+ var/list/iter_test_wound_list
+ victim.dna.species.species_traits &= HAS_FLESH // take away the base human's flesh (ouchie!) ((not actually ouchie, this just affects their wounds and dismemberment handling))
+
+ for(iter_test_wound_list in list(list(/datum/wound/blunt/moderate, /datum/wound/blunt/severe, /datum/wound/blunt/critical),\
+ list(/datum/wound/slash/moderate, /datum/wound/slash/severe, /datum/wound/slash/critical),\
+ list(/datum/wound/pierce/moderate, /datum/wound/pierce/severe, /datum/wound/pierce/critical),\
+ list(/datum/wound/burn/moderate, /datum/wound/burn/severe, /datum/wound/burn/critical)))
+
+ TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test")
+ var/datum/wound/iter_test_wound
+ var/threshold_penalty = 0
+
+ for(iter_test_wound in iter_test_wound_list)
+ var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty
+ if(dam_types[i] == BRUTE)
+ tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i])
+ else if(dam_types[i] == BURN)
+ tested_part.receive_damage(0, WOUND_MINIMUM_DAMAGE, wound_bonus = threshold, sharpness=sharps[i])
+
+ // so if we just tried to deal a flesh wound, make sure we didn't actually suffer it. We may have suffered a bone wound instead, but we just want to make sure we don't have a flesh wound
+ if(initial(iter_test_wound.wound_flags) & FLESH_WOUND)
+ if(!length(victim.all_wounds)) // not having a wound is good news
+ continue
+ else // we have to check that it's actually a bone wound and not the intended wound type
+ TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]")
+ var/datum/wound/actual_wound = victim.all_wounds[1]
+ TEST_ASSERT((actual_wound.wound_flags & ~FLESH_WOUND), "Patient has flesh wound despite no HAS_FLESH flag, expected either no wound or bone wound. Offending wound: [actual_wound]")
+ threshold_penalty = actual_wound.threshold_penalty
+ else // otherwise if it's a bone wound, check that we have it per usual
+ TEST_ASSERT(length(victim.all_wounds), "Patient has no wounds when one wound is expected. Severity: [initial(iter_test_wound.severity)]")
+ TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]")
+ var/datum/wound/actual_wound = victim.all_wounds[1]
+ TEST_ASSERT_EQUAL(actual_wound.type, iter_test_wound, "Patient has wound of incorrect severity. Expected: [initial(iter_test_wound.name)] Got: [actual_wound]")
+ threshold_penalty = actual_wound.threshold_penalty
+ i++
+ victim.fully_heal(TRUE) // should clear all wounds between types
diff --git a/code/modules/unit_tests/metabolizing.dm b/code/modules/unit_tests/metabolizing.dm
new file mode 100644
index 0000000000..895762c0ec
--- /dev/null
+++ b/code/modules/unit_tests/metabolizing.dm
@@ -0,0 +1,19 @@
+/datum/unit_test/metabolization/Run()
+ // Pause natural mob life so it can be handled entirely by the test
+ SSmobs.pause()
+
+ var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human)
+ var/mob/living/carbon/monkey/monkey = allocate(/mob/living/carbon/monkey)
+
+ for (var/reagent_type in subtypesof(/datum/reagent))
+ test_reagent(human, reagent_type)
+ test_reagent(monkey, reagent_type)
+
+/datum/unit_test/metabolization/proc/test_reagent(mob/living/carbon/C, reagent_type)
+ C.reagents.add_reagent(reagent_type, 10)
+ C.reagents.metabolize(C, can_overdose = TRUE)
+ C.reagents.clear_reagents()
+
+/datum/unit_test/metabolization/Destroy()
+ SSmobs.ignite()
+ return ..()
diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm
new file mode 100644
index 0000000000..235820f9e9
--- /dev/null
+++ b/code/modules/unit_tests/outfit_sanity.dm
@@ -0,0 +1,50 @@
+#define CHECK_OUTFIT_SLOT(outfit_key, slot_name) if (outfit.##outfit_key) { \
+ H.equip_to_slot_or_del(new outfit.##outfit_key(H), ##slot_name, TRUE); \
+ /* We don't check the result of equip_to_slot_or_del because it returns false for random jumpsuits, as they delete themselves on init */ \
+ if (!H.get_item_by_slot(##slot_name)) { \
+ Fail("[outfit.name]'s [#outfit_key] is invalid!"); \
+ } \
+}
+
+/datum/unit_test/outfit_sanity/Run()
+ var/mob/living/carbon/human/H = allocate(/mob/living/carbon/human)
+
+ for (var/outfit_type in subtypesof(/datum/outfit))
+ // Only make one human and keep undressing it because it's much faster
+ for (var/obj/item/I in H.get_equipped_items(include_pockets = TRUE))
+ qdel(I)
+
+ var/datum/outfit/outfit = new outfit_type
+ outfit.pre_equip(H, TRUE)
+
+ CHECK_OUTFIT_SLOT(uniform, ITEM_SLOT_ICLOTHING)
+ CHECK_OUTFIT_SLOT(suit, ITEM_SLOT_OCLOTHING)
+ CHECK_OUTFIT_SLOT(back, ITEM_SLOT_BACK)
+ CHECK_OUTFIT_SLOT(belt, ITEM_SLOT_BELT)
+ CHECK_OUTFIT_SLOT(gloves, ITEM_SLOT_GLOVES)
+ CHECK_OUTFIT_SLOT(shoes, ITEM_SLOT_FEET)
+ CHECK_OUTFIT_SLOT(head, ITEM_SLOT_HEAD)
+ CHECK_OUTFIT_SLOT(mask, ITEM_SLOT_MASK)
+ CHECK_OUTFIT_SLOT(neck, ITEM_SLOT_NECK)
+ CHECK_OUTFIT_SLOT(ears, ITEM_SLOT_EARS)
+ CHECK_OUTFIT_SLOT(glasses, ITEM_SLOT_EYES)
+ CHECK_OUTFIT_SLOT(id, ITEM_SLOT_ID)
+ CHECK_OUTFIT_SLOT(suit_store, ITEM_SLOT_SUITSTORE)
+ CHECK_OUTFIT_SLOT(l_pocket, ITEM_SLOT_POCKET)
+ CHECK_OUTFIT_SLOT(r_pocket, ITEM_SLOT_POCKET)
+
+ if (outfit.backpack_contents || outfit.box)
+ var/list/backpack_contents = outfit.backpack_contents?.Copy()
+ if (outfit.box)
+ if (!backpack_contents)
+ backpack_contents = list()
+ backpack_contents.Insert(1, outfit.box)
+ backpack_contents[outfit.box] = 1
+
+ for (var/path in backpack_contents)
+ var/number = backpack_contents[path] || 1
+ for (var/_ in 1 to number)
+ if (!H.equip_to_slot_or_del(new path(H), ITEM_SLOT_BACKPACK, TRUE))
+ Fail("[outfit.name]'s backpack_contents are invalid! Couldn't add [path] to backpack.")
+
+#undef CHECK_OUTFIT_SLOT
diff --git a/code/modules/unit_tests/plantgrowth_tests.dm b/code/modules/unit_tests/plantgrowth_tests.dm
new file mode 100644
index 0000000000..6b40236860
--- /dev/null
+++ b/code/modules/unit_tests/plantgrowth_tests.dm
@@ -0,0 +1,27 @@
+
+// Checks plants for broken tray icons. Use Advanced Proc Call to activate.
+// Maybe some day it would be used as unit test.
+// -------- IT IS NOW!
+/datum/unit_test/plantgrowth/Run()
+ var/list/states = icon_states('icons/obj/hydroponics/growing.dmi')
+ states |= icon_states('icons/obj/hydroponics/growing_fruits.dmi')
+ states |= icon_states('icons/obj/hydroponics/growing_flowers.dmi')
+ states |= icon_states('icons/obj/hydroponics/growing_mushrooms.dmi')
+ states |= icon_states('icons/obj/hydroponics/growing_vegetables.dmi')
+ states |= icon_states('goon/icons/obj/hydroponics.dmi')
+ var/list/paths = subtypesof(/obj/item/seeds) - /obj/item/seeds - typesof(/obj/item/seeds/sample) - /obj/item/seeds/lavaland
+
+ for(var/seedpath in paths)
+ var/obj/item/seeds/seed = new seedpath
+
+ for(var/i in 1 to seed.growthstages)
+ if("[seed.icon_grow][i]" in states)
+ continue
+ Fail("[seed.name] ([seed.type]) lacks the [seed.icon_grow][i] icon!")
+
+ if(!(seed.icon_dead in states))
+ Fail("[seed.name] ([seed.type]) lacks the [seed.icon_dead] icon!")
+
+ if(seed.icon_harvest) // mushrooms have no grown sprites, same for items with no product
+ if(!(seed.icon_harvest in states))
+ Fail("[seed.name] ([seed.type]) lacks the [seed.icon_harvest] icon!")
diff --git a/code/modules/unit_tests/quick_swap_sanity.dm b/code/modules/unit_tests/quick_swap_sanity.dm
new file mode 100644
index 0000000000..85e73f9b6a
--- /dev/null
+++ b/code/modules/unit_tests/quick_swap_sanity.dm
@@ -0,0 +1,31 @@
+/// Test that quick swap correctly swaps items and invalidates suit storage
+/datum/unit_test/quick_swap_sanity/Run()
+ // Create a human with a medical winter coat and a health analyzer in suit storage
+ var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human)
+
+ var/obj/item/coat = allocate(/obj/item/clothing/suit/hooded/wintercoat/medical)
+ TEST_ASSERT(human.equip_to_slot_if_possible(coat, ITEM_SLOT_OCLOTHING), "Couldn't equip winter coat")
+
+ var/obj/item/analyzer = allocate(/obj/item/healthanalyzer)
+ TEST_ASSERT(human.equip_to_slot_if_possible(analyzer, ITEM_SLOT_SUITSTORE), "Couldn't equip health analyzer")
+
+ // Then, have them quick swap between the coat and a space suit
+ var/obj/item/hardsuit = allocate(/obj/item/clothing/suit/space/hardsuit)
+ TEST_ASSERT(human.equip_to_appropriate_slot(hardsuit, swap = TRUE), "Couldn't quick swap to hardsuit")
+
+ // Check if the human has the hardsuit on
+ TEST_ASSERT_EQUAL(human.wear_suit, hardsuit, "Human didn't equip the hardsuit")
+
+ // Make sure the health analyzer was dropped as part of the swap
+ // Since health analyzers are an invalid suit storage item
+ TEST_ASSERT_EQUAL(human.s_store, null, "Human didn't drop the health analyzer")
+
+ // Give the human an emergency oxygen tank
+ // This is valid suit storage for both the winter coat AND the hardsuit
+ var/obj/item/tank = allocate(/obj/item/tank/internals/emergency_oxygen)
+ TEST_ASSERT(human.equip_to_slot_if_possible(tank, ITEM_SLOT_SUITSTORE), "Couldn't equip emergency oxygen tank")
+
+ // Now, quick swap back to the coat
+ // Since the tank is a valid suit storage item, it should not be dropped
+ TEST_ASSERT(human.equip_to_appropriate_slot(coat, swap = TRUE), "Couldn't quick swap to coat")
+ TEST_ASSERT_EQUAL(human.s_store, tank, "Human dropped the oxygen tank, when it was a valid item to keep in suit storage")
diff --git a/code/modules/unit_tests/resist.dm b/code/modules/unit_tests/resist.dm
new file mode 100644
index 0000000000..9fe5cd1114
--- /dev/null
+++ b/code/modules/unit_tests/resist.dm
@@ -0,0 +1,29 @@
+/// Test that stop, drop, and roll lowers fire stacks
+/datum/unit_test/stop_drop_and_roll/Run()
+ var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human)
+
+ TEST_ASSERT_EQUAL(human.fire_stacks, 0, "Human does not have 0 fire stacks pre-ignition")
+
+ human.adjust_fire_stacks(5)
+ human.IgniteMob()
+
+ TEST_ASSERT_EQUAL(human.fire_stacks, 5, "Human does not have 5 fire stacks pre-resist")
+
+ // Stop, drop, and roll has a sleep call. This would delay the test, and is not necessary.
+ CallAsync(human, /mob/living/verb/resist)
+
+ TEST_ASSERT(human.fire_stacks < 5, "Human did not lower fire stacks after resisting")
+
+/// Test that you can resist out of a container
+/datum/unit_test/container_resist/Run()
+ var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human)
+ var/obj/structure/closet/closet = allocate(/obj/structure/closet, get_turf(human))
+
+ closet.open(human)
+ TEST_ASSERT(!(human in closet.contents), "Human was in the contents of an open closet")
+
+ closet.close(human)
+ TEST_ASSERT(human in closet.contents, "Human was not in the contents of the closed closet")
+
+ human.resist()
+ TEST_ASSERT(!(human in closet.contents), "Human resisted out of a standard closet, but was still in it")
diff --git a/code/modules/unit_tests/say.dm b/code/modules/unit_tests/say.dm
new file mode 100644
index 0000000000..3fe6675ab4
--- /dev/null
+++ b/code/modules/unit_tests/say.dm
@@ -0,0 +1,24 @@
+/// Test to verify message mods are parsed correctly
+/datum/unit_test/get_message_mods
+ var/mob/host_mob
+
+/datum/unit_test/get_message_mods/Run()
+ host_mob = allocate(/mob/living/carbon/human)
+
+ test("Hello", "Hello", list())
+ test(";HELP", "HELP", list(MODE_HEADSET = TRUE))
+ test(";%Never gonna give you up", "Never gonna give you up", list(MODE_HEADSET = TRUE, MODE_SING = TRUE))
+ test(".s Gun plz", "Gun plz", list(RADIO_KEY = RADIO_KEY_SECURITY, RADIO_EXTENSION = RADIO_CHANNEL_SECURITY))
+ test("...What", "...What", list())
+ //note to lettern: add the ++, ||, __, and the verb*text checks
+
+/datum/unit_test/get_message_mods/proc/test(message, expected_message, list/expected_mods)
+ var/list/mods = list()
+ TEST_ASSERT_EQUAL(host_mob.get_message_mods(message, mods), expected_message, "Chopped message was not what we expected. Message: [message]")
+
+ for (var/mod_key in mods)
+ TEST_ASSERT_EQUAL(mods[mod_key], expected_mods[mod_key], "The value for [mod_key] was not what we expected. Message: [message]")
+ expected_mods -= mod_key
+
+ if (expected_mods.len)
+ Fail("Some message mods were expected, but were not returned by get_message_mods: [json_encode(expected_mods)]. Message: [message]")
diff --git a/code/modules/unit_tests/spawn_humans.dm b/code/modules/unit_tests/spawn_humans.dm
index 0500deae0a..7189e87277 100644
--- a/code/modules/unit_tests/spawn_humans.dm
+++ b/code/modules/unit_tests/spawn_humans.dm
@@ -1,7 +1,7 @@
/datum/unit_test/spawn_humans/Run()
- var/locs = block(run_loc_bottom_left, run_loc_top_right)
+ var/locs = block(run_loc_bottom_left, run_loc_top_right)
- for(var/I in 1 to 5)
- new /mob/living/carbon/human(pick(locs))
+ for(var/I in 1 to 5)
+ new /mob/living/carbon/human(pick(locs))
- sleep(50)
+ sleep(50)
diff --git a/code/modules/unit_tests/subsystem_init.dm b/code/modules/unit_tests/subsystem_init.dm
index f768f03f78..7d5473bc1b 100644
--- a/code/modules/unit_tests/subsystem_init.dm
+++ b/code/modules/unit_tests/subsystem_init.dm
@@ -4,4 +4,4 @@
if(ss.flags & SS_NO_INIT)
continue
if(!ss.initialized)
- Fail("[ss]([ss.type]) is a subsystem meant to initialize but doesn't get set as initialized.")
\ No newline at end of file
+ Fail("[ss]([ss.type]) is a subsystem meant to initialize but doesn't get set as initialized.")
diff --git a/code/modules/unit_tests/surgeries.dm b/code/modules/unit_tests/surgeries.dm
new file mode 100644
index 0000000000..491b0c5645
--- /dev/null
+++ b/code/modules/unit_tests/surgeries.dm
@@ -0,0 +1,79 @@
+/datum/unit_test/amputation/Run()
+ var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human)
+ var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human)
+
+ TEST_ASSERT_EQUAL(patient.get_missing_limbs().len, 0, "Patient is somehow missing limbs before surgery")
+
+ var/datum/surgery/amputation/surgery = new(patient, BODY_ZONE_R_ARM, patient.get_bodypart(BODY_ZONE_R_ARM))
+
+ var/datum/surgery_step/sever_limb/sever_limb = new
+ sever_limb.success(user, patient, BODY_ZONE_R_ARM, null, surgery)
+
+ TEST_ASSERT_EQUAL(patient.get_missing_limbs().len, 1, "Patient did not lose any limbs")
+ TEST_ASSERT_EQUAL(patient.get_missing_limbs()[1], BODY_ZONE_R_ARM, "Patient is missing a limb that isn't the one we operated on")
+
+/datum/unit_test/brain_surgery/Run()
+ var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human)
+ patient.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_SURGERY)
+ patient.setOrganLoss(ORGAN_SLOT_BRAIN, 20)
+
+ TEST_ASSERT(patient.has_trauma_type(), "Patient does not have any traumas, despite being given one")
+
+ var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human)
+
+ var/datum/surgery_step/fix_brain/fix_brain = new
+ fix_brain.success(user, patient)
+
+ TEST_ASSERT(!patient.has_trauma_type(), "Patient kept their brain trauma after brain surgery")
+ TEST_ASSERT(patient.getOrganLoss(ORGAN_SLOT_BRAIN) < 20, "Patient did not heal their brain damage after brain surgery")
+
+/datum/unit_test/multiple_surgeries/Run()
+ var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human)
+ var/mob/living/carbon/human/patient_zero = allocate(/mob/living/carbon/human)
+ var/mob/living/carbon/human/patient_one = allocate(/mob/living/carbon/human)
+
+ var/obj/item/scalpel/scalpel = allocate(/obj/item/scalpel)
+
+ var/datum/surgery_step/incise/surgery_step = new
+ var/datum/surgery/organ_manipulation/surgery_for_zero = new
+
+ INVOKE_ASYNC(surgery_step, /datum/surgery_step/proc/initiate, user, patient_zero, BODY_ZONE_CHEST, scalpel, surgery_for_zero)
+ TEST_ASSERT(surgery_for_zero.step_in_progress, "Surgery on patient zero was not initiated")
+
+ var/datum/surgery/organ_manipulation/surgery_for_one = new
+
+ // Without waiting for the incision to complete, try to start a new surgery
+ TEST_ASSERT(!surgery_step.initiate(user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one), "Was allowed to start a second surgery without the rod of asclepius")
+ TEST_ASSERT(!surgery_for_one.step_in_progress, "Surgery for patient one is somehow in progress, despite not initiating")
+
+ user.apply_status_effect(STATUS_EFFECT_HIPPOCRATIC_OATH)
+ INVOKE_ASYNC(surgery_step, /datum/surgery_step/proc/initiate, user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one)
+ TEST_ASSERT(surgery_for_one.step_in_progress, "Surgery on patient one was not initiated, despite having rod of asclepius")
+
+/datum/unit_test/tend_wounds/Run()
+ var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human)
+ patient.take_overall_damage(100, 100)
+
+ var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human)
+
+ // Test that tending wounds actually lowers damage
+ var/datum/surgery_step/heal/brute/basic/basic_brute_heal = new
+ basic_brute_heal.success(user, patient, BODY_ZONE_CHEST)
+ TEST_ASSERT(patient.getBruteLoss() < 100, "Tending brute wounds didn't lower brute damage ([patient.getBruteLoss()])")
+
+ var/datum/surgery_step/heal/burn/basic/basic_burn_heal = new
+ basic_burn_heal.success(user, patient, BODY_ZONE_CHEST)
+ TEST_ASSERT(patient.getFireLoss() < 100, "Tending burn wounds didn't lower burn damage ([patient.getFireLoss()])")
+
+ // Test that wearing clothing lowers heal amount
+ var/mob/living/carbon/human/naked_patient = allocate(/mob/living/carbon/human)
+ naked_patient.take_overall_damage(100)
+
+ var/mob/living/carbon/human/clothed_patient = allocate(/mob/living/carbon/human)
+ clothed_patient.equipOutfit(/datum/outfit/job/doctor, TRUE)
+ clothed_patient.take_overall_damage(100)
+
+ basic_brute_heal.success(user, naked_patient, BODY_ZONE_CHEST)
+ basic_brute_heal.success(user, clothed_patient, BODY_ZONE_CHEST)
+
+ TEST_ASSERT(naked_patient.getBruteLoss() < clothed_patient.getBruteLoss(), "Naked patient did not heal more from wounds tending than a clothed patient")
diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm
index 49974f2cb0..36b406e75e 100644
--- a/code/modules/unit_tests/unit_test.dm
+++ b/code/modules/unit_tests/unit_test.dm
@@ -1,14 +1,9 @@
/*
-
Usage:
Override /Run() to run your test code
-
Call Fail() to fail the test (You should specify a reason)
-
You may use /New() and /Destroy() for setup/teardown respectively
-
You can use the run_loc_bottom_left and run_loc_top_right to get turfs for testing
-
*/
GLOBAL_DATUM(current_test, /datum/unit_test)
@@ -18,16 +13,18 @@ GLOBAL_VAR(test_log)
/datum/unit_test
//Bit of metadata for the future maybe
var/list/procs_tested
-
+
//usable vars
var/turf/run_loc_bottom_left
var/turf/run_loc_top_right
//internal shit
var/succeeded = TRUE
+ var/list/allocated
var/list/fail_reasons
/datum/unit_test/New()
+ allocated = new
run_loc_bottom_left = locate(1, 1, 1)
run_loc_top_right = locate(5, 5, 1)
@@ -35,6 +32,7 @@ GLOBAL_VAR(test_log)
//clear the test area
for(var/atom/movable/AM in block(run_loc_bottom_left, run_loc_top_right))
qdel(AM)
+ QDEL_LIST(allocated)
return ..()
/datum/unit_test/proc/Run()
@@ -48,6 +46,18 @@ GLOBAL_VAR(test_log)
LAZYADD(fail_reasons, reason)
+/// Allocates an instance of the provided type, and places it somewhere in an available loc
+/// Instances allocated through this proc will be destroyed when the test is over
+/datum/unit_test/proc/allocate(type, ...)
+ var/list/arguments = args.Copy(2)
+ if (!arguments.len)
+ arguments = list(run_loc_bottom_left)
+ else if (arguments[1] == null)
+ arguments[1] = run_loc_bottom_left
+ var/instance = new type(arglist(arguments))
+ allocated += instance
+ return instance
+
/proc/RunUnitTests()
CHECK_TICK
diff --git a/code/modules/uplink/uplink_items/uplink_clothing.dm b/code/modules/uplink/uplink_items/uplink_clothing.dm
index 745eddcc07..6163e5722a 100644
--- a/code/modules/uplink/uplink_items/uplink_clothing.dm
+++ b/code/modules/uplink/uplink_items/uplink_clothing.dm
@@ -92,8 +92,8 @@
cost = 6
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
-/datum/uplink_item/device_tools/guerillagloves
- name = "Guerilla Gloves"
+/datum/uplink_item/device_tools/guerrillagloves
+ name = "Guerrilla Gloves"
desc = "A pair of highly robust combat gripper gloves that excels at performing takedowns at close range, with an added lining of insulation. Careful not to hit a wall!"
item = /obj/item/clothing/gloves/tackler/combat/insulated
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
diff --git a/code/modules/uplink/uplink_items/uplink_implants.dm b/code/modules/uplink/uplink_items/uplink_implants.dm
index bb4e0c7960..4839c96a2d 100644
--- a/code/modules/uplink/uplink_items/uplink_implants.dm
+++ b/code/modules/uplink/uplink_items/uplink_implants.dm
@@ -31,7 +31,7 @@
/datum/uplink_item/implants/warp
name = "Warp Implant"
- desc = "An implant injected into the body and later activated at the user's will. It will inject eigenstasium which saves the user's location and teleports them there after five seconds. Lasts only fifteen times."
+ desc = "An implant injected into the body and later activated at the user's will. Allows the user to teleport to where they were 10 seconds ago. Has a 10 second cooldown."
item = /obj/item/storage/box/syndie_kit/imp_warp
cost = 6
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index a115300085..26bee38f7b 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -529,7 +529,7 @@ GLOBAL_LIST_EMPTY(vending_products)
if(5) // limb squish!
for(var/i in C.bodyparts)
var/obj/item/bodypart/squish_part = i
- if(squish_part.is_organic_limb())
+ if(squish_part.is_organic_limb() || squish_part.render_like_organic)
var/type_wound = pick(list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate))
squish_part.force_wound_upwards(type_wound)
else
diff --git a/code/modules/vore/eating/living.dm b/code/modules/vore/eating/living.dm
index 8923e9107d..a0ae58a44d 100644
--- a/code/modules/vore/eating/living.dm
+++ b/code/modules/vore/eating/living.dm
@@ -342,21 +342,23 @@
to_chat(src, "You can't do that so fast, slow down.")
return
- var/list/choices
+ DelayNextAction(CLICK_CD_MELEE, flush = TRUE)
+
+ var/list/lickable = list()
for(var/mob/living/L in view(1))
if(L != src && (!L.ckey || L.client?.prefs.vore_flags & LICKABLE) && Adjacent(L))
- LAZYADD(choices, L)
+ LAZYADD(lickable, L)
+ for(var/mob/living/listed in lickable)
+ lickable[listed] = new /mutable_appearance(listed)
- if(!choices)
+ if(!lickable)
return
- var/mob/living/tasted = input(src, "Who would you like to lick? (Excluding yourself and those with the preference disabled)", "Licking") as null|anything in choices
+ var/mob/living/tasted = show_radial_menu(src, src, lickable, radius = 40, require_near = TRUE)
if(QDELETED(tasted) || (tasted.ckey && !(tasted.client?.prefs.vore_flags & LICKABLE)) || !Adjacent(tasted) || incapacitated(ignore_restraints = TRUE))
return
- DelayNextAction(CLICK_CD_MELEE)
-
visible_message("[src] licks [tasted]!","You lick [tasted]. They taste rather like [tasted.get_taste_message()].","Slurp!")
/mob/living/proc/get_taste_message(allow_generic = TRUE, datum/species/mrace)
diff --git a/code/modules/vore/eating/vorepanel.dm b/code/modules/vore/eating/vorepanel.dm
index 1adf5ef6e7..6e3951e60a 100644
--- a/code/modules/vore/eating/vorepanel.dm
+++ b/code/modules/vore/eating/vorepanel.dm
@@ -46,6 +46,7 @@
/datum/vore_look/Destroy()
loop = null
selected = null
+ ..() //this is a must
return QDEL_HINT_HARDDEL
/datum/vore_look/Topic(href,href_list[])
@@ -660,7 +661,7 @@
if(href_list["saveprefs"])
if(!(user.client?.prefs))
return FALSE
- if(!user.client.prefs.save_character())
+ if(!user.copy_to_prefs_vr() || !user.client.prefs.save_character())
to_chat(user, "Belly Preferences not saved!")
log_admin("Could not save vore prefs on USER: [user].")
else
diff --git a/html/changelog.html b/html/changelog.html
index ba57bbfac2..8a1401744e 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -50,6 +50,127 @@
-->
04 October 2020
+ DeltaFire15 updated:
+
+
+ Detective-Google updated:
+
+
+ Putnam3145 updated:
+
+
+ monster860 updated:
+
+
+ timothyteakettle updated:
+
+
+
+ 02 October 2020
+ ArcaneMusic, with minor tweaks by TheObserver-sys updated:
+
+
+ CoreFlare updated:
+
+
+ Detective-Google updated:
+
+
+ EmeraldSundisk updated:
+
+
+ ItzGabby updated:
+
+
+ LetterN updated:
+
+
+ MrJWhit updated:
+
+
+ Putnam3145 updated:
+
+
+ SandPoot updated:
+
+
+ Tupinambis updated:
+
+
+ dapnee updated:
+
+
+ lolman360 updated:
+
+
+ timothyteakettle updated:
+
+
+ zeroisthebiggay updated:
+
+
+
01 October 2020
BlueWildrose updated:
@@ -203,272 +324,11 @@
12 September 2020
+ 01 October 2020
BlueWildrose updated:
-
- DeltaFire15 updated:
-
-
- Putnam3145 updated:
-
-
- Sonic121x updated:
-
-
- TheObserver-sys updated:
-
-
- Trilbyspaceclone updated:
-
-
- Tupinambis updated:
-
-
- lolman360 updated:
-
-
- zeroisthebiggay updated:
-
-
-
- 11 September 2020
- Putnam3145 updated:
-
-
-
- 09 September 2020
- Putnam3145 updated:
-
-
- timothyteakettle updated:
-
-
-
- 08 September 2020
- Ghommie updated:
-
-
- KeRSedChaplain updated:
-
-
- silicons updated:
-
-
-
- 07 September 2020
- DeltaFire15 updated:
-
-
- Putnam for debugging ammo loading! Thx!! updated:
-
-
-
- 06 September 2020
- Putnam3145 updated:
-
-
- lolman360, NecromancerAnne updated:
-
-
- raspy-on-osu updated:
-
-
-
- 05 September 2020
- Bhijn updated:
-
-
- Putnam3145 updated:
-
-
- raspy-on-osu updated:
-
-
-
- 04 September 2020
- timothyteakettle updated:
-
-
-
- 03 September 2020
- Ghommie updated:
-
-
-
- 02 September 2020
- Putnam3145 updated:
-
-
- Tupinambis updated:
-
-
- raspy-on-osu updated:
-
-
- timothyteakettle updated:
-
-
-
- 01 September 2020
- BlueWildrose updated:
-
-
-
- 31 August 2020
- Arturlang updated:
-
-
- Chiirno updated:
-
-
- Couls, ported by NecromancerAnne updated:
-
-
- DeltaFire15 updated:
-
-
- Detective-Google updated:
-
-
- EmeraldSundisk updated:
-
-
- ForrestWick updated:
-
-
- Ghommie updated:
-
-
- LetterN updated:
-
-
- Lynxless updated:
-
-
- Putnam3145 updated:
-
-
- Sonic121x updated:
-
-
- kappa-sama updated:
-
-
- lolman360 updated:
-
-
- raspy-on-osu updated:
-
-
- silicons updated:
-
-
- timothyteakettle updated:
-
-
- zeroisthebiggay updated:
-
-
30 August 2020
@@ -1081,66 +941,6 @@
02 August 2020
- Auris456852 updated:
-
-
- Hatterhat updated:
-
-
- KeRSedChaplain updated:
-
-
- MrJWhit updated:
-
-
- Seris02 updated:
-
-
- dapnee updated:
-
-
- ike709 and bobbahbrown updated:
-
-
- kappa-sama updated:
-
-
- timothyteakettle updated:
-
-
-
- 01 August 2020
- dapnee updated:
-
-
- silicons updated:
-
-
- timothyteakettle updated:
-
-
+ blueprint pod and edit vars directly
+
+
+ NOTE: Custom sounds from outside the base game files will not save! :(
+
+
/gi,"\n").replace(/<\/?[a-z0-9-_]+[^>]*>/gi,"").replace(/&(nbsp|amp|quot|lt|gt|apos);/g,(function(e,n){return t[n]})).replace(/?([0-9]+);/gi,(function(e,t){var n=parseInt(t,10);return String.fromCharCode(n)})).replace(/?([0-9a-f]+);/gi,(function(e,t){var n=parseInt(t,16);return String.fromCharCode(n)}))};t.buildQueryString=function(e){return Object.keys(e).map((function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])})).join("&")}},function(e,t,n){"use strict";var r={}.hasOwnProperty;e.exports=function(e,t){return r.call(e,t)}},function(e,t,n){"use strict";var r=n(53),o=n(66),i=n(18),a=n(12),c=n(72),u=[].push,s=function(e){var t=1==e,n=2==e,s=3==e,l=4==e,f=6==e,d=5==e||f;return function(p,h,g,v){for(var m,y,b=i(p),x=o(b),w=r(h,g,3),_=a(x.length),E=0,k=v||c,S=t?k(p,_):n?k(p,0):undefined;_>E;E++)if((d||E in x)&&(y=w(m=x[E],E,b),e))if(t)S[E]=y;else if(y)switch(e){case 3:return!0;case 5:return m;case 6:return E;case 2:u.call(S,m)}else if(l)return!1;return f?-1:s||l?l:S}};e.exports={forEach:s(0),map:s(1),filter:s(2),some:s(3),every:s(4),find:s(5),findIndex:s(6)}},function(e,t,n){"use strict";t.__esModule=!0,t.useSelector=t.useDispatch=t.createAction=t.combineReducers=t.applyMiddleware=t.createStore=void 0;n(0);var r=n(35);function o(e,t){var n;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0;return function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=e[Symbol.iterator]()).next.bind(n)}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);nu||n!=n?l*Infinity:l*n}},function(e,t,n){"use strict";var r=n(7).isFinite;e.exports=Number.isFinite||function(e){return"number"==typeof e&&r(e)}},function(e,t,n){"use strict";var r=n(7),o=n(62).trim,i=n(92),a=r.parseFloat,c=1/a(i+"-0")!=-Infinity;e.exports=c?function(e){var t=o(String(e)),n=a(t);return 0===n&&"-"==t.charAt(0)?-0:n}:a},function(e,t,n){"use strict";var r=n(36);e.exports=function(e){if("number"!=typeof e&&"Number"!=r(e))throw TypeError("Incorrect invocation");return+e}},function(e,t,n){"use strict";var r=n(9),o=n(5),i=n(71),a=n(115),c=n(82),u=n(18),s=n(66),l=Object.assign,f=Object.defineProperty;e.exports=!l||o((function(){if(r&&1!==l({b:1},l(f({},"a",{enumerable:!0,get:function(){f(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},t={},n=Symbol();return e[n]=7,"abcdefghijklmnopqrst".split("").forEach((function(e){t[e]=e})),7!=l({},e)[n]||"abcdefghijklmnopqrst"!=i(l({},t)).join("")}))?function(e,t){for(var n=u(e),o=arguments.length,l=1,f=a.f,d=c.f;o>l;)for(var p,h=s(arguments[l++]),g=f?i(h).concat(f(h)):i(h),v=g.length,m=0;v>m;)p=g[m++],r&&!d.call(h,p)||(n[p]=h[p]);return n}:l},function(e,t,n){"use strict";var r=n(121),o=n(85);e.exports=r?{}.toString:function(){return"[object "+o(this)+"]"}},function(e,t,n){"use strict";var r=n(7);e.exports=function(e,t){var n=r.console;n&&n.error&&(1===arguments.length?n.error(e):n.error(e,t))}},function(e,t,n){"use strict";var r=n(37);e.exports=function(e){var t=r(e);if(t<0)throw RangeError("The argument can't be less than 0");return t}},function(e,t,n){"use strict";t.__esModule=!0,t._CI=Ae,t._HI=B,t._M=Te,t._MCCC=Le,t._ME=Ie,t._MFCC=Ve,t._MP=Ce,t._MR=ye,t.__render=je,t.createComponentVNode=function(e,t,n,r,o){var a=new T(1,null,null,e=function(e,t){if(12&e)return e;if(t.prototype&&t.prototype.render)return 4;if(t.render)return 32776;return 8}(e,t),r,function(e,t,n){var r=(32768&e?t.render:t).defaultProps;if(i(r))return n;if(i(n))return l(r,null);return N(n,r)}(e,t,n),function(e,t,n){if(4&e)return n;var r=(32768&e?t.render:t).defaultHooks;if(i(r))return n;if(i(n))return r;return N(n,r)}(e,t,o),t);k.createVNode&&k.createVNode(a);return a},t.createFragment=M,t.createPortal=function(e,t){var n=B(e);return O(1024,1024,null,n,0,null,n.key,t)},t.createRef=function(){return{current:null}},t.createRenderer=function(e){return function(t,n,r,o){e||(e=t),Fe(n,e,r,o)}},t.createTextVNode=I,t.createVNode=O,t.directClone=L,t.findDOMfromVNode=b,t.forwardRef=function(e){return{render:e}},t.getFlagsForElementVnode=function(e){switch(e){case"svg":return 32;case"input":return 64;case"select":return 256;case"textarea":return 128;case"$F":return 8192;default:return 1}},t.linkEvent=function(e,t){if(c(t))return{data:e,event:t};return null},t.normalizeProps=function(e){var t=e.props;if(t){var n=e.flags;481&n&&(void 0!==t.children&&i(e.children)&&P(e,t.children),void 0!==t.className&&(e.className=t.className||null,t.className=undefined)),void 0!==t.key&&(e.key=t.key,t.key=undefined),void 0!==t.ref&&(e.ref=8&n?l(e.ref,t.ref):t.ref,t.ref=undefined)}return e},t.render=Fe,t.rerender=He,t.version=t.options=t.Fragment=t.EMPTY_OBJ=t.Component=void 0;var r=Array.isArray;function o(e){var t=typeof e;return"string"===t||"number"===t}function i(e){return null==e}function a(e){return null===e||!1===e||!0===e||void 0===e}function c(e){return"function"==typeof e}function u(e){return"string"==typeof e}function s(e){return null===e}function l(e,t){var n={};if(e)for(var r in e)n[r]=e[r];if(t)for(var o in t)n[o]=t[o];return n}function f(e){return!s(e)&&"object"==typeof e}var d={};t.EMPTY_OBJ=d;function p(e){return e.substr(2).toLowerCase()}function h(e,t){e.appendChild(t)}function g(e,t,n){s(n)?h(e,t):e.insertBefore(t,n)}function v(e,t){e.removeChild(t)}function m(e){for(var t=0;t
\n":"'+(n?e:Y(e,!0))+"
\n"},t.blockquote=function(e){return""+(n?e:Y(e,!0))+"\n"+e+"
\n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"
\n":"
\n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+""+r+">\n"},t.listitem=function(e){return"\n\n"+e+"\n"+t+"
\n"},t.tablerow=function(e){return"\n"+e+" \n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+""+n+">\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
":"
"},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=z(this.options.sanitize,this.options.baseUrl,e)))return n;var r='"+n+""},t.image=function(e,t,n){if(null===(e=z(this.options.sanitize,this.options.baseUrl,e)))return n;var r='":">"},t.text=function(e){return e},e}(),$=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),H=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t)){var n=t;do{this.seen[n]++,t=n+"-"+this.seen[n]}while(this.seen.hasOwnProperty(t))}return this.seen[t]=0,t},e}(),W=r.defaults,q=w.unescape,G=function(){function e(e){this.options=e||W,this.options.renderer=this.options.renderer||new U,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new $,this.slugger=new H}e.parse=function(t,n){return new e(n).parse(t)};var t=e.prototype;return t.parse=function(e,t){void 0===t&&(t=!0);var n,r,o,i,a,c,u,s,l,f,d,p,h,g,v,m,y,b,x="",w=e.length;for(n=0;n
"+Q(u.message+"",!0)+"";throw u}}return ne.options=ne.setOptions=function(e){return X(ne.defaults,e),ee(ne.defaults),ne},ne.getDefaults=J,ne.defaults=te,ne.use=function(e){var t=X({},e);if(e.renderer&&function(){var n=ne.defaults.renderer||new U,r=function(t){var r=n[t];n[t]=function(){for(var o=arguments.length,i=new Array(o),a=0;a
'+(n?e:Y(e,!0))+"\n":""+(n?e:Y(e,!0))+"\n"},t.blockquote=function(e){return"\n"+e+"\n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"
"+e+"
\n"},t.table=function(e,t){return t&&(t=""+t+""),""+e+""},t.br=function(){return this.options.xhtml?""+Q(u.message+"",!0)+"";throw u}}return ne.options=ne.setOptions=function(e){return X(ne.defaults,e),ee(ne.defaults),ne},ne.getDefaults=J,ne.defaults=te,ne.use=function(e){var t=X({},e);if(e.renderer&&function(){var n=ne.defaults.renderer||new U,r=function(t){var r=n[t];n[t]=function(){for(var o=arguments.length,i=new Array(o),a=0;a
'+(n?e:Y(e,!0))+"\n":""+(n?e:Y(e,!0))+"\n"},t.blockquote=function(e){return"\n"+e+"\n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"
"+e+"
\n"},t.table=function(e,t){return t&&(t=""+t+""),""+e+""},t.br=function(){return this.options.xhtml?""+Q(u.message+"",!0)+"";throw u}}return ne.options=ne.setOptions=function(e){return X(ne.defaults,e),ee(ne.defaults),ne},ne.getDefaults=J,ne.defaults=te,ne.use=function(e){var t=X({},e);if(e.renderer&&function(){var n=ne.defaults.renderer||new U,r=function(t){var r=n[t];n[t]=function(){for(var o=arguments.length,i=new Array(o),a=0;a