diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index c00e2688f1..e14c5d1624 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -111,6 +111,9 @@ The use of the : operator to override type safety checks is not allowed. You mus
### Type paths must begin with a /
eg: `/datum/thing`, not `datum/thing`
+### Type paths must be lowercase
+eg: `/datum/thing/blue`, not `datum/thing/BLUE` or `datum/thing/Blue`
+
### Datum type paths must began with "datum"
In DM, this is optional, but omitting it makes finding definitions harder.
@@ -240,6 +243,8 @@ This prevents nesting levels from getting deeper then they need to be.
* Queries must never specify the database, be it in code, or in text files in the repo.
+* Primary keys are inherently immutable and you must never do anything to change the primary key of a row or entity. This includes preserving auto increment numbers of rows when copying data to a table in a conversion script. No amount of bitching about gaps in ids or out of order ids will save you from this policy.
+
### Mapping Standards
* TGM Format & Map Merge
* All new maps submitted to the repo through a pull request must be in TGM format (unless there is a valid reason present to have it in the default BYOND format.) This is done using the [Map Merge](https://github.com/tgstation/tgstation/wiki/Map-Merger) utility included in the repo to convert the file to TGM format.
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 949f1c4c44..0000000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,9 +0,0 @@
-[Round ID]: # (If you discovered this issue from playing tgstation hosted servers:)
-[Round ID]: # (**INCLUDE THE ROUND ID**)
-[Round ID]: # (It can be found in the Status panel or retrieved from https://atlantaned.space/statbus/round.php ! The round id let's us look up valuable information and logs for the round the bug happened.)
-
-[Testmerges]: # (If you believe the issue to be caused by a test merge [OOC tab -> Show Server Revision], report it in the pull request's comment section instead.)
-
-[Reproduction]: # (Explain your issue in detail, including the steps to reproduce it. Issues without proper reproduction steps or explanation are open to being ignored/closed by maintainers.)
-
-[For Admins]: # (Oddities induced by var-edits and other admin tools are not necessarily bugs. Verify that your issues occur under regular circumstances before reporting them.)
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000..09f99f6c85
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,20 @@
+---
+name: Bug report
+about: Create a report to help reproduce and fix the issue
+---
+
+## Round ID:
+
+
+
+## Testmerges:
+
+
+
+## Reproduction:
+
+
+
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000..2c9eb90c72
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,7 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+Please be aware that feature discussions most often take place on the Citadel Station Discord and should not be requested here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 7855fd5782..f204eb0a72 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,6 +1,16 @@
-[Changelogs]: # (Your PR should contain a detailed changelog of notable changes, titled and categorized appropriately. This includes, new features, sprites, sounds, balance changes, admin tools, map edits, removals, big refactors, config changes, hosting changes and important fixes. An example changelog has been provided below for you to edit. If you need additional help, read https://github.com/tgstation/tgstation/wiki/Changelogs)
+
+
-:cl: optional name here
+## About The Pull Request
+
+
+
+## Why It's Good For The Game
+
+
+
+## Changelog
+:cl:
add: Added new things
add: Added more things
del: Removed old things
@@ -19,4 +29,5 @@ admin: messed with admin stuff
server: something server ops should know
/:cl:
-[why]: # (Please add a short description [two lines down] of why you think these changes would benefit the game. If you can't justify it in words, it might not be worth adding.)
+
+
diff --git a/.travis.yml b/.travis.yml
index 7138b23354..bef3a69ad7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
language: generic
sudo: false
+dist: xenial
branches:
except:
- ___TGS3TempBranch
@@ -14,6 +15,7 @@ matrix:
packages:
- python3
- python3-pip
+ - python3-setuptools
cache:
directories:
- tgui/node_modules
@@ -43,7 +45,8 @@ matrix:
- gcc-multilib
- g++-7
- g++-7-multilib
- - libmariadbclient-dev:i386
+ - libmariadb-client-lgpl-dev:i386
+ - libmariadbd-dev
cache:
directories:
- $HOME/.cargo
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm
index b3a0289761..738148c948 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm
@@ -209,6 +209,8 @@
dir = 8
},
/obj/item/malf_upgrade,
+/obj/item/disk/tech_disk/illegal,
+/obj/structure/safe,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/ash_walkers)
"aB" = (
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
index ba291fc258..945ea515c7 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
@@ -272,7 +272,13 @@
/obj/machinery/light,
/turf/open/floor/plasteel/freezer,
/area/ruin/powered/seedvault)
-
+"Z" = (
+/obj/item/disk/design_disk/plant_disk,
+/obj/machinery/autolathe/hacked{
+ desc = "This autolathe seems to have its safety light off."
+ },
+/turf/open/floor/plasteel/freezer,
+/area/ruin/powered/seedvault)
(1,1,1) = {"
a
a
@@ -375,7 +381,7 @@ h
h
u
R
-u
+Z
Q
a
a
diff --git a/_maps/RandomRuins/SpaceRuins/arcade.dmm b/_maps/RandomRuins/SpaceRuins/arcade.dmm
new file mode 100644
index 0000000000..771c33c55b
--- /dev/null
+++ b/_maps/RandomRuins/SpaceRuins/arcade.dmm
@@ -0,0 +1,711 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"a" = (
+/turf/template_noop,
+/area/template_noop)
+"b" = (
+/turf/open/floor/plating/asteroid,
+/area/ruin/powered)
+"c" = (
+/turf/closed/mineral/random/high_chance,
+/area/ruin/powered)
+"d" = (
+/turf/closed/wall/mineral/titanium/survival/pod,
+/area/ruin/powered)
+"e" = (
+/obj/machinery/computer/arcade,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"f" = (
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/machinery/vending/coffee,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"g" = (
+/obj/item/coin,
+/obj/item/toy/plush/random,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"h" = (
+/obj/effect/mob_spawn/human/corpse/assistant,
+/obj/effect/decal/cleanable/blood,
+/obj/item/toy/plush/random,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"i" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/item/toy/plush/random,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"j" = (
+/obj/machinery/light{
+ dir = 8
+ },
+/turf/open/floor/engine,
+/area/ruin/powered)
+"k" = (
+/obj/item/coin/gold,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"l" = (
+/turf/open/floor/engine,
+/area/ruin/powered)
+"m" = (
+/obj/item/coin/iron,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"n" = (
+/obj/item/toy/plush/random,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"o" = (
+/obj/item/kitchen/knife{
+ pixel_x = 5;
+ pixel_y = 11
+ },
+/obj/item/toy/plush/random,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"p" = (
+/turf/closed/wall/mineral/titanium/survival/nodiagonal,
+/area/ruin/powered)
+"q" = (
+/turf/open/floor/light/colour_cycle/dancefloor_b,
+/area/ruin/powered)
+"r" = (
+/turf/open/floor/light/colour_cycle/dancefloor_a,
+/area/ruin/powered)
+"s" = (
+/obj/machinery/door/airlock/external/glass,
+/obj/structure/fans/tiny,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"t" = (
+/obj/item/trash/chips,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"u" = (
+/obj/item/trash/cheesie,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"v" = (
+/obj/item/coin,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"w" = (
+/obj/item/coin/diamond,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"x" = (
+/obj/machinery/jukebox/disco/indestructible,
+/turf/open/floor/light/colour_cycle/dancefloor_b,
+/area/ruin/powered)
+"y" = (
+/obj/machinery/light,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"z" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/engine,
+/area/ruin/powered)
+"A" = (
+/obj/machinery/door/airlock/external/glass,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"B" = (
+/obj/machinery/vending/cola/random,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"C" = (
+/obj/machinery/vending/snack/random,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"D" = (
+/obj/item/trash/can,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"E" = (
+/obj/item/trash/sosjerky,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"F" = (
+/obj/structure/closet/crate/trashcart,
+/turf/open/floor/plating/asteroid,
+/area/ruin/powered)
+"G" = (
+/obj/structure/chair/sofa/right,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"H" = (
+/obj/structure/chair/sofa/left,
+/obj/item/bedsheet/ian,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"I" = (
+/obj/item/aiModule/toyAI,
+/turf/open/floor/engine,
+/area/ruin/powered)
+"J" = (
+/obj/item/twohanded/dualsaber/toy,
+/turf/open/floor/light/colour_cycle/dancefloor_b,
+/area/ruin/powered)
+"K" = (
+/obj/item/gun/energy/pumpaction/toy,
+/turf/open/floor/engine,
+/area/ruin/powered)
+
+(1,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(2,1,1) = {"
+a
+a
+a
+a
+b
+b
+b
+b
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(3,1,1) = {"
+a
+a
+a
+b
+b
+b
+b
+b
+b
+b
+b
+a
+a
+a
+b
+b
+b
+b
+a
+a
+"}
+(4,1,1) = {"
+a
+a
+a
+b
+b
+b
+b
+b
+b
+b
+b
+a
+a
+b
+b
+b
+b
+b
+b
+a
+"}
+(5,1,1) = {"
+a
+a
+a
+b
+b
+c
+c
+c
+c
+b
+b
+b
+b
+b
+b
+c
+c
+c
+b
+b
+"}
+(6,1,1) = {"
+a
+a
+a
+b
+c
+c
+c
+c
+c
+b
+b
+b
+b
+c
+c
+c
+c
+c
+c
+b
+"}
+(7,1,1) = {"
+a
+a
+a
+b
+c
+c
+d
+d
+d
+d
+d
+d
+d
+d
+d
+d
+c
+c
+c
+b
+"}
+(8,1,1) = {"
+a
+a
+a
+b
+c
+c
+d
+e
+j
+l
+l
+K
+j
+G
+B
+d
+c
+c
+b
+b
+"}
+(9,1,1) = {"
+a
+a
+a
+b
+c
+c
+d
+e
+k
+l
+v
+l
+l
+H
+C
+d
+c
+c
+b
+a
+"}
+(10,1,1) = {"
+a
+a
+b
+b
+c
+c
+d
+e
+l
+I
+l
+l
+l
+k
+B
+d
+c
+c
+b
+a
+"}
+(11,1,1) = {"
+a
+a
+b
+c
+c
+c
+d
+e
+l
+l
+w
+l
+y
+d
+d
+p
+c
+b
+b
+a
+"}
+(12,1,1) = {"
+a
+a
+b
+c
+c
+c
+d
+e
+m
+J
+r
+q
+l
+A
+l
+s
+b
+b
+b
+a
+"}
+(13,1,1) = {"
+a
+b
+b
+c
+c
+c
+d
+f
+l
+r
+x
+r
+l
+d
+d
+d
+b
+b
+b
+a
+"}
+(14,1,1) = {"
+a
+b
+b
+c
+c
+c
+d
+e
+l
+q
+r
+q
+D
+A
+l
+s
+b
+b
+b
+a
+"}
+(15,1,1) = {"
+a
+b
+b
+b
+c
+c
+d
+e
+t
+u
+l
+E
+y
+d
+d
+p
+b
+b
+b
+a
+"}
+(16,1,1) = {"
+a
+b
+b
+b
+c
+c
+d
+e
+g
+n
+t
+k
+l
+l
+B
+d
+c
+b
+b
+a
+"}
+(17,1,1) = {"
+a
+b
+b
+c
+c
+c
+d
+e
+h
+o
+D
+l
+D
+l
+C
+d
+c
+c
+b
+b
+"}
+(18,1,1) = {"
+a
+a
+b
+c
+c
+c
+d
+e
+i
+n
+E
+l
+z
+m
+B
+d
+c
+c
+c
+b
+"}
+(19,1,1) = {"
+a
+a
+b
+c
+c
+c
+d
+d
+d
+d
+d
+d
+d
+d
+d
+d
+c
+c
+c
+b
+"}
+(20,1,1) = {"
+a
+a
+b
+b
+c
+c
+c
+c
+c
+c
+b
+F
+b
+c
+c
+c
+c
+c
+c
+b
+"}
+(21,1,1) = {"
+a
+a
+a
+b
+c
+c
+c
+c
+c
+c
+b
+b
+b
+c
+c
+c
+c
+c
+b
+b
+"}
+(22,1,1) = {"
+a
+a
+a
+b
+b
+c
+c
+c
+c
+b
+b
+b
+b
+b
+b
+c
+c
+b
+b
+a
+"}
+(23,1,1) = {"
+a
+a
+a
+a
+b
+b
+b
+b
+b
+b
+a
+b
+b
+b
+b
+b
+b
+b
+a
+a
+"}
+(24,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+b
+b
+b
+b
+b
+a
+a
+a
+"}
+(25,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+b
+b
+a
+a
+a
+a
+"}
diff --git a/_maps/RandomRuins/SpaceRuins/augmentationfacility.dmm b/_maps/RandomRuins/SpaceRuins/augmentationfacility.dmm
new file mode 100644
index 0000000000..c64050ce3a
--- /dev/null
+++ b/_maps/RandomRuins/SpaceRuins/augmentationfacility.dmm
@@ -0,0 +1,731 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"a" = (
+/turf/template_noop,
+/area/template_noop)
+"b" = (
+/turf/open/floor/plating/asteroid,
+/area/ruin/powered)
+"c" = (
+/turf/closed/mineral/random/high_chance,
+/area/ruin/powered)
+"d" = (
+/turf/closed/wall/r_wall/rust,
+/area/ruin/powered)
+"e" = (
+/obj/machinery/mecha_part_fabricator,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"f" = (
+/turf/closed/wall/rust,
+/area/ruin/powered)
+"g" = (
+/obj/structure/table,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/stack/sheet/glass/fifty,
+/obj/item/stack/sheet/metal/fifty,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"h" = (
+/obj/machinery/mecha_part_fabricator,
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"i" = (
+/obj/structure/table,
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/dirt,
+/obj/item/stack/sheet/glass/fifty,
+/obj/item/stack/sheet/metal/fifty,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"j" = (
+/obj/structure/chair/sofa/right,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"k" = (
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"l" = (
+/obj/structure/chair/sofa/left,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"m" = (
+/obj/machinery/computer/rdconsole/production{
+ dir = 4
+ },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"n" = (
+/obj/effect/decal/cleanable/oil/streak,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"o" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"p" = (
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"q" = (
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/aug_manipulator,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"r" = (
+/obj/structure/table,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/organ/cyberimp/chest/reviver,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"s" = (
+/obj/structure/table,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/organ/cyberimp/arm/surgery,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"t" = (
+/obj/structure/table,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/storage/backpack/duffelbag/med/surgery,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"u" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"v" = (
+/obj/machinery/porta_turret/syndicate/energy{
+ mode = 1
+ },
+/turf/closed/wall/r_wall/rust,
+/area/ruin/powered)
+"w" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/computer/mech_bay_power_console{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"x" = (
+/obj/effect/decal/cleanable/oil,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"y" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer1,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"z" = (
+/obj/structure/table,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/storage/belt/utility/full,
+/obj/item/clothing/glasses/welding,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"A" = (
+/obj/structure/table,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/mmi/posibrain{
+ pixel_y = 9
+ },
+/obj/item/mmi,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"B" = (
+/obj/structure/table/optable,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"C" = (
+/obj/machinery/mech_bay_recharge_port,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"D" = (
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/mech_bay_recharge_floor,
+/area/ruin/powered)
+"E" = (
+/obj/machinery/computer/operating{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"F" = (
+/obj/structure/table,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/autosurgeon{
+ name = "rusted autosurgeon";
+ desc = "A device that automatically inserts an implant or organ into the user without the hassle of extensive surgery. It has a slot to insert an organ of implant. But this rusted version looks like it could only manage one implant....";
+ uses = 1
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"G" = (
+/obj/machinery/light,
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/airalarm{
+ dir = 1;
+ pixel_y = -22
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"H" = (
+/obj/effect/decal/cleanable/oil,
+/obj/machinery/light,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"I" = (
+/obj/machinery/door/airlock/external/glass,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"J" = (
+/obj/machinery/atmospherics/components/unary/outlet_injector/on/layer1{
+ dir = 4
+ },
+/turf/open/floor/plating/asteroid,
+/area/ruin/powered)
+"K" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{
+ dir = 4
+ },
+/turf/closed/mineral/random/high_chance,
+/area/ruin/powered)
+"L" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{
+ dir = 4
+ },
+/turf/closed/wall/r_wall/rust,
+/area/ruin/powered)
+"M" = (
+/obj/structure/mecha_wreckage/ripley,
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"N" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"O" = (
+/obj/machinery/turretid{
+ lethal = 1;
+ pixel_y = -25;
+ req_access = null
+ },
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
+ dir = 5
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"P" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/components/unary/vent_pump/on,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"Q" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"R" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"S" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{
+ dir = 9
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"T" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/components/unary/tank/air{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"U" = (
+/obj/machinery/door/airlock/external/glass,
+/obj/structure/fans/tiny,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+"V" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/structure/reagent_dispensers/fueltank,
+/turf/open/floor/plasteel,
+/area/ruin/powered)
+
+(1,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(2,1,1) = {"
+a
+a
+a
+a
+a
+a
+b
+b
+b
+b
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(3,1,1) = {"
+a
+a
+a
+a
+b
+b
+c
+c
+c
+c
+J
+b
+b
+a
+a
+a
+a
+a
+a
+a
+"}
+(4,1,1) = {"
+a
+a
+a
+b
+c
+c
+c
+c
+c
+c
+K
+c
+b
+b
+b
+a
+a
+a
+a
+a
+"}
+(5,1,1) = {"
+a
+a
+b
+c
+c
+d
+d
+d
+d
+d
+L
+d
+c
+c
+b
+a
+a
+a
+a
+a
+"}
+(6,1,1) = {"
+a
+a
+b
+c
+d
+d
+m
+q
+w
+C
+M
+d
+d
+c
+b
+a
+a
+a
+a
+a
+"}
+(7,1,1) = {"
+a
+b
+b
+c
+d
+e
+n
+o
+x
+D
+N
+f
+d
+v
+b
+a
+a
+a
+a
+a
+"}
+(8,1,1) = {"
+a
+b
+c
+c
+d
+g
+o
+o
+y
+Q
+S
+I
+k
+U
+b
+a
+a
+a
+a
+a
+"}
+(9,1,1) = {"
+a
+b
+c
+c
+d
+h
+p
+r
+z
+o
+G
+f
+f
+d
+b
+a
+a
+a
+a
+a
+"}
+(10,1,1) = {"
+a
+b
+c
+c
+d
+i
+p
+s
+A
+o
+H
+f
+f
+d
+b
+a
+a
+a
+a
+a
+"}
+(11,1,1) = {"
+a
+b
+c
+c
+d
+j
+p
+t
+F
+o
+p
+I
+k
+U
+b
+a
+a
+a
+a
+a
+"}
+(12,1,1) = {"
+a
+b
+c
+c
+d
+l
+p
+p
+P
+R
+O
+f
+d
+v
+b
+b
+a
+a
+a
+a
+"}
+(13,1,1) = {"
+a
+b
+b
+c
+d
+d
+V
+u
+B
+E
+T
+d
+d
+c
+c
+b
+a
+a
+a
+a
+"}
+(14,1,1) = {"
+a
+a
+b
+c
+c
+d
+d
+d
+d
+d
+d
+d
+c
+c
+c
+b
+a
+a
+a
+a
+"}
+(15,1,1) = {"
+a
+a
+a
+b
+c
+c
+c
+c
+c
+c
+c
+c
+c
+c
+b
+b
+a
+a
+a
+a
+"}
+(16,1,1) = {"
+a
+a
+a
+b
+b
+b
+b
+c
+c
+c
+c
+b
+b
+b
+b
+a
+a
+a
+a
+a
+"}
+(17,1,1) = {"
+a
+a
+a
+a
+a
+a
+b
+b
+b
+b
+b
+b
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(18,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(19,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(20,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
diff --git a/_maps/RandomRuins/SpaceRuins/bigape.dmm b/_maps/RandomRuins/SpaceRuins/bigape.dmm
new file mode 100644
index 0000000000..09e85e129d
--- /dev/null
+++ b/_maps/RandomRuins/SpaceRuins/bigape.dmm
@@ -0,0 +1,196 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"a" = (
+/turf/template_noop,
+/area/template_noop)
+"b" = (
+/obj/structure/lattice,
+/turf/template_noop,
+/area/template_noop)
+"c" = (
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"d" = (
+/obj/structure/fans/tiny/invisible,
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"e" = (
+/obj/item/reagent_containers/food/snacks/grown/banana,
+/obj/item/reagent_containers/food/snacks/grown/banana,
+/obj/item/reagent_containers/food/snacks/grown/banana,
+/obj/item/reagent_containers/food/snacks/grown/banana,
+/obj/item/reagent_containers/food/snacks/grown/banana,
+/obj/structure/fans/tiny/invisible,
+/obj/structure/closet/secure_closet/freezer,
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"f" = (
+/obj/structure/chair/sofa/left{
+ dir = 4
+ },
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"g" = (
+/obj/item/flashlight/lamp/bananalamp{
+ brightness_on = 10
+ },
+/obj/structure/table/wood,
+/obj/structure/fans/tiny/invisible,
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"h" = (
+/obj/structure/table/wood,
+/obj/machinery/computer/security/wooden_tv,
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"i" = (
+/obj/structure/chair/sofa/right{
+ dir = 4
+ },
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"j" = (
+/obj/structure/sink/puddle,
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"k" = (
+/obj/structure/chair/sofa{
+ dir = 4
+ },
+/mob/living/simple_animal/hostile/gorilla{
+ AIStatus = null;
+ desc = "There is no need to be upset.";
+ dir = 4;
+ name = "Familiar Gorilla"
+ },
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"l" = (
+/obj/effect/overlay/palmtree_r,
+/obj/structure/fans/tiny/invisible,
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+"m" = (
+/obj/item/grown/bananapeel,
+/turf/open/floor/plating/beach/sand,
+/area/ruin/powered)
+
+(1,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+b
+a
+"}
+(2,1,1) = {"
+a
+a
+b
+b
+b
+b
+b
+b
+a
+a
+"}
+(3,1,1) = {"
+a
+a
+b
+b
+g
+d
+d
+b
+b
+a
+"}
+(4,1,1) = {"
+a
+a
+b
+d
+f
+k
+i
+d
+d
+b
+"}
+(5,1,1) = {"
+a
+a
+b
+e
+c
+c
+m
+j
+d
+b
+"}
+(6,1,1) = {"
+a
+a
+b
+d
+c
+h
+c
+l
+d
+b
+"}
+(7,1,1) = {"
+a
+b
+b
+b
+d
+d
+d
+b
+b
+a
+"}
+(8,1,1) = {"
+a
+b
+a
+a
+b
+b
+b
+b
+b
+b
+"}
+(9,1,1) = {"
+a
+b
+a
+a
+a
+b
+a
+a
+a
+b
+"}
+(10,1,1) = {"
+a
+a
+a
+a
+a
+b
+a
+a
+a
+a
+"}
diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm
index ef36495c58..e820b06f61 100644
--- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm
+++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm
@@ -2183,9 +2183,7 @@
/obj/effect/turf_decal/tile/purple{
dir = 8
},
-/turf/open/floor/plasteel/white{
- icon_state = "whitepurple"
- },
+/turf/open/floor/plasteel/white,
/area/ruin/space/has_grav/ancientstation/rnd)
"fU" = (
/obj/effect/decal/cleanable/dirt,
diff --git a/_maps/RandomRuins/SpaceRuins/originalcontent.dmm b/_maps/RandomRuins/SpaceRuins/originalcontent.dmm
index 624aa03d7c..2945a06b25 100644
--- a/_maps/RandomRuins/SpaceRuins/originalcontent.dmm
+++ b/_maps/RandomRuins/SpaceRuins/originalcontent.dmm
@@ -742,6 +742,7 @@
/turf/open/indestructible/paper,
/area/ruin/powered)
"cc" = (
+/obj/item/book/granter/action/origami,
/mob/living/simple_animal/hostile/boss/paper_wizard,
/turf/open/indestructible/paper,
/area/ruin/powered)
@@ -912,6 +913,10 @@
},
/turf/open/indestructible/paper,
/area/ruin/powered)
+"Ns" = (
+/obj/item/paper/secretrecipe,
+/turf/open/indestructible/paper,
+/area/ruin/powered)
(1,1,1) = {"
aa
@@ -2246,7 +2251,7 @@ ap
az
af
al
-aA
+Ns
bW
ca
af
diff --git a/_maps/RandomRuins/SpaceRuins/spacehermit.dmm b/_maps/RandomRuins/SpaceRuins/spacehermit.dmm
new file mode 100644
index 0000000000..341dcf7b99
--- /dev/null
+++ b/_maps/RandomRuins/SpaceRuins/spacehermit.dmm
@@ -0,0 +1,2941 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"aa" = (
+/turf/template_noop,
+/area/template_noop)
+"ab" = (
+/turf/closed/mineral/random/low_chance,
+/area/ruin/unpowered)
+"ac" = (
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"ad" = (
+/obj/machinery/hydroponics/soil,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"ae" = (
+/turf/closed/wall/mineral/titanium,
+/area/ruin/powered)
+"af" = (
+/obj/effect/spawner/structure/window/shuttle,
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"ag" = (
+/obj/structure/shuttle/engine/propulsion/right{
+ dir = 4
+ },
+/turf/closed/wall/mineral/titanium,
+/area/ruin/powered)
+"ah" = (
+/obj/structure/table/wood,
+/obj/item/shovel,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"ai" = (
+/obj/structure/lattice,
+/turf/template_noop,
+/area/template_noop)
+"aj" = (
+/obj/machinery/computer/cryopod,
+/turf/closed/wall/mineral/titanium,
+/area/ruin/powered)
+"ak" = (
+/obj/structure/fluff/empty_cryostasis_sleeper,
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"al" = (
+/obj/machinery/status_display/shuttle,
+/turf/closed/wall/mineral/titanium,
+/area/ruin/powered)
+"am" = (
+/obj/item/circuitboard/computer/rdconsole,
+/obj/item/circuitboard/machine/protolathe/department/science,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"an" = (
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"ao" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 8
+ },
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"ap" = (
+/obj/machinery/light{
+ dir = 1
+ },
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"aq" = (
+/obj/machinery/computer{
+ desc = "A computer long since rendered non-functional due to lack of maintenance. Spitting out error messages.";
+ dir = 4;
+ name = "Broken Computer"
+ },
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"ar" = (
+/obj/machinery/door/airlock/titanium{
+ name = "Escape Pod Airlock"
+ },
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"as" = (
+/obj/machinery/light,
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"at" = (
+/obj/structure/shuttle/engine/propulsion/left{
+ dir = 4
+ },
+/turf/closed/wall/mineral/titanium,
+/area/ruin/powered)
+"au" = (
+/obj/item/seeds/tower,
+/obj/item/seeds/tower,
+/obj/item/seeds/tower,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"av" = (
+/obj/structure/table/wood,
+/obj/item/paper/crumpled{
+ info = "
So this is it, I guess.. Always thought I'd go out doing something stupid, but.. not like this.
Should anyone find this note, tell Jeremy Clarke he can kiss my ass. Launching the pod unprepared like that..
Well. Now that I'm keeling over here, I guess I should write how I came to be the last one standing here.
Four of us took this pod.. only three of us woke up though.. fourth pod is locked from the inside, we couldn't figure out how to get it open.
Me and the clown set up a farm s'we can survive at least a while.. though, he didn't seem to understand that man cannot live on banana alone.
Had a bunch of circuits on him for some reason when he eventually passed, whispered to me something about a chem dispenser.. I.. don't know what he meant by that. I was never good with machinary. Maybe he wanted space lube?
The assistant that we gave the space suit to go out and find help never came back.. I'm betting he found salvation and left us behind.. never can trust those grubby greytiders."
+ },
+/obj/item/pen,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aw" = (
+/obj/item/stack/sheet/mineral/wood,
+/obj/item/stack/sheet/mineral/wood,
+/obj/item/stack/sheet/mineral/wood,
+/obj/item/stack/sheet/mineral/wood,
+/obj/item/stack/sheet/mineral/wood,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"ax" = (
+/obj/item/twohanded/spear,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"ay" = (
+/obj/item/grown/log,
+/obj/item/grown/log,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"az" = (
+/obj/structure/table/wood,
+/obj/item/storage/bag/plants/portaseeder,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aA" = (
+/turf/open/floor/plating/asteroid/airless,
+/area/ruin/unpowered)
+"aB" = (
+/obj/item/seeds/banana,
+/obj/item/seeds/banana,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aC" = (
+/obj/effect/mob_spawn/human/clown/corpse,
+/obj/structure/fans/tiny/invisible,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aD" = (
+/obj/item/mining_scanner,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aE" = (
+/obj/machinery/status_display/shuttle,
+/turf/closed/wall/mineral/titanium,
+/area/ruin/unpowered)
+"aF" = (
+/obj/item/pickaxe/emergency,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aG" = (
+/obj/structure/sink/puddle,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aH" = (
+/obj/structure/table/wood,
+/obj/item/storage/firstaid/regular,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aI" = (
+/obj/effect/mob_spawn/human/corpse/assistant,
+/turf/template_noop,
+/area/template_noop)
+"aJ" = (
+/obj/structure/table/wood,
+/obj/item/storage/bag/ore,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aK" = (
+/obj/structure/reagent_dispensers/fueltank,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aL" = (
+/obj/structure/table/wood,
+/obj/item/storage/toolbox/mechanical,
+/obj/item/clothing/head/welding,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aM" = (
+/mob/living/simple_animal/hostile/carp,
+/turf/template_noop,
+/area/template_noop)
+"aN" = (
+/obj/structure/mineral_door/sandstone,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aO" = (
+/mob/living/simple_animal/hostile/carp,
+/turf/open/floor/plating/asteroid/airless,
+/area/ruin/unpowered)
+"aP" = (
+/obj/item/stack/ore/gold,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aQ" = (
+/obj/item/stack/ore/gold,
+/obj/item/stack/ore/gold,
+/obj/item/stack/ore/gold,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aR" = (
+/obj/item/stack/ore/iron,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aS" = (
+/turf/closed/wall/mineral/iron,
+/area/ruin/unpowered)
+"aT" = (
+/obj/item/stack/ore/iron,
+/obj/item/stack/ore/iron,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aU" = (
+/obj/item/flashlight/lamp,
+/obj/structure/table/wood,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"aV" = (
+/obj/item/clothing/suit/space/orange,
+/turf/template_noop,
+/area/template_noop)
+"aW" = (
+/obj/item/clothing/head/helmet/space/orange,
+/turf/template_noop,
+/area/template_noop)
+"aX" = (
+/mob/living/simple_animal/hostile/carp/megacarp,
+/turf/template_noop,
+/area/template_noop)
+"aY" = (
+/obj/effect/mob_spawn/human/hermit{
+ flavour_text = "You've been late to awaken from your cryo slumber. Blasted machine, you set it to 10 days not 10 weeks! Where have the others gone while we were out? Did they manage to survive? These thoughts are dispelled by yet another recollection of how you got here... ";
+ job_description = "Space Hermit"
+ },
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"aZ" = (
+/turf/closed/wall/mineral/titanium,
+/area/ruin/unpowered)
+"ba" = (
+/obj/effect/spawner/structure/window/shuttle,
+/turf/open/floor/mineral/titanium,
+/area/ruin/unpowered)
+"bb" = (
+/obj/structure/shuttle/engine/propulsion/left{
+ dir = 4
+ },
+/turf/closed/wall/mineral/titanium,
+/area/ruin/unpowered)
+"bc" = (
+/obj/item/circuitboard/machine/circuit_imprinter,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bd" = (
+/obj/item/grown/bananapeel,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"be" = (
+/obj/effect/mob_spawn/human/corpse/cargo_tech,
+/obj/structure/fans/tiny/invisible,
+/obj/effect/decal/cleanable/vomit,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bf" = (
+/obj/item/clothing/glasses/meson,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bg" = (
+/obj/item/stock_parts/matter_bin,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bh" = (
+/obj/item/circuitboard/machine/autolathe,
+/turf/open/floor/mineral/titanium,
+/area/ruin/powered)
+"bi" = (
+/obj/item/stock_parts/manipulator,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bj" = (
+/obj/item/holosign_creator/atmos,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bk" = (
+/obj/structure/holosign/barrier/atmos,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bl" = (
+/obj/machinery/power/floodlight,
+/obj/structure/cable{
+ icon_state = "0-2"
+ },
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bm" = (
+/obj/structure/cable{
+ icon_state = "1-4"
+ },
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bn" = (
+/obj/structure/cable{
+ icon_state = "2-8"
+ },
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bo" = (
+/obj/structure/cable{
+ icon_state = "1-2"
+ },
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bp" = (
+/obj/item/stack/ore/iron,
+/obj/item/stack/ore/iron,
+/obj/item/stack/ore/iron,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bq" = (
+/obj/structure/cable,
+/obj/machinery/power/port_gen/pacman{
+ active = 1;
+ anchored = 1;
+ sheets = 10
+ },
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"br" = (
+/obj/item/stack/ore/iron,
+/obj/item/stack/sheet/mineral/plasma,
+/obj/item/stack/sheet/mineral/plasma,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+"bs" = (
+/obj/item/flashlight/lamp/bananalamp,
+/turf/open/floor/plating/asteroid,
+/area/ruin/unpowered)
+
+(1,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ac
+aO
+aA
+aA
+aA
+aA
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+"}
+(2,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+aA
+aA
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aA
+aA
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+aa
+aa
+"}
+(3,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aA
+aa
+aa
+aa
+aa
+aW
+aa
+aM
+aa
+"}
+(4,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aV
+aI
+aX
+aa
+aa
+"}
+(5,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+aA
+aA
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+"}
+(6,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aM
+aa
+aa
+aa
+"}
+(7,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aM
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+"}
+(8,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ae
+af
+ae
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+"}
+(9,1,1) = {"
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+af
+aq
+af
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+"}
+(10,1,1) = {"
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ae
+ae
+ao
+ae
+ae
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+"}
+(11,1,1) = {"
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+af
+an
+an
+an
+af
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(12,1,1) = {"
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aA
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ae
+ae
+bh
+an
+an
+ae
+aZ
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(13,1,1) = {"
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aA
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+af
+aY
+ao
+ao
+ao
+ak
+ba
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(14,1,1) = {"
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aA
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+al
+aj
+ap
+an
+as
+aj
+aE
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(15,1,1) = {"
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+aA
+aa
+aa
+aa
+aA
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+af
+ak
+ao
+ao
+ao
+ak
+ba
+ac
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(16,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ah
+az
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aR
+ae
+ae
+an
+an
+an
+ae
+aZ
+ac
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aM
+"}
+(17,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ac
+ac
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aR
+ag
+ag
+af
+ar
+af
+at
+bb
+ac
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(18,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ad
+ac
+ac
+ac
+ac
+ab
+aH
+aJ
+aL
+ab
+ab
+aT
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+aR
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(19,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ad
+au
+ac
+aB
+am
+ac
+ac
+ac
+ac
+ab
+ab
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+bg
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(20,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ad
+aw
+bs
+aC
+ac
+ac
+ac
+ac
+ac
+ab
+ab
+ab
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(21,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ad
+ax
+ac
+aD
+aF
+ac
+ac
+ac
+ab
+ab
+ab
+aU
+bd
+ac
+ac
+bl
+bm
+ac
+ac
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(22,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ad
+ay
+ac
+ac
+ac
+aG
+ac
+ac
+ab
+ab
+ab
+av
+be
+ac
+ac
+ac
+bn
+bo
+bo
+bq
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+"}
+(23,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ab
+ab
+ab
+bc
+bf
+ac
+ac
+ac
+ac
+ac
+ac
+br
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+"}
+(24,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ac
+ab
+ac
+ac
+ac
+ac
+ac
+ab
+ab
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+"}
+(25,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ac
+ac
+ac
+ac
+ac
+aN
+ac
+ac
+ac
+ac
+aR
+ac
+ac
+ac
+ac
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+"}
+(26,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ac
+ac
+ac
+ab
+ab
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+"}
+(27,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aK
+ab
+ab
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+bp
+ac
+ac
+aR
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+aM
+"}
+(28,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aP
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+ac
+aR
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+"}
+(29,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aQ
+aP
+ac
+ac
+aR
+ac
+ac
+ac
+ac
+ab
+ac
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+"}
+(30,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ac
+ac
+ac
+ac
+aP
+ac
+bg
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+"}
+(31,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ac
+ac
+ac
+ac
+ac
+ac
+aS
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+ab
+aA
+"}
+(32,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+bg
+ac
+ac
+ac
+ac
+ac
+aS
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aO
+ab
+ab
+"}
+(33,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ac
+ac
+bj
+ac
+ac
+ac
+aS
+ab
+ab
+ab
+ab
+aA
+aa
+aA
+ab
+ab
+ab
+"}
+(34,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aS
+bi
+ac
+ac
+ac
+aS
+aS
+ab
+ab
+ab
+ab
+aA
+aa
+aA
+ab
+ab
+aA
+"}
+(35,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+aa
+aa
+aa
+aa
+aM
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aS
+ac
+ac
+ac
+ac
+aS
+aS
+ab
+ab
+ab
+aA
+aa
+aa
+aA
+ab
+ab
+ab
+"}
+(36,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aS
+aS
+aS
+bk
+bk
+aS
+aS
+aS
+aS
+ab
+ab
+aA
+aa
+aa
+aa
+ab
+ab
+ab
+"}
+(37,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aA
+aA
+aS
+aS
+aS
+bk
+aS
+aS
+aS
+aA
+aA
+ab
+aA
+aa
+aa
+aa
+aa
+aA
+aA
+"}
+(38,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aA
+ai
+ai
+ai
+ai
+ai
+ai
+ai
+ai
+aA
+aA
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+"}
+(39,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+ai
+ai
+ai
+aa
+ai
+aa
+aa
+aA
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+"}
+(40,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+ai
+aa
+aa
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+"}
+(41,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+"}
+(42,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+aA
+aA
+aA
+aA
+aA
+aA
+aA
+ab
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+"}
+(43,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+aA
+aA
+aA
+ab
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+"}
+(44,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ac
+aa
+aa
+aa
+"}
+(45,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+aa
+ac
+ab
+ac
+aa
+aa
+"}
+(46,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aM
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+aa
+aa
+"}
+(47,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+ab
+ab
+aa
+aa
+"}
+(48,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+ab
+ab
+ab
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+ab
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ac
+ab
+ac
+aa
+aa
+"}
+(49,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aA
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aA
+aa
+aa
+aa
+aa
+aM
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ac
+aa
+aa
+aa
+aa
+"}
+(50,1,1) = {"
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+aa
+ab
+aa
+aa
+aa
+aa
+"}
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index f9792a736e..0dc0afcd0c 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -35713,13 +35713,13 @@
/obj/structure/extinguisher_cabinet{
pixel_x = -26
},
-/obj/machinery/rnd/production/protolathe/department/medical,
/obj/effect/turf_decal/tile/blue{
dir = 1
},
/obj/effect/turf_decal/tile/blue{
dir = 4
},
+/obj/machinery/rnd/production/techfab/department/medical,
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
"bEw" = (
diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm
index b5ba44d956..928837979c 100644
--- a/code/__DEFINES/atmospherics.dm
+++ b/code/__DEFINES/atmospherics.dm
@@ -1,8 +1,5 @@
//LISTMOS
//indices of values in gas lists.
-#define MOLES 1
-#define ARCHIVE 2
-#define GAS_META 3
#define META_GAS_SPECIFIC_HEAT 1
#define META_GAS_NAME 2
#define META_GAS_MOLES_VISIBLE 3
@@ -242,20 +239,25 @@
//HELPERS
#define THERMAL_ENERGY(gas) (gas.temperature * gas.heat_capacity())
-
-#define ADD_GAS(gas_id, out_list)\
- var/list/tmp_gaslist = GLOB.gaslist_cache[gas_id]; out_list[gas_id] = tmp_gaslist.Copy();
-
-#define ASSERT_GAS(gas_id, gas_mixture) if (!gas_mixture.gases[gas_id]) { ADD_GAS(gas_id, gas_mixture.gases) };
-
+#define QUANTIZE(variable) (round(variable,0.0000001))/*I feel the need to document what happens here. Basically this is used to catch most rounding errors, however it's previous value made it so that
+ once gases got hot enough, most procedures wouldnt occur due to the fact that the mole counts would get rounded away. Thus, we lowered it a few orders of magnititude */
//prefer this to gas_mixture/total_moles in performance critical areas
#define TOTAL_MOLES(cached_gases, out_var)\
out_var = 0;\
for(var/total_moles_id in cached_gases){\
- out_var += cached_gases[total_moles_id][MOLES];\
+ out_var += cached_gases[total_moles_id];\
}
+//Unomos - So for whatever reason, garbage collection actually drastically decreases the cost of atmos later in the round. Turning this into a define yields massively improved performance.
+#define GAS_GARBAGE_COLLECT(GASGASGAS)\
+ var/list/CACHE_GAS = GASGASGAS;\
+ for(var/id in CACHE_GAS){\
+ if(QUANTIZE(CACHE_GAS[id]) <= 0)\
+ CACHE_GAS -= id;\
+ }
+
+#define ARCHIVE_TEMPERATURE(gas) gas.temperature_archived = gas.temperature
GLOBAL_LIST_INIT(pipe_paint_colors, list(
"amethyst" = rgb(130,43,255), //supplymain
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index dbe8cfbb62..210bdf57a6 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -130,6 +130,7 @@
#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged" //from base of mob/RangedAttack(): (atom/A, params)
#define COMSIG_MOB_THROW "mob_throw" //from base of /mob/throw_item(): (atom/target)
+#define COMSIG_MOB_UPDATE_SIGHT "mob_update_sight" //from base of /mob/update_sight(): ()
// /mob/living signals
#define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living)
diff --git a/code/__DEFINES/construction.dm b/code/__DEFINES/construction.dm
index 9f3d38efa1..ee51fb6909 100644
--- a/code/__DEFINES/construction.dm
+++ b/code/__DEFINES/construction.dm
@@ -102,7 +102,8 @@
#define CAT_SANDWICH "Sandwiches"
#define CAT_SOUP "Soups"
#define CAT_SPAGHETTI "Spaghettis"
-#define CAT_SUSHI "Fish"
+#define CAT_FISH "Fish"
+#define CAT_ICE "Frozen"
#define RCD_FLOORWALL 1
#define RCD_AIRLOCK 2
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index ad9aef5a8b..60148e0388 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -56,9 +56,6 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define FLYING (1<<1)
#define VENTCRAWLING (1<<2)
-// Flags for reagents
-#define REAGENT_NOREACT (1<<0)
-
//Fire and Acid stuff, for resistance_flags
#define LAVA_PROOF (1<<0)
#define FIRE_PROOF (1<<1) //100% immune to fire damage (but not necessarily to lava or heat)
diff --git a/code/__DEFINES/food.dm b/code/__DEFINES/food.dm
index 2c7a66ce40..15c7af5749 100644
--- a/code/__DEFINES/food.dm
+++ b/code/__DEFINES/food.dm
@@ -16,3 +16,4 @@
#define DRINK_GOOD 2
#define DRINK_VERYGOOD 3
#define DRINK_FANTASTIC 4
+#define FOOD_AMAZING 5
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index ce7f48762a..28e4e8f5ea 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -114,8 +114,9 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
#define TRANSITIONEDGE 7 //Distance from edge to move to another z-level
-#define BE_CLOSE 1 //in the case of a silicon, to select if they need to be next to the atom
-#define NO_DEXTERY 1 //if other mobs (monkeys, aliens, etc) can use this
+#define BE_CLOSE TRUE //in the case of a silicon, to select if they need to be next to the atom
+#define NO_DEXTERY TRUE //if other mobs (monkeys, aliens, etc) can use this
+#define NO_TK TRUE
//used by canUseTopic()
//singularity defines
@@ -218,6 +219,9 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
//Gets the turf this atom inhabits
#define get_turf(A) (get_step(A, 0))
+//Same as above except gets the area instead
+#define get_area(A) (isarea(A) ? A : get_step(A, 0)?.loc)
+
//Ghost orbit types:
#define GHOST_ORBIT_CIRCLE "circle"
#define GHOST_ORBIT_TRIANGLE "triangle"
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 4b42595b48..1d1dda6d99 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -54,6 +54,10 @@
#define BODYPART_ORGANIC 1
#define BODYPART_ROBOTIC 2
+#define BODYPART_NOT_DISABLED 0
+#define BODYPART_DISABLED_DAMAGE 1
+#define BODYPART_DISABLED_PARALYSIS 2
+
#define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi'
#define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi'
diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm
index f8f59a367f..c3682d905d 100644
--- a/code/__DEFINES/reagents.dm
+++ b/code/__DEFINES/reagents.dm
@@ -2,7 +2,7 @@
#define LIQUID 2
#define GAS 3
-// container_type defines
+// reagents_flags defines
#define INJECTABLE (1<<0) // Makes it possible to add reagents through droppers and syringes.
#define DRAWABLE (1<<1) // Makes it possible to remove reagents through syringes.
@@ -11,6 +11,7 @@
#define TRANSPARENT (1<<4) // Used on containers which you want to be able to see the reagents off.
#define AMOUNT_VISIBLE (1<<5) // For non-transparent containers that still have the general amount of reagents in them visible.
+#define NO_REACT (1<<6) // Applied to a reagent holder, the contents will not react with each other.
// Is an open container for all intents and purposes.
#define OPENCONTAINER (REFILLABLE | DRAINABLE | TRANSPARENT)
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index f54a0542f4..ecd1ef1e21 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -102,7 +102,6 @@
#define FIRE_PRIORITY_SPACEDRIFT 30
#define FIRE_PRIORITY_FIELDS 30
#define FIRE_PRIOTITY_SMOOTHING 35
-#define FIRE_PRIORITY_ORBIT 35
#define FIRE_PRIORITY_NETWORKS 40
#define FIRE_PRIORITY_OBJ 40
#define FIRE_PRIORITY_ACID 40
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 5c2deae875..b42cbb8f00 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -1,3 +1,61 @@
+// trait accessor defines
+#define ADD_TRAIT(target, trait, source) \
+ do { \
+ var/list/_L; \
+ if (!target.status_traits) { \
+ target.status_traits = list(); \
+ _L = target.status_traits; \
+ _L[trait] = list(source); \
+ } else { \
+ _L = target.status_traits; \
+ if (_L[trait]) { \
+ _L[trait] |= list(source); \
+ } else { \
+ _L[trait] = list(source); \
+ } \
+ } \
+ } while (0)
+#define REMOVE_TRAIT(target, trait, sources) \
+ do { \
+ var/list/_L = target.status_traits; \
+ var/list/_S; \
+ if (sources && !islist(sources)) { \
+ _S = list(sources); \
+ } else { \
+ _S = sources\
+ }; \
+ if (_L && _L[trait]) { \
+ for (var/_T in _L[trait]) { \
+ if ((!_S && (_T != ROUNDSTART_TRAIT)) || (_T in _S)) { \
+ _L[trait] -= _T \
+ } \
+ };\
+ if (!length(_L[trait])) { \
+ _L -= trait \
+ }; \
+ if (!length(_L)) { \
+ target.status_traits = null \
+ }; \
+ } \
+ } while (0)
+#define REMOVE_TRAITS_NOT_IN(target, sources) \
+ do { \
+ var/list/_L = target.status_traits; \
+ var/list/_S = sources; \
+ if (_L) { \
+ for (var/_T in _L) { \
+ _L[_T] &= _S;\
+ if (!length(_L[_T])) { \
+ _L -= _T } \
+ };\
+ if (!length(_L)) { \
+ target.status_traits = null\
+ };\
+ }\
+ } while (0)
+#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
+#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
+
//mob traits
#define TRAIT_BLIND "blind"
#define TRAIT_MUTE "mute"
@@ -50,7 +108,13 @@
#define TRAIT_NOHARDCRIT "nohardcrit"
#define TRAIT_NOSOFTCRIT "nosoftcrit"
#define TRAIT_MINDSHIELD "mindshield"
+#define TRAIT_PARALYSIS_L_ARM "para-l-arm" //These are used for brain-based paralysis, where replacing the limb won't fix it
+#define TRAIT_PARALYSIS_R_ARM "para-r-arm"
+#define TRAIT_PARALYSIS_L_LEG "para-l-leg"
+#define TRAIT_PARALYSIS_R_LEG "para-r-leg"
+ //non-mob traits
+#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
#define TRAIT_AGEUSIA "ageusia"
@@ -72,7 +136,11 @@
#define TRAIT_CROCRIN_IMMUNE "crocin_immune"
#define TRAIT_NYMPHO "nymphomania"
#define TRAIT_MASO "masochism"
+#define TRAIT_PARA "paraplegic"
+#define TRAIT_EMPATH "empath"
+#define TRAIT_FRIENDLY "friendly"
#define TRAIT_ASSBLASTUSA "assblastusa"
+#define TRAIT_CULT_EYES "cult_eyes"
// common trait sources
#define TRAIT_GENERIC "generic"
@@ -95,4 +163,3 @@
#define STASIS_MUTE "stasis"
#define GENETICS_SPELL "genetics_spell"
#define EYES_COVERED "eyes_covered"
-#define CULT_EYES "cult_eyes"
diff --git a/code/__HELPERS/areas.dm b/code/__HELPERS/areas.dm
index f05bf6f3e1..1f5b82f7bf 100644
--- a/code/__HELPERS/areas.dm
+++ b/code/__HELPERS/areas.dm
@@ -86,6 +86,8 @@
newA.contents += thing
thing.change_area(old_area, newA)
+ newA.reg_in_areas_in_z()
+
var/list/firedoors = oldA.firedoors
for(var/door in firedoors)
var/obj/machinery/door/firedoor/FD = door
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 899ef16306..c741a08108 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -8,12 +8,6 @@
#define Z_TURFS(ZLEVEL) block(locate(1,1,ZLEVEL), locate(world.maxx, world.maxy, ZLEVEL))
#define CULT_POLL_WAIT 2400
-/proc/get_area(atom/A)
- if(isarea(A))
- return A
- var/turf/T = get_turf(A)
- return T ? T.loc : null
-
/proc/get_area_name(atom/X, format_text = FALSE)
var/area/A = isarea(X) ? X : get_area(X)
if(!A)
diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm
index 8b77b170e0..d96ec76a7c 100644
--- a/code/__HELPERS/matrices.dm
+++ b/code/__HELPERS/matrices.dm
@@ -2,7 +2,7 @@
. = new_angle - old_angle
Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT
-/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3)
+/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3, parallel = TRUE)
if(!segments)
return
var/segment = 360/segments
@@ -18,7 +18,11 @@
speed /= segments
- animate(src, transform = matrices[1], time = speed, loops)
+ if(parallel)
+ animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
+ else
+ animate(src, transform = matrices[1], time = speed, loops)
+
for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
diff --git a/code/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm
new file mode 100644
index 0000000000..f1208abdd3
--- /dev/null
+++ b/code/__HELPERS/reagents.dm
@@ -0,0 +1,74 @@
+/proc/chem_recipes_do_conflict(datum/chemical_reaction/r1, datum/chemical_reaction/r2)
+ //do the non-list tests first, because they are cheaper
+ if(r1.required_container != r2.required_container)
+ return FALSE
+ if(r1.is_cold_recipe == r2.is_cold_recipe)
+ if(r1.required_temp != r2.required_temp)
+ //one reaction requires a more extreme temperature than the other, so there is no conflict
+ return FALSE
+ else
+ var/datum/chemical_reaction/cold_one = r1.is_cold_recipe ? r1 : r2
+ var/datum/chemical_reaction/warm_one = r1.is_cold_recipe ? r2 : r1
+ if(cold_one.required_temp < warm_one.required_temp)
+ //the range of temperatures does not overlap, so there is no conflict
+ return FALSE
+
+ //find the reactions with the shorter and longer required_reagents list
+ var/datum/chemical_reaction/long_req
+ var/datum/chemical_reaction/short_req
+ if(r1.required_reagents.len > r2.required_reagents.len)
+ long_req = r1
+ short_req = r2
+ else if(r1.required_reagents.len < r2.required_reagents.len)
+ long_req = r2
+ short_req = r1
+ else
+ //if they are the same length, sort instead by the length of the catalyst list
+ //this is important if the required_reagents lists are the same
+ if(r1.required_catalysts.len > r2.required_catalysts.len)
+ long_req = r1
+ short_req = r2
+ else
+ long_req = r2
+ short_req = r1
+
+
+ //check if the shorter reaction list is a subset of the longer one
+ var/list/overlap = r1.required_reagents & r2.required_reagents
+ if(overlap.len != short_req.required_reagents.len)
+ //there is at least one reagent in the short list that is not in the long list, so there is no conflict
+ return FALSE
+
+ //check to see if the shorter reaction's catalyst list is also a subset of the longer reaction's catalyst list
+ //if the longer reaction's catalyst list is a subset of the shorter ones, that is fine
+ //if the reaction lists are the same, the short reaction will have the shorter required_catalysts list, so it will register as a conflict
+ var/list/short_minus_long_catalysts = short_req.required_catalysts - long_req.required_catalysts
+ if(short_minus_long_catalysts.len)
+ //there is at least one unique catalyst for the short reaction, so there is no conflict
+ return FALSE
+
+ //if we got this far, the longer reaction will be impossible to create if the shorter one is earlier in GLOB.chemical_reactions_list, and will require the reagents to be added in a particular order otherwise
+ return TRUE
+
+/proc/get_chemical_reaction(id)
+ if(!GLOB.chemical_reactions_list)
+ return
+ for(var/reagent in GLOB.chemical_reactions_list)
+ for(var/datum/chemical_reaction/R in GLOB.chemical_reactions_list[reagent])
+ if(R.id == id)
+ return R
+
+/proc/remove_chemical_reaction(datum/chemical_reaction/R)
+ if(!GLOB.chemical_reactions_list || !R)
+ return
+ for(var/rid in R.required_reagents)
+ GLOB.chemical_reactions_list[rid] -= R
+
+//see build_chemical_reactions_list in holder.dm for explanations
+/proc/add_chemical_reaction(datum/chemical_reaction/R)
+ if(!GLOB.chemical_reactions_list || !R.id || !R.required_reagents || !R.required_reagents.len)
+ return
+ var/primary_reagent = R.required_reagents[1]
+ if(!GLOB.chemical_reactions_list[primary_reagent])
+ GLOB.chemical_reactions_list[primary_reagent] = list()
+ GLOB.chemical_reactions_list[primary_reagent] += R
diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm
index 200e1f907f..b28e7b5807 100644
--- a/code/__HELPERS/time.dm
+++ b/code/__HELPERS/time.dm
@@ -70,3 +70,6 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
if(hour)
hourT = " and [hour] hour[(hour != 1)? "s":""]"
return "[day] day[(day != 1)? "s":""][hourT][minuteT][secondT]"
+
+/proc/daysSince(realtimev)
+ return round((world.realtime - realtimev) / (24 HOURS))
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 835a733752..c37e6fa531 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -115,9 +115,6 @@ GLOBAL_LIST_INIT(bitfields, list(
"GOLIATH_RESISTANCE" = GOLIATH_RESISTANCE,
"GOLIATH_WEAKNESS" = GOLIATH_WEAKNESS
),
- "reagents_holder_flags" = list(
- "REAGENT_NOREACT" = REAGENT_NOREACT
- ),
"flags_1" = list(
"NOJAUNT_1" = NOJAUNT_1,
"UNUSED_RESERVATION_TURF_1" = UNUSED_RESERVATION_TURF_1,
@@ -158,13 +155,14 @@ GLOBAL_LIST_INIT(bitfields, list(
"SMOOTH_BORDER" = SMOOTH_BORDER,
"SMOOTH_QUEUED" = SMOOTH_QUEUED,
),
- "container_type" = list(
+ "reagents_holder_flags" = list(
"INJECTABLE" = INJECTABLE,
"DRAWABLE" = DRAWABLE,
"REFILLABLE" = REFILLABLE,
"DRAINABLE" = DRAINABLE,
"TRANSPARENT" = TRANSPARENT,
"AMOUNT_VISIBLE" = AMOUNT_VISIBLE,
+ "NO_REACT" = NO_REACT,
),
"car_traits" = list(
"CAN_KIDNAP" = CAN_KIDNAP,
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index 8b0ac278cd..47b7e2ab62 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -40,6 +40,54 @@ GLOBAL_LIST_EMPTY(caps_list)
GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites
GLOBAL_LIST_INIT(ghost_forms_with_accessories_list, list("ghost")) //stores the ghost forms that support hair and other such things
+GLOBAL_LIST_INIT(ai_core_display_screens, list(
+ ":thinking:",
+ "Alien",
+ "Angel",
+ "Banned",
+ "Bliss",
+ "Blue",
+ "Clown",
+ "Database",
+ "Dorf",
+ "Firewall",
+ "Fuzzy",
+ "Gentoo",
+ "Glitchman",
+ "Gondola",
+ "Goon",
+ "Hades",
+ "Heartline",
+ "Helios",
+ "House",
+ "Inverted",
+ "Matrix",
+ "Monochrome",
+ "Murica",
+ "Nanotrasen",
+ "Not Malf",
+ "President",
+ "Random",
+ "Rainbow",
+ "Red",
+ "Red October",
+ "Static",
+ "Syndicat Meow",
+ "TechDemon",
+ "Text",
+ "Too Deep",
+ "Triumvirate",
+ "Triumvirate-M",
+ "Weird"))
+
+/proc/resolve_ai_icon(input)
+ if(!input || !(input in GLOB.ai_core_display_screens))
+ return "ai"
+ else
+ if(input == "Random")
+ input = pick(GLOB.ai_core_display_screens - "Random")
+ return "ai-[lowertext(input)]"
+
GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
//Backpacks
@@ -117,7 +165,7 @@ GLOBAL_LIST_INIT(TAGGERLOCATIONS, list("Disposals",
"CMO Office", "Chemistry", "Research", "RD Office",
"Robotics", "HoP Office", "Library", "Chapel", "Theatre",
"Bar", "Kitchen", "Hydroponics", "Janitor Closet","Genetics",
- "Circuitry", "Toxins", "Dormitories", "Virology",
+ "Circuitry", "Toxins", "Dormitories", "Virology",
"Xenobiology", "Law Office","Detective's Office"))
GLOBAL_LIST_INIT(station_prefixes, world.file2list("strings/station_prefixes.txt") + "")
diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm
index 36049de77b..efd405a4dc 100644
--- a/code/_globalvars/lists/maintenance_loot.dm
+++ b/code/_globalvars/lists/maintenance_loot.dm
@@ -109,5 +109,8 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/item/reagent_containers/pill/floorpill = 1,
/obj/item/storage/daki = 3, //VERY IMPORTANT CIT CHANGE - adds bodypillows to maint
/obj/item/storage/pill_bottle/penis_enlargement = 2,
+ /obj/item/clothing/shoes/wheelys = 1,
+ /obj/item/clothing/shoes/kindleKicks = 1,
+ /obj/item/autosurgeon/penis = 1,
"" = 3
))
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index 03b951e6bb..df91223ed1 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -1,4 +1,7 @@
#define NEXT_PAGE_ID "__next__"
+#define DEFAULT_CHECK_DELAY 20
+
+GLOBAL_LIST_EMPTY(radial_menus)
/obj/screen/radial
icon = 'icons/mob/radial.dmi'
@@ -10,14 +13,19 @@
icon_state = "radial_slice"
var/choice
var/next_page = FALSE
+ var/tooltips = FALSE
/obj/screen/radial/slice/MouseEntered(location, control, params)
. = ..()
icon_state = "radial_slice_focus"
+ if(tooltips)
+ openToolTip(usr, src, params, title = name)
/obj/screen/radial/slice/MouseExited(location, control, params)
. = ..()
icon_state = "radial_slice"
+ if(tooltips)
+ closeToolTip(usr)
/obj/screen/radial/slice/Click(location, control, params)
if(usr.client == parent.current_user)
@@ -30,6 +38,14 @@
name = "Close Menu"
icon_state = "radial_center"
+/obj/screen/radial/center/MouseEntered(location, control, params)
+ . = ..()
+ icon_state = "radial_center_focus"
+
+/obj/screen/radial/center/MouseExited(location, control, params)
+ . = ..()
+ icon_state = "radial_center"
+
/obj/screen/radial/center/Click(location, control, params)
if(usr.client == parent.current_user)
parent.finished = TRUE
@@ -48,6 +64,9 @@
var/atom/anchor
var/image/menu_holder
var/finished = FALSE
+ var/datum/callback/custom_check_callback
+ var/next_check = 0
+ var/check_delay = DEFAULT_CHECK_DELAY
var/radius = 32
var/starting_angle = 0
@@ -57,7 +76,7 @@
var/max_elements
var/pages = 1
var/current_page = 1
-
+
var/hudfix_method = TRUE //TRUE to change anchor to user, FALSE to shift by py_shift
var/py_shift = 0
var/entry_animation = TRUE
@@ -75,7 +94,7 @@
restrict_to_dir(NORTH) //I was going to parse screen loc here but that's more effort than it's worth.
//Sets defaults
-//These assume 45 deg min_angle
+//These assume 45 deg min_angle
/datum/radial_menu/proc/restrict_to_dir(dir)
switch(dir)
if(NORTH)
@@ -91,18 +110,19 @@
starting_angle = 180
ending_angle = 45
-/datum/radial_menu/proc/setup_menu()
+/datum/radial_menu/proc/setup_menu(use_tooltips)
if(ending_angle > starting_angle)
zone = ending_angle - starting_angle
else
zone = 360 - starting_angle + ending_angle
-
+
max_elements = round(zone / min_angle)
var/paged = max_elements < choices.len
if(elements.len < max_elements)
var/elements_to_add = max_elements - elements.len
for(var/i in 1 to elements_to_add) //Create all elements
- var/obj/screen/radial/new_element = new /obj/screen/radial/slice
+ var/obj/screen/radial/slice/new_element = new /obj/screen/radial/slice
+ new_element.tooltips = use_tooltips
new_element.parent = src
elements += new_element
@@ -163,7 +183,7 @@
else
E.pixel_y = py
E.pixel_x = px
-
+
//Visuals
E.alpha = 255
E.mouse_opacity = MOUSE_OPACITY_ICON
@@ -183,7 +203,7 @@
E.next_page = FALSE
if(choices_icons[choice_id])
E.add_overlay(choices_icons[choice_id])
-
+
/datum/radial_menu/New()
close_button = new
close_button.parent = src
@@ -200,7 +220,7 @@
/datum/radial_menu/proc/get_next_id()
return "c_[choices.len]"
-/datum/radial_menu/proc/set_choices(list/new_choices)
+/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips)
if(choices.len)
Reset()
for(var/E in new_choices)
@@ -211,7 +231,7 @@
var/I = extract_image(new_choices[E])
if(I)
choices_icons[id] = I
- setup_menu()
+ setup_menu(use_tooltips)
/datum/radial_menu/proc/extract_image(E)
@@ -220,7 +240,7 @@
MA.layer = ABOVE_HUD_LAYER
MA.appearance_flags |= RESET_TRANSFORM
return MA
-
+
/datum/radial_menu/proc/next_page()
if(pages > 1)
@@ -243,28 +263,49 @@
if(current_user)
current_user.images -= menu_holder
-/datum/radial_menu/proc/wait()
+/datum/radial_menu/proc/wait(atom/user, atom/anchor, require_near = FALSE)
while (current_user && !finished && !selected_choice)
+ if(require_near && !in_range(anchor, user))
+ return
+ if(custom_check_callback && next_check < world.time)
+ if(!custom_check_callback.Invoke())
+ return
+ else
+ next_check = world.time + check_delay
stoplag(1)
/datum/radial_menu/Destroy()
Reset()
hide()
+ QDEL_NULL(custom_check_callback)
. = ..()
+
/*
- Presents radial menu to user anchored to anchor (or user if the anchor is currently in users screen)
+ Presents radial menu to user anchored to anchor (or user if the anchor is currently in users screen)
Choices should be a list where list keys are movables or text used for element names and return value
and list values are movables/icons/images used for element icons
*/
-/proc/show_radial_menu(mob/user,atom/anchor,list/choices)
+/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE)
+ if(!user || !anchor || !length(choices))
+ return
+ if(!uniqueid)
+ uniqueid = "defmenu_[REF(user)]_[REF(anchor)]"
+
+ if(GLOB.radial_menus[uniqueid])
+ return
+
var/datum/radial_menu/menu = new
- if(!user)
- user = usr
+ GLOB.radial_menus[uniqueid] = menu
+ if(radius)
+ menu.radius = radius
+ if(istype(custom_check))
+ menu.custom_check_callback = custom_check
menu.anchor = anchor
menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud
- menu.set_choices(choices)
+ menu.set_choices(choices, tooltips)
menu.show_to(user)
- menu.wait()
+ menu.wait(user, anchor, require_near)
var/answer = menu.selected_choice
qdel(menu)
+ GLOB.radial_menus -= uniqueid
return answer
\ No newline at end of file
diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm
new file mode 100644
index 0000000000..0b5e8dc356
--- /dev/null
+++ b/code/_onclick/hud/radial_persistent.dm
@@ -0,0 +1,76 @@
+/*
+ A derivative of radial menu which persists onscreen until closed and invokes a callback each time an element is clicked
+*/
+
+/obj/screen/radial/persistent/center
+ name = "Close Menu"
+ icon_state = "radial_center"
+
+/obj/screen/radial/persistent/center/Click(location, control, params)
+ if(usr.client == parent.current_user)
+ parent.element_chosen(null,usr)
+
+/obj/screen/radial/persistent/center/MouseEntered(location, control, params)
+ . = ..()
+ icon_state = "radial_center_focus"
+
+/obj/screen/radial/persistent/center/MouseExited(location, control, params)
+ . = ..()
+ icon_state = "radial_center"
+
+
+
+/datum/radial_menu/persistent
+ var/uniqueid
+ var/datum/callback/select_proc_callback
+
+/datum/radial_menu/persistent/New()
+ close_button = new /obj/screen/radial/persistent/center
+ close_button.parent = src
+
+
+/datum/radial_menu/persistent/element_chosen(choice_id,mob/user)
+ select_proc_callback.Invoke(choices_values[choice_id])
+
+
+/datum/radial_menu/persistent/proc/change_choices(list/newchoices, tooltips)
+ if(!newchoices.len)
+ return
+ Reset()
+ set_choices(newchoices,tooltips)
+
+/datum/radial_menu/persistent/Destroy()
+ QDEL_NULL(select_proc_callback)
+ GLOB.radial_menus -= uniqueid
+ Reset()
+ hide()
+ . = ..()
+
+/*
+ Creates a persistent radial menu and shows it to the user, anchored to anchor (or user if the anchor is currently in users screen).
+ Choices should be a list where list keys are movables or text used for element names and return value
+ and list values are movables/icons/images used for element icons
+ Select_proc is the proc to be called each time an element on the menu is clicked, and should accept the chosen element as its final argument
+ Clicking the center button will return a choice of null
+*/
+/proc/show_radial_menu_persistent(mob/user, atom/anchor, list/choices, datum/callback/select_proc, uniqueid, radius, tooltips = FALSE)
+ if(!user || !anchor || !length(choices) || !select_proc)
+ return
+ if(!uniqueid)
+ uniqueid = "defmenu_[REF(user)]_[REF(anchor)]"
+
+ if(GLOB.radial_menus[uniqueid])
+ return
+
+ var/datum/radial_menu/persistent/menu = new
+ menu.uniqueid = uniqueid
+ GLOB.radial_menus[uniqueid] = menu
+ if(radius)
+ menu.radius = radius
+ menu.select_proc_callback = select_proc
+ menu.anchor = anchor
+ menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud
+ menu.set_choices(choices, tooltips)
+ menu.show_to(user)
+ return menu
+
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index d23d0905e9..2a14d232aa 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -64,7 +64,7 @@
to_chat(user, "You're too exhausted.") // CIT CHANGE - ditto
return // CIT CHANGE - ditto
- if(force && user.has_trait(TRAIT_PACIFISM))
+ if(force && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "You don't want to harm other living beings!")
return
diff --git a/code/controllers/subsystem/augury.dm b/code/controllers/subsystem/augury.dm
index 875f1ee7d3..1b1c7bc3b7 100644
--- a/code/controllers/subsystem/augury.dm
+++ b/code/controllers/subsystem/augury.dm
@@ -50,7 +50,7 @@ SUBSYSTEM_DEF(augury)
watchers -= w
continue
var/mob/dead/observer/O = w
- if(biggest_doom && (!O.orbiting || O.orbiting.orbiting != biggest_doom))
+ if(biggest_doom && (!O.orbiting || O.orbiting.parent != biggest_doom))
O.ManualFollow(biggest_doom)
/datum/action/innate/augury
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index a2c60618ac..a365405ce6 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -256,10 +256,13 @@ GLOBAL_LIST_EMPTY(the_station_areas)
/datum/controller/subsystem/mapping/proc/generate_station_area_list()
var/list/station_areas_blacklist = typecacheof(list(/area/space, /area/mine, /area/ruin, /area/asteroid/nearstation))
for(var/area/A in world)
- var/turf/picked = safepick(get_area_turfs(A.type))
- if(picked && is_station_level(picked.z))
- if(!(A.type in GLOB.the_station_areas) && !is_type_in_typecache(A, station_areas_blacklist))
- GLOB.the_station_areas.Add(A.type)
+ if (is_type_in_typecache(A, station_areas_blacklist))
+ continue
+ if (!A.contents.len || !A.unique)
+ continue
+ var/turf/picked = A.contents[1]
+ if (is_station_level(picked.z))
+ GLOB.the_station_areas += A.type
if(!GLOB.the_station_areas.len)
log_world("ERROR: Station areas list failed to generate!")
@@ -495,4 +498,9 @@ GLOBAL_LIST_EMPTY(the_station_areas)
clearing |= used_turfs //used turfs is an associative list, BUT, reserve_turfs() can still handle it. If the code above works properly, this won't even be needed as the turfs would be freed already.
unused_turfs.Cut()
used_turfs.Cut()
- reserve_turfs(clearing)
\ No newline at end of file
+ reserve_turfs(clearing)
+
+/datum/controller/subsystem/mapping/proc/reg_in_areas_in_z(list/areas)
+ for(var/B in areas)
+ var/area/A = B
+ A.reg_in_areas_in_z()
diff --git a/code/controllers/subsystem/orbit.dm b/code/controllers/subsystem/orbit.dm
deleted file mode 100644
index 45d280b601..0000000000
--- a/code/controllers/subsystem/orbit.dm
+++ /dev/null
@@ -1,44 +0,0 @@
-SUBSYSTEM_DEF(orbit)
- name = "Orbits"
- priority = FIRE_PRIORITY_ORBIT
- wait = 2
- flags = SS_NO_INIT|SS_TICKER
-
- var/list/currentrun = list()
- var/list/processing = list()
-
-/datum/controller/subsystem/orbit/stat_entry()
- ..("P:[processing.len]")
-
-
-/datum/controller/subsystem/orbit/fire(resumed = 0)
- if (!resumed)
- src.currentrun = processing.Copy()
-
- //cache for sanic speed (lists are references anyways)
- var/list/currentrun = src.currentrun
-
- while (currentrun.len)
- var/datum/orbit/O = currentrun[currentrun.len]
- currentrun.len--
- if (!O)
- processing -= O
- if (MC_TICK_CHECK)
- return
- continue
- if (!O.orbiter)
- qdel(O)
- if (MC_TICK_CHECK)
- return
- continue
- if (O.lastprocess >= world.time) //we already checked recently
- if (MC_TICK_CHECK)
- return
- continue
- var/targetloc = get_turf(O.orbiting)
- if (targetloc != O.lastloc || O.orbiter.loc != targetloc)
- O.Check(targetloc)
- if (MC_TICK_CHECK)
- return
-
-
diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm
index 978eedb62f..455b53b1df 100644
--- a/code/controllers/subsystem/persistence.dm
+++ b/code/controllers/subsystem/persistence.dm
@@ -28,6 +28,7 @@ SUBSYSTEM_DEF(persistence)
LoadPhotoPersistence()
if(CONFIG_GET(flag/use_antag_rep))
LoadAntagReputation()
+ LoadRandomizedRecipes()
return ..()
/datum/controller/subsystem/persistence/proc/LoadSatchels()
@@ -206,6 +207,7 @@ SUBSYSTEM_DEF(persistence)
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
if(CONFIG_GET(flag/use_antag_rep))
CollectAntagReputation()
+ SaveRandomizedRecipes()
/datum/controller/subsystem/persistence/proc/GetPhotoAlbums()
var/album_path = file("data/photo_albums.json")
@@ -371,3 +373,43 @@ SUBSYSTEM_DEF(persistence)
fdel(FILE_ANTAG_REP)
text2file(json_encode(antag_rep), FILE_ANTAG_REP)
+/datum/controller/subsystem/persistence/proc/LoadRandomizedRecipes()
+ var/json_file = file("data/RandomizedChemRecipes.json")
+ var/json
+ if(fexists(json_file))
+ json = json_decode(file2text(json_file))
+
+ for(var/randomized_type in subtypesof(/datum/chemical_reaction/randomized))
+ var/datum/chemical_reaction/randomized/R = new randomized_type
+ var/loaded = FALSE
+ if(R.persistent && json)
+ var/list/recipe_data = json[R.id]
+ if(recipe_data && R.LoadOldRecipe(recipe_data) && (daysSince(R.created) <= R.persistence_period))
+ loaded = TRUE
+ if(!loaded) //We do not have information for whatever reason, just generate new one
+ R.GenerateRecipe()
+
+ if(!R.HasConflicts()) //Might want to try again if conflicts happened in the future.
+ add_chemical_reaction(R)
+
+/datum/controller/subsystem/persistence/proc/SaveRandomizedRecipes()
+ var/json_file = file("data/RandomizedChemRecipes.json")
+ var/list/file_data = list()
+
+ //asert globchems done
+ for(var/randomized_type in subtypesof(/datum/chemical_reaction/randomized))
+ var/datum/chemical_reaction/randomized/R = randomized_type
+ R = get_chemical_reaction(initial(R.id)) //ew, would be nice to add some simple tracking
+ if(R && R.persistent && R.id)
+ var/recipe_data = list()
+ recipe_data["timestamp"] = R.created
+ recipe_data["required_reagents"] = R.required_reagents
+ recipe_data["required_catalysts"] = R.required_catalysts
+ recipe_data["required_temp"] = R.required_temp
+ recipe_data["is_cold_recipe"] = R.is_cold_recipe
+ recipe_data["results"] = R.results
+ recipe_data["required_container"] = "[R.required_container]"
+ file_data["[R.id]"] = recipe_data
+
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(file_data))
diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm
index de58c1a0d7..77ad712b99 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -116,7 +116,7 @@ SUBSYSTEM_DEF(throwing)
return
dist_travelled++
-
+
if (dist_travelled > MAX_THROWING_DIST)
finalize()
return
@@ -154,7 +154,7 @@ SUBSYSTEM_DEF(throwing)
/datum/thrownthing/proc/hitcheck()
for (var/thing in get_turf(thrownthing))
var/atom/movable/AM = thing
- if (AM == thrownthing)
+ if (AM == thrownthing || (AM == thrower && !ismob(thrownthing)))
continue
if (AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags_1 & ON_BORDER_1))
finalize(hit=TRUE, target=AM)
diff --git a/code/datums/action.dm b/code/datums/action.dm
index b7089279cb..f64a549b29 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -195,11 +195,16 @@
/datum/action/item_action/toggle_firemode
name = "Toggle Firemode"
-/datum/action/item_action/rcl
+/datum/action/item_action/rcl_col
name = "Change Cable Color"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "rcl_rainbow"
+/datum/action/item_action/rcl_gui
+ name = "Toggle Fast Wiring Gui"
+ icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "rcl_gui"
+
/datum/action/item_action/startchainsaw
name = "Pull The Starting Cord"
diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm
index afd53726db..f2fec3bb63 100644
--- a/code/datums/brain_damage/mild.dm
+++ b/code/datums/brain_damage/mild.dm
@@ -42,7 +42,7 @@
lose_text = "You feel smart again."
/datum/brain_trauma/mild/dumbness/on_gain()
- owner.add_trait(TRAIT_DUMB, TRAUMA_TRAIT)
+ ADD_TRAIT(owner, TRAIT_DUMB, TRAUMA_TRAIT)
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "dumb", /datum/mood_event/oblivious)
..()
@@ -55,7 +55,7 @@
..()
/datum/brain_trauma/mild/dumbness/on_lose()
- owner.remove_trait(TRAIT_DUMB, TRAUMA_TRAIT)
+ REMOVE_TRAIT(owner, TRAIT_DUMB, TRAUMA_TRAIT)
owner.derpspeech = 0
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "dumb")
..()
diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm
index a8adbfbce8..d094c162d7 100644
--- a/code/datums/brain_damage/severe.dm
+++ b/code/datums/brain_damage/severe.dm
@@ -13,11 +13,11 @@
lose_text = "You suddenly remember how to speak."
/datum/brain_trauma/severe/mute/on_gain()
- owner.add_trait(TRAIT_MUTE, TRAUMA_TRAIT)
+ ADD_TRAIT(owner, TRAIT_MUTE, TRAUMA_TRAIT)
..()
/datum/brain_trauma/severe/mute/on_lose()
- owner.remove_trait(TRAIT_MUTE, TRAUMA_TRAIT)
+ REMOVE_TRAIT(owner, TRAIT_MUTE, TRAUMA_TRAIT)
..()
/datum/brain_trauma/severe/aphasia
@@ -60,18 +60,68 @@
/datum/brain_trauma/severe/paralysis
name = "Paralysis"
- desc = "Patient's brain can no longer control its motor functions."
+ desc = "Patient's brain can no longer control part of its motor functions."
scan_desc = "cerebral paralysis"
- gain_text = "You can't feel your body anymore!"
- lose_text = "You can feel your limbs again!"
+ gain_text = ""
+ lose_text = ""
+ var/paralysis_type
+ var/list/paralysis_traits = list()
+ //for descriptions
-/datum/brain_trauma/severe/paralysis/on_life()
- owner.Knockdown(200, ignore_canknockdown = TRUE)
+/datum/brain_trauma/severe/paralysis/New(specific_type)
+ if(specific_type)
+ paralysis_type = specific_type
+ if(!paralysis_type)
+ paralysis_type = pick("full","left","right","arms","legs","r_arm","l_arm","r_leg","l_leg")
+ var/subject
+ switch(paralysis_type)
+ if("full")
+ subject = "your body"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG)
+ if("left")
+ subject = "the left side of your body"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_L_LEG)
+ if("right")
+ subject = "the right side of your body"
+ paralysis_traits = list(TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_R_LEG)
+ if("arms")
+ subject = "your arms"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM)
+ if("legs")
+ subject = "your legs"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG)
+ if("r_arm")
+ subject = "your right arm"
+ paralysis_traits = list(TRAIT_PARALYSIS_R_ARM)
+ if("l_arm")
+ subject = "your left arm"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_ARM)
+ if("r_leg")
+ subject = "your right leg"
+ paralysis_traits = list(TRAIT_PARALYSIS_R_LEG)
+ if("l_leg")
+ subject = "your left leg"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_LEG)
+
+ gain_text = "You can't feel [subject] anymore!"
+ lose_text = "You can feel [subject] again!"
+
+/datum/brain_trauma/severe/paralysis/on_gain()
..()
+ for(var/X in paralysis_traits)
+ ADD_TRAIT(owner, X, "trauma_paralysis")
+ owner.update_disabled_bodyparts()
/datum/brain_trauma/severe/paralysis/on_lose()
- owner.SetKnockdown(0)
..()
+ for(var/X in paralysis_traits)
+ REMOVE_TRAIT(owner, X, "trauma_paralysis")
+ owner.update_disabled_bodyparts()
+
+/datum/brain_trauma/severe/paralysis/paraplegic
+ //can_gain = FALSE maybe breaks.
+ paralysis_type = "legs"
+ resilience = TRAUMA_RESILIENCE_ABSOLUTE
/datum/brain_trauma/severe/narcolepsy
name = "Narcolepsy"
@@ -121,7 +171,7 @@
stress -= 4
/datum/brain_trauma/severe/monophobia/proc/check_alone()
- if(owner.has_trait(TRAIT_BLIND))
+ if(HAS_TRAIT(owner, TRAIT_BLIND))
return TRUE
for(var/mob/M in oview(owner, 7))
if(!isliving(M)) //ghosts ain't people
@@ -183,11 +233,11 @@
lose_text = "You feel in control of your hands again."
/datum/brain_trauma/severe/discoordination/on_gain()
- owner.add_trait(TRAIT_MONKEYLIKE, TRAUMA_TRAIT)
+ ADD_TRAIT(owner, TRAIT_MONKEYLIKE, TRAUMA_TRAIT)
..()
/datum/brain_trauma/severe/discoordination/on_lose()
- owner.remove_trait(TRAIT_MONKEYLIKE, TRAUMA_TRAIT)
+ REMOVE_TRAIT(owner, TRAIT_MONKEYLIKE, TRAUMA_TRAIT)
..()
/datum/brain_trauma/severe/pacifism
@@ -198,9 +248,9 @@
lose_text = "You no longer feel compelled to not harm."
/datum/brain_trauma/severe/pacifism/on_gain()
- owner.add_trait(TRAIT_PACIFISM, TRAUMA_TRAIT)
+ ADD_TRAIT(owner, TRAIT_PACIFISM, TRAUMA_TRAIT)
..()
/datum/brain_trauma/severe/pacifism/on_lose()
- owner.remove_trait(TRAIT_PACIFISM, TRAUMA_TRAIT)
- ..()
\ No newline at end of file
+ REMOVE_TRAIT(owner, TRAIT_PACIFISM, TRAUMA_TRAIT)
+ ..()
diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm
index 9ce65717f1..612af13392 100644
--- a/code/datums/brain_damage/split_personality.dm
+++ b/code/datums/brain_damage/split_personality.dm
@@ -192,7 +192,7 @@
return //no random switching
/datum/brain_trauma/severe/split_personality/brainwashing/on_hear(message, speaker, message_language, raw_message, radio_freq)
- if(owner.has_trait(TRAIT_DEAF) || owner == speaker)
+ if(HAS_TRAIT(owner, TRAIT_DEAF) || owner == speaker)
return message
if(findtext(message, codeword))
message = replacetext(message, codeword, "[codeword]")
diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm
index 1e1b7a0a48..838a1b576a 100644
--- a/code/datums/components/caltrop.dm
+++ b/code/datums/components/caltrop.dm
@@ -24,7 +24,7 @@
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
- if(H.has_trait(TRAIT_PIERCEIMMUNE))
+ if(HAS_TRAIT(H, TRAIT_PIERCEIMMUNE))
return
if((flags & CALTROP_IGNORE_WALKERS) && H.m_intent == MOVE_INTENT_WALK)
@@ -46,7 +46,7 @@
return
var/damage = rand(min_damage, max_damage)
- if(H.has_trait(TRAIT_LIGHT_STEP))
+ if(HAS_TRAIT(H, TRAIT_LIGHT_STEP))
damage *= 0.75
H.apply_damage(damage, BRUTE, picked_def_zone)
diff --git a/code/datums/components/earhealing.dm b/code/datums/components/earhealing.dm
index 9396eab3a3..6eb71285e0 100644
--- a/code/datums/components/earhealing.dm
+++ b/code/datums/components/earhealing.dm
@@ -23,7 +23,7 @@
if (!wearer)
STOP_PROCESSING(SSobj, src)
return
- if(!wearer.has_trait(TRAIT_DEAF))
+ if(!HAS_TRAIT(wearer, TRAIT_DEAF))
var/obj/item/organ/ears/ears = wearer.getorganslot(ORGAN_SLOT_EARS)
if (ears)
ears.deaf = max(ears.deaf - 1, (ears.ear_damage < UNHEALING_EAR_DAMAGE ? 0 : 1)) // Do not clear deafness while above the unhealing ear damage threshold
diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm
index 933c38505b..b32921a4ce 100644
--- a/code/datums/components/mood.dm
+++ b/code/datums/components/mood.dm
@@ -15,7 +15,7 @@
/datum/component/mood/Initialize()
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
-
+
START_PROCESSING(SSmood, src)
RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/add_event)
@@ -150,17 +150,17 @@
else
owner.crit_threshold -= (holdmyinsanityeffect - insanity_effect)
- if(owner.has_trait(TRAIT_DEPRESSION))
+ if(HAS_TRAIT(owner, TRAIT_DEPRESSION))
if(prob(0.05))
add_event(null, "depression", /datum/mood_event/depression)
clear_event(null, "jolly")
- if(owner.has_trait(TRAIT_JOLLY))
+ if(HAS_TRAIT(owner, TRAIT_JOLLY))
if(prob(0.05))
add_event(null, "jolly", /datum/mood_event/jolly)
clear_event(null, "depression")
holdmyinsanityeffect = insanity_effect
-
+
HandleNutrition(owner)
/datum/component/mood/proc/DecreaseSanity(amount, minimum = SANITY_INSANE)
diff --git a/code/datums/components/orbiter.dm b/code/datums/components/orbiter.dm
new file mode 100644
index 0000000000..301e50dc42
--- /dev/null
+++ b/code/datums/components/orbiter.dm
@@ -0,0 +1,156 @@
+/datum/component/orbiter
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+ var/list/orbiters
+ var/datum/callback/orbiter_spy
+ var/datum/callback/orbited_spy
+
+//radius: range to orbit at, radius of the circle formed by orbiting (in pixels)
+//clockwise: whether you orbit clockwise or anti clockwise
+//rotation_speed: how fast to rotate (how many ds should it take for a rotation to complete)
+//rotation_segments: the resolution of the orbit circle, less = a more block circle, this can be used to produce hexagons (6 segments) triangles (3 segments), and so on, 36 is the best default.
+//pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts
+/datum/component/orbiter/Initialize(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
+ if(!istype(orbiter) || !isatom(parent) || isarea(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ orbiters = list()
+ orbiter_spy = CALLBACK(src, .proc/orbiter_move_react)
+ orbited_spy = CALLBACK(src, .proc/move_react)
+
+ var/atom/master = parent
+ master.orbiters = src
+
+ begin_orbit(orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
+
+/datum/component/orbiter/RegisterWithParent()
+ var/atom/target = parent
+ while(ismovableatom(target))
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, orbited_spy)
+ target = target.loc
+
+/datum/component/orbiter/UnregisterFromParent()
+ var/atom/target = parent
+ while(ismovableatom(target))
+ UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
+ target = target.loc
+
+/datum/component/orbiter/Destroy()
+ var/atom/master = parent
+ master.orbiters = null
+ for(var/i in orbiters)
+ end_orbit(i)
+ orbiters = null
+ QDEL_NULL(orbiter_spy)
+ QDEL_NULL(orbited_spy)
+ return ..()
+
+/datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, list/arguments)
+ if(arguments)
+ begin_orbit(arglist(arguments))
+ return
+ // The following only happens on component transfers
+ orbiters += newcomp.orbiters
+
+/datum/component/orbiter/PostTransfer()
+ if(!isatom(parent) || isarea(parent) || !get_turf(parent))
+ return COMPONENT_INCOMPATIBLE
+ move_react()
+
+/datum/component/orbiter/proc/begin_orbit(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
+ if(orbiter.orbiting)
+ if(orbiter.orbiting == src)
+ orbiter.orbiting.end_orbit(orbiter, TRUE)
+ else
+ orbiter.orbiting.end_orbit(orbiter)
+ orbiters[orbiter] = TRUE
+ orbiter.orbiting = src
+ RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, orbiter_spy)
+ var/matrix/initial_transform = matrix(orbiter.transform)
+
+ // Head first!
+ if(pre_rotation)
+ var/matrix/M = matrix(orbiter.transform)
+ var/pre_rot = 90
+ if(!clockwise)
+ pre_rot = -90
+ M.Turn(pre_rot)
+ orbiter.transform = M
+
+ var/matrix/shift = matrix(orbiter.transform)
+ shift.Translate(0, radius)
+ orbiter.transform = shift
+
+ orbiter.SpinAnimation(rotation_speed, -1, clockwise, rotation_segments, parallel = FALSE)
+
+ //we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
+ orbiter.transform = initial_transform
+ orbiter.forceMove(get_turf(parent))
+ to_chat(orbiter, "Now orbiting [parent].")
+
+/datum/component/orbiter/proc/end_orbit(atom/movable/orbiter, refreshing=FALSE)
+ if(!orbiters[orbiter])
+ return
+ UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED)
+ orbiter.SpinAnimation(0, 0)
+ orbiters -= orbiter
+ orbiter.stop_orbit(src)
+ orbiter.orbiting = null
+ if(!refreshing && !length(orbiters) && !QDELING(src))
+ qdel(src)
+
+// This proc can receive signals by either the thing being directly orbited or anything holding it
+/datum/component/orbiter/proc/move_react(atom/orbited, atom/oldloc, direction)
+ set waitfor = FALSE // Transfer calls this directly and it doesnt care if the ghosts arent done moving
+
+ var/atom/movable/master = parent
+ if(master.loc == oldloc)
+ return
+
+ var/turf/newturf = get_turf(master)
+ if(!newturf)
+ qdel(src)
+
+ // Handling the signals of stuff holding us (or not anymore)
+ // These are prety rarely activated, how often are you following something in a bag?
+ if(oldloc && !isturf(oldloc)) // We used to be registered to it, probably
+ var/atom/target = oldloc
+ while(ismovableatom(target))
+ UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
+ target = target.loc
+ if(orbited?.loc && orbited.loc != newturf) // We want to know when anything holding us moves too
+ var/atom/target = orbited.loc
+ while(ismovableatom(target))
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, orbited_spy, TRUE)
+ target = target.loc
+
+ var/atom/curloc = master.loc
+ for(var/i in orbiters)
+ var/atom/movable/thing = i
+ if(QDELETED(thing) || thing.loc == newturf)
+ continue
+ thing.forceMove(newturf)
+ if(CHECK_TICK && master.loc != curloc)
+ // We moved again during the checktick, cancel current operation
+ break
+
+
+/datum/component/orbiter/proc/orbiter_move_react(atom/movable/orbiter, atom/oldloc, direction)
+ if(orbiter.loc == get_turf(parent))
+ return
+ end_orbit(orbiter)
+
+/////////////////////
+
+/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE)
+ if(!istype(A) || !get_turf(A) || A == src)
+ return
+
+ return A.AddComponent(/datum/component/orbiter, src, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
+
+/atom/movable/proc/stop_orbit(datum/component/orbiter/orbits)
+ return // We're just a simple hook
+
+/atom/proc/transfer_observers_to(atom/target)
+ if(!orbiters || !istype(target) || !get_turf(target) || target == src)
+ return
+ target.TakeComponent(orbiters)
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index e74e30b536..cdb195dd82 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -2,6 +2,7 @@
var/gc_destroyed //Time when this object was destroyed.
var/list/active_timers //for SStimer
var/list/datum_components //for /datum/components
+ var/list/status_traits
var/list/comp_lookup //it used to be for looking up components which had registered a signal but now anything can register
var/list/signal_procs
var/signal_enabled = FALSE
diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm
index ba570eca06..e1432bf9a6 100644
--- a/code/datums/diseases/_MobProcs.dm
+++ b/code/datums/diseases/_MobProcs.dm
@@ -117,7 +117,7 @@
/mob/living/carbon/AirborneContractDisease(datum/disease/D, force_spread)
if(internal)
return
- if(has_trait(TRAIT_NOBREATH))
+ if(HAS_TRAIT(src, TRAIT_NOBREATH))
return
..()
@@ -137,7 +137,7 @@
/mob/living/carbon/human/CanContractDisease(datum/disease/D)
if(dna)
- if(has_trait(TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity)
+ if(HAS_TRAIT(src, TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity)
return FALSE
for(var/thing in D.required_organs)
diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm
index 0ace2ca8fd..e666c7acd6 100644
--- a/code/datums/diseases/advance/symptoms/heal.dm
+++ b/code/datums/diseases/advance/symptoms/heal.dm
@@ -233,7 +233,7 @@
/datum/symptom/heal/coma/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
- if(M.has_trait(TRAIT_DEATHCOMA))
+ if(HAS_TRAIT(M, TRAIT_DEATHCOMA))
return power
else if(M.IsUnconscious() || M.stat == UNCONSCIOUS)
return power * 0.9
@@ -364,15 +364,15 @@
/datum/symptom/heal/plasma/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
var/datum/gas_mixture/environment
- var/list/gases
+ var/plasmamount
. = 0
if(M.loc)
environment = M.loc.return_air()
if(environment)
- gases = environment.gases
- if(gases["plasma"] && gases["plasma"][MOLES] > gases["plasma"][GAS_META][META_GAS_MOLES_VISIBLE]) //if there's enough plasma in the air to see
+ plasmamount = environment.gases[/datum/gas/plasma]
+ if(plasmamount && plasmamount > GLOB.meta_gas_visibility[/datum/gas/plasma]) //if there's enough plasma in the air to see
. += power * 0.5
if(M.reagents.has_reagent("plasma"))
. += power * 0.75
diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm
index ffc145bd72..8d7cc5ed70 100644
--- a/code/datums/diseases/advance/symptoms/sensory.dm
+++ b/code/datums/diseases/advance/symptoms/sensory.dm
@@ -85,14 +85,14 @@
if(4, 5)
M.restoreEars()
- if(M.has_trait(TRAIT_BLIND, EYE_DAMAGE))
+ if(HAS_TRAIT_FROM(M, TRAIT_BLIND, EYE_DAMAGE))
if(prob(20))
to_chat(M, "Your vision slowly returns...")
M.cure_blind(EYE_DAMAGE)
M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(35)
- else if(M.has_trait(TRAIT_NEARSIGHT, EYE_DAMAGE))
+ else if(HAS_TRAIT_FROM(M, TRAIT_NEARSIGHT, EYE_DAMAGE))
to_chat(M, "You can finally focus your eyes on distant objects.")
M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(10)
diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm
index 0b42012f76..d1cc6905a6 100644
--- a/code/datums/diseases/advance/symptoms/vision.dm
+++ b/code/datums/diseases/advance/symptoms/vision.dm
@@ -61,7 +61,7 @@ Bonus
M.become_nearsighted(EYE_DAMAGE)
if(prob(eyes.eye_damage - 10 + 1))
if(!remove_eyes)
- if(!M.has_trait(TRAIT_BLIND))
+ if(!HAS_TRAIT(M, TRAIT_BLIND))
to_chat(M, "You go blind!")
M.become_blind(EYE_DAMAGE)
else
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index 57cdb9bcf5..6c91cc3a7d 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -133,7 +133,7 @@
if(isliving(user))
var/mob/living/L = user
- if(L.has_trait(TRAIT_EMOTEMUTE))
+ if(HAS_TRAIT(L, TRAIT_EMOTEMUTE))
return FALSE
/datum/emote/sound
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index d673cdb16d..0623e2f5f9 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -103,11 +103,11 @@
// Can most things breathe?
if(trace_gases)
continue
- if(!(A_gases[/datum/gas/oxygen] && A_gases[/datum/gas/oxygen][MOLES] >= 16))
+ if(A_gases[/datum/gas/oxygen] >= 16)
continue
if(A_gases[/datum/gas/plasma])
continue
- if(A_gases[/datum/gas/carbon_dioxide] && A_gases[/datum/gas/carbon_dioxide][MOLES] >= 10)
+ if(A_gases[/datum/gas/carbon_dioxide] >= 10)
continue
// Aim for goldilocks temperatures and pressure
diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm
index 8a5f0f9439..127413262c 100644
--- a/code/datums/martial/krav_maga.dm
+++ b/code/datums/martial/krav_maga.dm
@@ -86,13 +86,13 @@
return 0
/datum/martial_art/krav_maga/proc/leg_sweep(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(D.stat || D.IsKnockdown())
+ if(D.lying || D.IsKnockdown())
return 0
D.visible_message("[A] leg sweeps [D]!", \
"[A] leg sweeps you!")
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE)
- D.Knockdown(40)
+ D.Knockdown(40, override_hardstun = 0.01, 25)
log_combat(A, D, "leg sweeped")
return 1
@@ -191,3 +191,18 @@
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
+
+/obj/item/clothing/gloves/krav_maga/combatglovesplus
+ name = "combat gloves plus"
+ desc = "These tactical gloves are fireproof and shock resistant, and using nanochip technology it teaches you the powers of krav maga."
+ icon_state = "black"
+ item_state = "blackglovesplus"
+ siemens_coefficient = 0
+ permeability_coefficient = 0.05
+ strip_delay = 80
+ cold_protection = HANDS
+ min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
+ heat_protection = HANDS
+ max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
+ resistance_flags = NONE
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 50)
diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index 4a15afd672..035e5ac833 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -179,7 +179,7 @@
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
add_fingerprint(user)
- if((user.has_trait(TRAIT_CLUMSY)) && prob(50))
+ if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
to_chat(user, "You club yourself over the head with [src].")
user.Knockdown(60)
if(ishuman(user))
diff --git a/code/datums/mood_events/drink_events.dm b/code/datums/mood_events/drink_events.dm
index db5a91009e..5d0eb0e0cb 100644
--- a/code/datums/mood_events/drink_events.dm
+++ b/code/datums/mood_events/drink_events.dm
@@ -22,3 +22,8 @@
description = "That drink was amazing!\n"
mood_change = 4
timeout = 1200
+
+/datum/mood_event/amazingtaste
+ description = "Amazing taste!\n"
+ mood_change = 50
+ timeout = 10 MINUTES
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index 4021d11128..06857c0f55 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -125,3 +125,11 @@
/datum/mood_event/surgery
description = "HE'S CUTTING ME OPEN!!\n"
mood_change = -8
+
+/datum/mood_event/sad_empath
+ description = "Someone seems upset...\n"
+ mood_change = -2
+ timeout = 600
+
+/datum/mood_event/sad_empath/add_effects(mob/sadtarget)
+ description = "[sadtarget.name] seems upset...\n"
diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm
index 6989744fe3..051a548d1d 100644
--- a/code/datums/mood_events/generic_positive_events.dm
+++ b/code/datums/mood_events/generic_positive_events.dm
@@ -75,3 +75,27 @@
description = "There is something soothing about this music.\n"
mood_change = 3
timeout = 600
+
+/datum/mood_event/betterhug
+ description = "Someone was very nice to me.\n"
+ mood_change = 3
+ timeout = 3000
+
+/datum/mood_event/betterhug/add_effects(mob/friend)
+ description = "[friend.name] was very nice to me.\n"
+
+/datum/mood_event/besthug
+ description = "Someone is great to be around, they make me feel so happy!\n"
+ mood_change = 5
+ timeout = 3000
+
+/datum/mood_event/besthug/add_effects(mob/friend)
+ description = "[friend.name] is great to be around, [friend.p_they()] makes me feel so happy!\n"
+
+/datum/mood_event/happy_empath
+ description = "Someone seems happy!\n"
+ mood_change = 2
+ timeout = 600
+
+/datum/mood_event/happy_empath/add_effects(var/mob/happytarget)
+ description = "[happytarget.name]'s happiness is infectious!\n"
diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm
index e114a43736..461c221ff8 100644
--- a/code/datums/mutations/body.dm
+++ b/code/datums/mutations/body.dm
@@ -86,12 +86,12 @@
/datum/mutation/human/clumsy/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.add_trait(TRAIT_CLUMSY, GENETIC_MUTATION)
+ ADD_TRAIT(owner, TRAIT_CLUMSY, GENETIC_MUTATION)
/datum/mutation/human/clumsy/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.remove_trait(TRAIT_CLUMSY, GENETIC_MUTATION)
+ REMOVE_TRAIT(owner, TRAIT_CLUMSY, GENETIC_MUTATION)
//Tourettes causes you to randomly stand in place and shout.
@@ -125,12 +125,12 @@
/datum/mutation/human/deaf/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.add_trait(TRAIT_DEAF, GENETIC_MUTATION)
+ ADD_TRAIT(owner, TRAIT_DEAF, GENETIC_MUTATION)
/datum/mutation/human/deaf/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.remove_trait(TRAIT_DEAF, GENETIC_MUTATION)
+ REMOVE_TRAIT(owner, TRAIT_DEAF, GENETIC_MUTATION)
//Monified turns you into a monkey.
diff --git a/code/datums/mutations/cold_resistance.dm b/code/datums/mutations/cold_resistance.dm
index 6c3ac2982d..3d8fbababa 100644
--- a/code/datums/mutations/cold_resistance.dm
+++ b/code/datums/mutations/cold_resistance.dm
@@ -17,14 +17,14 @@
/datum/mutation/human/cold_resistance/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.add_trait(TRAIT_RESISTCOLD, "cold_resistance")
-// owner.add_trait(TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE
+ ADD_TRAIT(owner, TRAIT_RESISTCOLD, "cold_resistance")
+// ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE
/datum/mutation/human/cold_resistance/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.remove_trait(TRAIT_RESISTCOLD, "cold_resistance")
-// owner.remove_trait(TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE
+ REMOVE_TRAIT(owner, TRAIT_RESISTCOLD, "cold_resistance")
+// REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE
/datum/mutation/human/cold_resistance/on_life(mob/living/carbon/human/owner)
if(owner.getFireLoss())
diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm
index 7bcd056fab..0c760f4620 100644
--- a/code/datums/mutations/hulk.dm
+++ b/code/datums/mutations/hulk.dm
@@ -11,8 +11,8 @@
/datum/mutation/human/hulk/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.add_trait(TRAIT_STUNIMMUNE, TRAIT_HULK)
- owner.add_trait(TRAIT_PUSHIMMUNE, TRAIT_HULK)
+ ADD_TRAIT(owner, TRAIT_STUNIMMUNE, TRAIT_HULK)
+ ADD_TRAIT(owner, TRAIT_PUSHIMMUNE, TRAIT_HULK)
owner.update_body_parts()
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "hulk", /datum/mood_event/hulk)
@@ -28,8 +28,8 @@
/datum/mutation/human/hulk/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.remove_trait(TRAIT_STUNIMMUNE, TRAIT_HULK)
- owner.remove_trait(TRAIT_PUSHIMMUNE, TRAIT_HULK)
+ REMOVE_TRAIT(owner, TRAIT_STUNIMMUNE, TRAIT_HULK)
+ REMOVE_TRAIT(owner, TRAIT_PUSHIMMUNE, TRAIT_HULK)
owner.update_body_parts()
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "hulk")
diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm
index 3f303535ce..d986672924 100644
--- a/code/datums/mutations/speech.dm
+++ b/code/datums/mutations/speech.dm
@@ -30,12 +30,12 @@
/datum/mutation/human/mute/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
- owner.add_trait(TRAIT_MUTE, GENETIC_MUTATION)
+ ADD_TRAIT(owner, TRAIT_MUTE, GENETIC_MUTATION)
/datum/mutation/human/mute/on_losing(mob/living/carbon/human/owner)
if(..())
return
- owner.remove_trait(TRAIT_MUTE, GENETIC_MUTATION)
+ REMOVE_TRAIT(owner, TRAIT_MUTE, GENETIC_MUTATION)
/datum/mutation/human/smile
@@ -229,4 +229,4 @@
/datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner)
..()
owner.grant_language(/datum/language/common)
- owner.remove_language(/datum/language/beachbum)
+ owner.remove_language(/datum/language/beachbum)
\ No newline at end of file
diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm
index 058c820f7a..22fca23902 100644
--- a/code/datums/ruins/space.dm
+++ b/code/datums/ruins/space.dm
@@ -281,3 +281,27 @@
suffix = "cloning_facility.dmm"
name = "Ancient Cloning Lab"
description = "An experimental cloning lab snapped off from an ancient ship. The cloner model inside lacks many modern functionalities and security measures."
+
+/datum/map_template/ruin/space/augmentation
+ id = "augmentationfacility"
+ suffix = "augmentationfacility.dmm"
+ name = "Roboticst Augmentation Facility"
+ description = "A mysterious lab in the depths of space containing robotics supplies and a one use autosurgeon."
+
+/datum/map_template/ruin/space/harambe
+ id = "bigape"
+ suffix = "bigape.dmm"
+ name = "Big Ape"
+ description = "A gorilla? Out here? But why."
+
+/datum/map_template/ruin/space/space_arcade
+ id = "arcade"
+ suffix = "arcade.dmm"
+ name = "Space Arcade"
+ description = "A lonely arcade in the depths of space."
+
+/datum/map_template/ruin/space/hermit
+ id = "spacehermit"
+ suffix = "spacehermit.dmm"
+ name = "Space Hermit"
+ description = "A late awakening cryo pod in a crashed escape pod wakes up to find what befell of his fellow survivors. Contains all the necessary resources to actually make it out alive. Good luck."
diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm
index ed6edd11ab..c4f485653e 100644
--- a/code/datums/saymode.dm
+++ b/code/datums/saymode.dm
@@ -27,7 +27,7 @@
switch(M.lingcheck())
if (LINGHIVE_LING)
var/mob/living/L = M
- if (!L.has_trait(CHANGELING_HIVEMIND_MUTE))
+ if (!HAS_TRAIT(L, CHANGELING_HIVEMIND_MUTE))
to_chat(M, msg)
if(LINGHIVE_LINK)
to_chat(M, msg)
@@ -35,7 +35,7 @@
if(prob(40))
to_chat(M, "We can faintly sense an outsider trying to communicate through the hivemind...")
if(LINGHIVE_LING)
- if (user.has_trait(CHANGELING_HIVEMIND_MUTE))
+ if (HAS_TRAIT(user, CHANGELING_HIVEMIND_MUTE))
to_chat(user, "The poison in the air hinders our ability to interact with the hivemind.")
return FALSE
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
@@ -52,7 +52,7 @@
to_chat(M, msg)
if(LINGHIVE_LING)
var/mob/living/L = M
- if (!L.has_trait(CHANGELING_HIVEMIND_MUTE))
+ if (!HAS_TRAIT(L, CHANGELING_HIVEMIND_MUTE))
to_chat(M, msg)
if(LINGHIVE_OUTSIDER)
if(prob(40))
diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm
index dd8ee1b166..0512977d1a 100644
--- a/code/datums/status_effects/buffs.dm
+++ b/code/datums/status_effects/buffs.dm
@@ -465,13 +465,13 @@
/datum/status_effect/hippocraticOath/on_apply()
//Makes the user passive, it's in their oath not to harm!
- owner.add_trait(TRAIT_PACIFISM, "hippocraticOath")
+ ADD_TRAIT(owner, TRAIT_PACIFISM, "hippocraticOath")
var/datum/atom_hud/H = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
H.add_hud_to(owner)
return ..()
/datum/status_effect/hippocraticOath/on_remove()
- owner.remove_trait(TRAIT_PACIFISM, "hippocraticOath")
+ REMOVE_TRAIT(owner, TRAIT_PACIFISM, "hippocraticOath")
var/datum/atom_hud/H = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
H.remove_hud_from(owner)
diff --git a/code/datums/traits/_quirk.dm b/code/datums/traits/_quirk.dm
index 963afacec3..cc6dd8db3f 100644
--- a/code/datums/traits/_quirk.dm
+++ b/code/datums/traits/_quirk.dm
@@ -21,7 +21,7 @@
to_chat(quirk_holder, gain_text)
quirk_holder.roundstart_quirks += src
if(mob_trait)
- quirk_holder.add_trait(mob_trait, ROUNDSTART_TRAIT)
+ ADD_TRAIT(quirk_holder, mob_trait, ROUNDSTART_TRAIT)
START_PROCESSING(SSquirks, src)
add()
if(spawn_effects)
@@ -35,7 +35,7 @@
to_chat(quirk_holder, lose_text)
quirk_holder.roundstart_quirks -= src
if(mob_trait)
- quirk_holder.remove_trait(mob_trait, ROUNDSTART_TRAIT, TRUE)
+ REMOVE_TRAIT(quirk_holder, mob_trait, ROUNDSTART_TRAIT)
SSquirks.quirk_objects -= src
return ..()
@@ -43,8 +43,8 @@
quirk_holder.roundstart_quirks -= src
to_mob.roundstart_quirks += src
if(mob_trait)
- quirk_holder.remove_trait(mob_trait, ROUNDSTART_TRAIT)
- to_mob.add_trait(mob_trait, ROUNDSTART_TRAIT)
+ REMOVE_TRAIT(quirk_holder, mob_trait, ROUNDSTART_TRAIT)
+ ADD_TRAIT(to_mob, mob_trait, ROUNDSTART_TRAIT)
quirk_holder = to_mob
on_transfer()
@@ -111,7 +111,7 @@ Use this as a guideline
mob_trait = TRAIT_NEARSIGHT
///This define is in __DEFINES/traits.dm and is the actual "trait" that the game tracks
- ///You'll need to use "has_trait(X, sources)" checks around the code to check this; for instance, the Ageusia trait is checked in taste code
+ ///You'll need to use "HAS_TRAIT_FROM(src, X, sources)" checks around the code to check this; for instance, the Ageusia trait is checked in taste code
///If you need help finding where to put it, the declaration finder on GitHub is the best way to locate it
gain_text = "Things far away from you start looking blurry."
diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm
index 513115b194..300a1264eb 100644
--- a/code/datums/traits/good.dm
+++ b/code/datums/traits/good.dm
@@ -35,6 +35,14 @@
lose_text = "You no longer feel like drinking would ease your pain."
medical_record_text = "Patient has unusually efficient liver metabolism and can slowly regenerate wounds by drinking alcoholic beverages."
+/datum/quirk/empath
+ name = "Empath"
+ desc = "Whether it's a sixth sense or careful study of body language, it only takes you a quick glance at someone to understand how they feel."
+ value = 2
+ mob_trait = TRAIT_EMPATH
+ gain_text = "You feel in tune with those around you."
+ lose_text = "You feel isolated from others."
+
/datum/quirk/freerunning
name = "Freerunning"
desc = "You're great at quick moves! You can climb tables more quickly."
@@ -43,6 +51,15 @@
gain_text = "You feel lithe on your feet!"
lose_text = "You feel clumsy again."
+/datum/quirk/friendly
+ name = "Friendly"
+ desc = "You give the best hugs, especially when you're in the right mood."
+ value = 1
+ mob_trait = TRAIT_FRIENDLY
+ gain_text = "You want to hug someone."
+ lose_text = "You no longer feel compelled to hug others."
+ mood_quirk = TRUE
+
/datum/quirk/jolly
name = "Jolly"
desc = "You sometimes just feel happy, for no reason at all."
diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm
index 614cc65cbb..36c6733cf7 100644
--- a/code/datums/traits/negative.dm
+++ b/code/datums/traits/negative.dm
@@ -38,13 +38,13 @@
var/obj/item/heirloom_type
switch(quirk_holder.mind.assigned_role)
if("Clown")
- heirloom_type = /obj/item/paint/anycolor
- heirloom_type = /obj/item/bikehorn/golden
+ heirloom_type = pick(/obj/item/paint/anycolor, /obj/item/bikehorn/golden)
if("Mime")
- heirloom_type = /obj/item/paint/anycolor
- heirloom_type = /obj/item/toy/dummy
+ heirloom_type = pick(/obj/item/paint/anycolor, /obj/item/toy/dummy)
if("Cook")
heirloom_type = /obj/item/kitchen/knife/scimitar
+ if("Botanist")
+ heirloom_type = pick(/obj/item/cultivator, /obj/item/reagent_containers/glass/bucket, /obj/item/storage/bag/plants, /obj/item/toy/plush/beeplushie)
if("Medical Doctor")
heirloom_type = /obj/item/healthanalyzer/advanced
if("Station Engineer")
@@ -60,7 +60,7 @@
if("Scientist")
heirloom_type = /obj/item/toy/plush/slimeplushie
if("Assistant")
- heirloom_type = /obj/item/storage/toolbox/mechanical/old/heirloom
+ heirloom_type = /obj/item/clothing/gloves/cut/family
if("Chaplain")
heirloom_type = /obj/item/camera/spooky/family
if("Captain")
@@ -187,6 +187,41 @@
to_chat(quirk_holder, "Your antagonistic nature has caused you to renounce your pacifism.")
qdel(src)
+/datum/quirk/paraplegic
+ name = "Paraplegic"
+ desc = "Your legs do not function. Nothing will ever fix this. But hey, free wheelchair!"
+ value = -3
+ mob_trait = TRAIT_PARA
+ human_only = TRUE
+ gain_text = null // Handled by trauma.
+ lose_text = null
+ medical_record_text = "Patient has an untreatable impairment in motor function in the lower extremities."
+
+/datum/quirk/paraplegic/add()
+ var/datum/brain_trauma/severe/paralysis/paraplegic/T = new()
+ var/mob/living/carbon/human/H = quirk_holder
+ H.gain_trauma(T, TRAUMA_RESILIENCE_ABSOLUTE)
+
+/datum/quirk/paraplegic/on_spawn()
+ if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs.
+ quirk_holder.buckled.unbuckle_mob(quirk_holder)
+
+ var/turf/T = get_turf(quirk_holder)
+ var/obj/structure/chair/spawn_chair = locate() in T
+
+ var/obj/vehicle/ridden/wheelchair/wheels = new(T)
+ if(spawn_chair) // Makes spawning on the arrivals shuttle more consistent looking
+ wheels.setDir(spawn_chair.dir)
+
+ wheels.buckle_mob(quirk_holder)
+
+ // During the spawning process, they may have dropped what they were holding, due to the paralysis
+ // So put the things back in their hands.
+
+ for(var/obj/item/I in T)
+ if(I.fingerprintslast == quirk_holder.ckey)
+ quirk_holder.put_in_hands(I)
+
/datum/quirk/poor_aim
name = "Poor Aim"
desc = "You're terrible with guns and can't line up a straight shot to save your life. Dual-wielding is right out."
@@ -208,8 +243,12 @@
var/slot_string = "limb"
/datum/quirk/prosthetic_limb/on_spawn()
- var/limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/mob/living/carbon/human/H = quirk_holder
+ var/limb_slot
+ if(HAS_TRAIT(H, TRAIT_PARA))//Prevent paraplegic legs being replaced
+ limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
+ else
+ limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/obj/item/bodypart/old_part = H.get_bodypart(limb_slot)
var/obj/item/bodypart/prosthetic
switch(limb_slot)
diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm
index 0906a7e053..f3b8118087 100644
--- a/code/datums/weather/weather_types/radiation_storm.dm
+++ b/code/datums/weather/weather_types/radiation_storm.dm
@@ -33,7 +33,7 @@
if(prob(40))
if(ishuman(L))
var/mob/living/carbon/human/H = L
- if(H.dna && !H.has_trait(TRAIT_RADIMMUNE))
+ if(H.dna && !HAS_TRAIT(H, TRAIT_RADIMMUNE))
if(prob(max(0,100-resist)))
H.randmuti()
if(prob(50))
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 10650153d6..dfbb59811b 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -76,7 +76,9 @@ GLOBAL_LIST_EMPTY(teleportlocs)
continue
if(GLOB.teleportlocs[AR.name])
continue
- var/turf/picked = safepick(get_area_turfs(AR.type))
+ if (!AR.contents.len)
+ continue
+ var/turf/picked = AR.contents[1]
if (picked && is_station_level(picked.z))
GLOB.teleportlocs[AR.name] = AR
@@ -120,6 +122,14 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(!IS_DYNAMIC_LIGHTING(src))
add_overlay(/obj/effect/fullbright)
+ reg_in_areas_in_z()
+
+ return INITIALIZE_HINT_LATELOAD
+
+/area/LateInitialize()
+ power_change() // all machines set to current power level, also updates icon
+
+/area/proc/reg_in_areas_in_z()
if(contents.len)
var/list/areas_in_z = SSmapping.areas_in_z
var/z
@@ -137,11 +147,6 @@ GLOBAL_LIST_EMPTY(teleportlocs)
areas_in_z["[z]"] = list()
areas_in_z["[z]"] += src
- return INITIALIZE_HINT_LATELOAD
-
-/area/LateInitialize()
- power_change() // all machines set to current power level, also updates icon
-
/area/Destroy()
if(GLOB.areas_by_type[type] == src)
GLOB.areas_by_type[type] = null
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 48596a0b6d..f2eb23808e 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -6,7 +6,6 @@
var/flags_1 = NONE
var/interaction_flags_atom = NONE
- var/container_type = NONE
var/datum/reagents/reagents = null
//This atom's HUD (med/sec, etc) images. Associative list.
@@ -32,6 +31,8 @@
var/list/filter_data //For handling persistent filters
+ var/datum/component/orbiter/orbiters
+
var/rad_flags = NONE // Will move to flags_1 when i can be arsed to
var/rad_insulation = RAD_NO_INSULATION
@@ -203,16 +204,16 @@
return is_refillable() && is_drainable()
/atom/proc/is_injectable(allowmobs = TRUE)
- return reagents && (container_type & (INJECTABLE | REFILLABLE))
+ return reagents && (reagents.reagents_holder_flags & (INJECTABLE | REFILLABLE))
/atom/proc/is_drawable(allowmobs = TRUE)
- return reagents && (container_type & (DRAWABLE | DRAINABLE))
+ return reagents && (reagents.reagents_holder_flags & (DRAWABLE | DRAINABLE))
/atom/proc/is_refillable()
- return reagents && (container_type & REFILLABLE)
+ return reagents && (reagents.reagents_holder_flags & REFILLABLE)
/atom/proc/is_drainable()
- return reagents && (container_type & DRAINABLE)
+ return reagents && (reagents.reagents_holder_flags & DRAINABLE)
/atom/proc/AllowDrop()
@@ -261,7 +262,7 @@
to_chat(user, desc)
if(reagents)
- if(container_type & TRANSPARENT)
+ if(reagents.reagents_holder_flags & TRANSPARENT)
to_chat(user, "It contains:")
if(reagents.reagent_list.len)
if(user.can_see_reagents()) //Show each individual reagent
@@ -274,7 +275,7 @@
to_chat(user, "[total_volume] units of various reagents")
else
to_chat(user, "Nothing.")
- else if(container_type & AMOUNT_VISIBLE)
+ else if(reagents.reagents_holder_flags & AMOUNT_VISIBLE)
if(reagents.total_volume)
to_chat(user, "It has [reagents.total_volume] unit\s left.")
else
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index e56f6d366c..f88f4f8e41 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -31,6 +31,8 @@
var/atom/movable/pulling
var/grab_state = 0
var/throwforce = 0
+ var/datum/component/orbiter/orbiting
+ var/can_be_z_moved = TRUE
/atom/movable/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list("step_x", "step_y", "step_size")
@@ -295,14 +297,7 @@
if (length(client_mobs_in_contents))
update_parallax_contents()
- if (orbiters)
- for (var/thing in orbiters)
- var/datum/orbit/O = thing
- O.Check()
- if (orbiting)
- orbiting.Check()
-
- return 1
+ return TRUE
/atom/movable/Destroy(force)
QDEL_NULL(proximity_monitor)
@@ -324,6 +319,10 @@
if(pulledby)
pulledby.stop_pulling()
+ if(orbiting)
+ orbiting.end_orbit(src)
+ orbiting = null
+
// Make sure you know what you're doing if you call this, this is intended to only be called by byond directly.
// You probably want CanPass()
/atom/movable/Cross(atom/movable/AM)
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 3af43ffb78..8506a4133a 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -100,7 +100,7 @@
//helper for getting the appropriate health status
/proc/RoundHealth(mob/living/M)
- if(M.stat == DEAD || (M.has_trait(TRAIT_FAKEDEATH)))
+ if(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_FAKEDEATH)))
return "health-100" //what's our health? it doesn't matter, we're dead, or faking
var/maxi_health = M.maxHealth
if(iscarbon(M) && M.health < 0)
@@ -172,7 +172,7 @@
var/image/holder = hud_list[STATUS_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
- if(stat == DEAD || (has_trait(TRAIT_FAKEDEATH)))
+ if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
holder.icon_state = "huddead"
else
holder.icon_state = "hudhealthy"
@@ -182,9 +182,9 @@
var/icon/I = icon(icon, icon_state, dir)
var/virus_threat = check_virus()
holder.pixel_y = I.Height() - world.icon_size
- if(has_trait(TRAIT_XENO_HOST))
+ if(HAS_TRAIT(src, TRAIT_XENO_HOST))
holder.icon_state = "hudxeno"
- else if(stat == DEAD || (has_trait(TRAIT_FAKEDEATH)))
+ else if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
if(tod)
var/tdelta = round(world.time - timeofdeath)
if(tdelta < (DEFIB_TIME_LIMIT * 10))
@@ -242,7 +242,7 @@
var/icon/IC = icon(icon, icon_state, dir)
holder.pixel_y = IC.Height() - world.icon_size
holder.icon_state = "hud_imp_chem"
- if(has_trait(TRAIT_MINDSHIELD))
+ if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
holder = hud_list[IMPLOYAL_HUD]
var/icon/IC = icon(icon, icon_state, dir)
holder.pixel_y = IC.Height() - world.icon_size
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index d6513b5d40..a24d846f15 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -64,7 +64,7 @@ Credit where due:
return FALSE
if(isliving(M))
var/mob/living/L = M
- if(L.has_trait(TRAIT_MINDSHIELD))
+ if(HAS_TRAIT(L, TRAIT_MINDSHIELD))
return FALSE
if(ishuman(M) || isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab) || istype(M, /mob/camera/eminence))
return TRUE
@@ -131,7 +131,7 @@ Credit where due:
config_tag = "clockwork_cult"
antag_flag = ROLE_SERVANT_OF_RATVAR
false_report_weight = 10
- required_players = 30
+ required_players = 35
required_enemies = 3
recommended_enemies = 5
enemy_minimum_age = 7
diff --git a/code/game/gamemodes/clown_ops/clown_ops.dm b/code/game/gamemodes/clown_ops/clown_ops.dm
index 12d3106c8d..a666b57afd 100644
--- a/code/game/gamemodes/clown_ops/clown_ops.dm
+++ b/code/game/gamemodes/clown_ops/clown_ops.dm
@@ -62,5 +62,6 @@
/datum/outfit/syndicate/clownop/leader
name = "Clown Operative Leader - Basic"
id = /obj/item/card/id/syndicate/nuke_leader
+ gloves = /obj/item/clothing/gloves/krav_maga/combatglovesplus
r_hand = /obj/item/nuclear_challenge/clownops
command_radio = TRUE
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index 7b492e3a95..8f091b6372 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -26,7 +26,7 @@
return FALSE
else
return FALSE
- if(M.has_trait(TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || is_servant_of_ratvar(M) || !M.client)
+ if(HAS_TRAIT(M, TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || is_servant_of_ratvar(M) || !M.client)
return FALSE //can't convert machines, shielded, braindead, or ratvar's dogs
return TRUE
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index d76552982c..615d55a818 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -137,6 +137,7 @@
/datum/outfit/syndicate/leader
name = "Syndicate Leader - Basic"
id = /obj/item/card/id/syndicate/nuke_leader
+ gloves = /obj/item/clothing/gloves/krav_maga/combatglovesplus
r_hand = /obj/item/nuclear_challenge
command_radio = TRUE
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 7532d18d06..f6b1def645 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -542,6 +542,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
return checking.researched_nodes.len >= target_amount
/datum/objective/capture
+ var/captured_amount = 0
/datum/objective/capture/proc/gen_amount_goal()
target_amount = rand(5,10)
@@ -549,8 +550,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
return target_amount
/datum/objective/capture/check_completion()//Basically runs through all the mobs in the area to determine how much they are worth.
- var/captured_amount = 0
- var/area/centcom/holding/A = GLOB.areas_by_type[/area/centcom/holding]
+ /*var/area/centcom/holding/A = GLOB.areas_by_type[/area/centcom/holding]
for(var/mob/living/carbon/human/M in A)//Humans.
if(M.stat == DEAD)//Dead folks are worth less.
captured_amount+=0.5
@@ -573,7 +573,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
if(M.stat == DEAD)
captured_amount+=1
continue
- captured_amount+=2
+ captured_amount+=2*/ //Removed in favour of adding points on capture, in energy_net_nets.dm
return captured_amount >= target_amount
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index 6603bb3604..e56495d808 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -124,7 +124,7 @@
/datum/objective_item/steal/plasma/check_special_completion(obj/item/tank/T)
var/target_amount = text2num(name)
var/found_amount = 0
- found_amount += T.air_contents.gases[/datum/gas/plasma] ? T.air_contents.gases[/datum/gas/plasma][MOLES] : 0
+ found_amount += T.air_contents.gases[/datum/gas/plasma]
return found_amount>=target_amount
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index d3b5e53a1b..36a5c6ede4 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -182,11 +182,11 @@
//Get the clone body ready
maim_clone(H)
- H.add_trait(TRAIT_STABLEHEART, "cloning")
- H.add_trait(TRAIT_EMOTEMUTE, "cloning")
- H.add_trait(TRAIT_MUTE, "cloning")
- H.add_trait(TRAIT_NOBREATH, "cloning")
- H.add_trait(TRAIT_NOCRITDAMAGE, "cloning")
+ ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning")
+ ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning")
+ ADD_TRAIT(H, TRAIT_MUTE, "cloning")
+ ADD_TRAIT(H, TRAIT_NOBREATH, "cloning")
+ ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
clonemind.transfer_to(H)
@@ -361,11 +361,11 @@
if(!mob_occupant)
return
- mob_occupant.remove_trait(TRAIT_STABLEHEART, "cloning")
- mob_occupant.remove_trait(TRAIT_EMOTEMUTE, "cloning")
- mob_occupant.remove_trait(TRAIT_MUTE, "cloning")
- mob_occupant.remove_trait(TRAIT_NOCRITDAMAGE, "cloning")
- mob_occupant.remove_trait(TRAIT_NOBREATH, "cloning")
+ REMOVE_TRAIT(mob_occupant, TRAIT_STABLEHEART, "cloning")
+ REMOVE_TRAIT(mob_occupant, TRAIT_EMOTEMUTE, "cloning")
+ REMOVE_TRAIT(mob_occupant, TRAIT_MUTE, "cloning")
+ REMOVE_TRAIT(mob_occupant, TRAIT_NOCRITDAMAGE, "cloning")
+ REMOVE_TRAIT(mob_occupant, TRAIT_NOBREATH, "cloning")
if(grab_ghost_when == CLONER_MATURE_CLONE)
mob_occupant.grab_ghost()
@@ -452,7 +452,7 @@
// brain function, they also have no limbs or internal organs.
- if(!H.has_trait(TRAIT_NODISMEMBER))
+ if(!HAS_TRAIT(H, TRAIT_NODISMEMBER))
var/static/list/zones = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
for(var/zone in zones)
var/obj/item/bodypart/BP = H.get_bodypart(zone)
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 1f262c0979..7f2fef18ac 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -1,3 +1,9 @@
+#define ARCADE_WEIGHT_TRICK 4
+#define ARCADE_WEIGHT_USELESS 2
+#define ARCADE_WEIGHT_RARE 1
+#define ARCADE_WEIGHT_PLUSH 65
+
+
/obj/machinery/computer/arcade
name = "random arcade"
desc = "random arcade machine"
@@ -6,55 +12,65 @@
icon_screen = "invaders"
clockwork = TRUE //it'd look weird
var/list/prizes = list(
- /obj/item/storage/box/snappops = 8,
- /obj/item/toy/talking/AI = 8,
- /obj/item/toy/talking/codex_gigas = 8,
- /obj/item/clothing/under/syndicate/tacticool = 8,
- /obj/item/toy/sword = 8,
- /obj/item/toy/gun = 8,
- /obj/item/gun/ballistic/shotgun/toy/crossbow = 8,
- /obj/item/storage/box/fakesyndiesuit = 8,
- /obj/item/storage/crayons = 8,
- /obj/item/toy/spinningtoy = 8,
- /obj/item/toy/prize/ripley = 4,
- /obj/item/toy/prize/fireripley = 4,
- /obj/item/toy/prize/deathripley = 4,
- /obj/item/toy/prize/gygax = 4,
- /obj/item/toy/prize/durand = 4,
- /obj/item/toy/prize/honk = 4,
- /obj/item/toy/prize/marauder = 4,
- /obj/item/toy/prize/seraph = 4,
- /obj/item/toy/prize/mauler = 4,
- /obj/item/toy/prize/odysseus = 4,
- /obj/item/toy/prize/phazon = 4,
- /obj/item/toy/prize/reticence = 4,
- /obj/item/toy/cards/deck = 8,
- /obj/item/toy/nuke = 8,
- /obj/item/toy/minimeteor = 8,
- /obj/item/toy/redbutton = 8,
- /obj/item/toy/talking/owl = 8,
- /obj/item/toy/talking/griffin = 8,
- /obj/item/coin/antagtoken = 8,
- /obj/item/stack/tile/fakespace/loaded = 8,
- /obj/item/stack/tile/fakepit/loaded = 8,
- /obj/item/toy/toy_xeno = 8,
- /obj/item/storage/box/actionfigure = 4,
- /obj/item/restraints/handcuffs/fake = 8,
- /obj/item/grenade/chem_grenade/glitter/pink = 4,
- /obj/item/grenade/chem_grenade/glitter/blue = 4,
- /obj/item/grenade/chem_grenade/glitter/white = 4,
- /obj/item/toy/eightball = 8,
- /obj/item/toy/windupToolbox = 8,
- /obj/item/toy/clockwork_watch = 8,
- /obj/item/toy/toy_dagger = 8,
- /obj/item/extendohand/acme = 4,
- /obj/item/hot_potato/harmless/toy = 4,
- /obj/item/card/emagfake = 4,
- /obj/item/clothing/shoes/wheelys = 8,
- /obj/item/clothing/shoes/kindleKicks = 8,
- /obj/item/storage/belt/military/snack = 8,
- /obj/item/toy/plush/random = 450
- )//plushies have a 0.6 chance
+ /obj/item/toy/balloon = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/beach_ball = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/cattoy = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/clockwork_watch = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/dummy = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/eightball = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/eightball/haunted = ARCADE_WEIGHT_RARE,
+ /obj/item/storage/box/actionfigure = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/foamblade = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/gun = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/gun/justicar = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/gun/m41 = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/katana = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/minimeteor = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/nuke = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/plush/random = ARCADE_WEIGHT_PLUSH,
+ /obj/item/toy/redbutton = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/spinningtoy = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/sword = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/sword/cx = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/talking/AI = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/talking/codex_gigas = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/talking/griffin = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/talking/owl = ARCADE_WEIGHT_USELESS,
+ /obj/item/toy/toy_dagger = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/toy_xeno = ARCADE_WEIGHT_TRICK,
+ /obj/item/toy/windupToolbox = ARCADE_WEIGHT_TRICK,
+
+ /obj/item/twohanded/dualsaber/toy = ARCADE_WEIGHT_RARE,
+ /mob/living/simple_animal/bot/secbot/grievous/toy = ARCADE_WEIGHT_RARE,
+ /obj/item/clothing/mask/facehugger/toy = ARCADE_WEIGHT_RARE,
+ /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = ARCADE_WEIGHT_TRICK,
+ /obj/item/hot_potato/harmless/toy = ARCADE_WEIGHT_RARE,
+ /obj/item/twohanded/dualsaber/toy = ARCADE_WEIGHT_RARE,
+ /obj/item/twohanded/hypereutactic/toy = ARCADE_WEIGHT_RARE,
+ /obj/item/twohanded/hypereutactic/toy/rainbow = ARCADE_WEIGHT_RARE,
+
+ /obj/item/storage/box/snappops = ARCADE_WEIGHT_TRICK,
+ /obj/item/clothing/under/syndicate/tacticool = ARCADE_WEIGHT_TRICK,
+ /obj/item/gun/ballistic/shotgun/toy/crossbow = ARCADE_WEIGHT_TRICK,
+ /obj/item/storage/box/fakesyndiesuit = ARCADE_WEIGHT_TRICK,
+ /obj/item/storage/crayons = ARCADE_WEIGHT_USELESS,
+ /obj/item/coin/antagtoken = ARCADE_WEIGHT_USELESS,
+ /obj/item/stack/tile/fakespace/loaded = ARCADE_WEIGHT_TRICK,
+ /obj/item/stack/tile/fakepit/loaded = ARCADE_WEIGHT_TRICK,
+ /obj/item/restraints/handcuffs/fake = ARCADE_WEIGHT_TRICK,
+
+ /obj/item/grenade/chem_grenade/glitter/pink = ARCADE_WEIGHT_TRICK,
+ /obj/item/grenade/chem_grenade/glitter/blue = ARCADE_WEIGHT_TRICK,
+ /obj/item/grenade/chem_grenade/glitter/white = ARCADE_WEIGHT_TRICK,
+
+ /obj/item/extendohand/acme = ARCADE_WEIGHT_TRICK,
+ /obj/item/card/emagfake = ARCADE_WEIGHT_TRICK,
+ /obj/item/clothing/shoes/wheelys = ARCADE_WEIGHT_RARE,
+ /obj/item/clothing/shoes/kindleKicks = ARCADE_WEIGHT_RARE,
+ /obj/item/storage/belt/military/snack = ARCADE_WEIGHT_RARE,
+
+ /obj/item/clothing/mask/fakemoustache/italian = ARCADE_WEIGHT_RARE
+ )
light_color = LIGHT_COLOR_GREEN
@@ -74,7 +90,8 @@
/obj/machinery/computer/arcade/proc/prizevend(mob/user)
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "arcade", /datum/mood_event/arcade)
- if(prob(0.0001)) //1 in a million
+
+ if(prob(1) && prob(1) && prob(1)) //Proper 1 in a million
new /obj/item/gun/energy/pulse/prize(src)
SSmedals.UnlockMedal(MEDAL_PULSE, usr.client)
@@ -124,6 +141,8 @@
var/blocked = FALSE //Player cannot attack/heal while set
var/turtle = 0
+ var/turn_speed = 5 //Measured in deciseconds.
+
/obj/machinery/computer/arcade/battle/Reset()
var/name_action
var/name_part1
@@ -172,7 +191,7 @@
if(turtle > 0)
turtle--
- sleep(10)
+ sleep(turn_speed)
enemy_hp -= attackamt
arcade_action(usr)
@@ -185,7 +204,7 @@
updateUsrDialog()
turtle++
- sleep(10)
+ sleep(turn_speed)
player_mp -= pointamt
player_hp += healamt
blocked = TRUE
@@ -202,7 +221,7 @@
turtle--
updateUsrDialog()
- sleep(10)
+ sleep(turn_speed)
arcade_action(usr)
if (href_list["close"])
@@ -211,10 +230,10 @@
else if (href_list["newgame"]) //Reset everything
temp = "New Round"
- player_hp = 30
- player_mp = 10
- enemy_hp = 45
- enemy_mp = 20
+ player_hp = initial(player_hp)
+ player_mp = initial(player_mp)
+ enemy_hp = initial(enemy_hp)
+ enemy_mp = initial(enemy_mp)
gameover = FALSE
turtle = 0
@@ -260,7 +279,7 @@
if (player_mp <= 0)
gameover = TRUE
- sleep(10)
+ sleep(turn_speed)
temp = "You have been drained! GAME OVER"
playsound(loc, 'sound/arcade/lose.ogg', 50, 1, extrarange = -3, falloff = 10)
if(obj_flags & EMAGGED)
diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm
index baa6fa577e..6576f51e46 100644
--- a/code/game/machinery/computer/atmos_control.dm
+++ b/code/game/machinery/computer/atmos_control.dm
@@ -59,8 +59,8 @@
var/total_moles = air_sample.total_moles()
if(total_moles)
for(var/gas_id in air_sample.gases)
- var/gas_name = air_sample.gases[gas_id][GAS_META][META_GAS_NAME]
- signal.data["gases"][gas_name] = air_sample.gases[gas_id][MOLES] / total_moles * 100
+ var/gas_name = GLOB.meta_gas_names[gas_id]
+ signal.data["gases"][gas_name] = air_sample.gases[gas_id] / total_moles * 100
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 00a5c8941d..39d5c3d56f 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -450,7 +450,7 @@
scantemp = "Subject's brain is not responding to scanning stimuli."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
- if((mob_occupant.has_trait(TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
+ if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "Subject no longer contains the fundamental materials required to create a living clone."
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 43f5b96fbd..752765baa1 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -173,14 +173,15 @@
var/obj/machinery/shuttle_manipulator/M = locate() in GLOB.machines
if(M)
SSshuttle.shuttle_purchased = TRUE
- M.unload_preview()
- M.load_template(S)
- M.existing_shuttle = SSshuttle.emergency
- M.action_load(S)
SSshuttle.points -= S.credit_cost
minor_announce("[usr.real_name] has purchased [S.name] for [S.credit_cost] credits." , "Shuttle Purchase")
message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [S.name].")
SSblackbox.record_feedback("text", "shuttle_purchase", 1, "[S.name]")
+ M.unload_preview()
+ M.load_template(S)
+ M.existing_shuttle = SSshuttle.emergency
+ M.action_load(S)
+ message_admins("[S.name] loaded, purchased by [usr]")
else
to_chat(usr, "Something went wrong! The shuttle exchange system seems to be down.")
else
diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index 2980c741be..9d49574317 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -76,7 +76,7 @@
if(connected && connected.is_operational())
if(connected.occupant) //set occupant_status message
viable_occupant = connected.occupant
- if(viable_occupant.has_dna() && !viable_occupant.has_trait(TRAIT_RADIMMUNE) && !viable_occupant.has_trait(TRAIT_NOCLONE) || (connected.scan_level == 3)) //occupant is viable for dna modification
+ if(viable_occupant.has_dna() && !HAS_TRAIT(viable_occupant, TRAIT_RADIMMUNE) && !HAS_TRAIT(viable_occupant, TRAIT_NOCLONE) || (connected.scan_level == 3)) //occupant is viable for dna modification
occupant_status += "[viable_occupant.name] => "
switch(viable_occupant.stat)
if(CONSCIOUS)
@@ -523,7 +523,7 @@
var/mob/living/carbon/viable_occupant = null
if(connected)
viable_occupant = connected.occupant
- if(!istype(viable_occupant) || !viable_occupant.dna || viable_occupant.has_trait(TRAIT_RADIMMUNE) || viable_occupant.has_trait(TRAIT_NOCLONE))
+ if(!istype(viable_occupant) || !viable_occupant.dna || HAS_TRAIT(viable_occupant, TRAIT_RADIMMUNE) || HAS_TRAIT(viable_occupant, TRAIT_NOCLONE))
viable_occupant = null
return viable_occupant
diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm
index 7beb32eebb..1c6d713437 100644
--- a/code/game/machinery/dance_machine.dm
+++ b/code/game/machinery/dance_machine.dm
@@ -214,11 +214,11 @@
sparkles += S
switch(i)
if(1 to 8)
- S.orbit(src, 30, TRUE, 60, 36, TRUE, FALSE)
+ S.orbit(src, 30, TRUE, 60, 36, TRUE)
if(9 to 16)
- S.orbit(src, 62, TRUE, 60, 36, TRUE, FALSE)
+ S.orbit(src, 62, TRUE, 60, 36, TRUE)
if(17 to 24)
- S.orbit(src, 95, TRUE, 60, 36, TRUE, FALSE)
+ S.orbit(src, 95, TRUE, 60, 36, TRUE)
if(25)
S.pixel_y = 7
S.forceMove(get_turf(src))
diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm
index 90a6b07733..7895fb8c9f 100644
--- a/code/game/machinery/dna_scanner.dm
+++ b/code/game/machinery/dna_scanner.dm
@@ -99,7 +99,7 @@
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
if(istype(mob_occupant))
if(locate_computer(/obj/machinery/computer/cloning))
- if(!mob_occupant.suiciding && !(mob_occupant.has_trait(TRAIT_NOCLONE)) && !mob_occupant.hellbound)
+ if(!mob_occupant.suiciding && !(HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && !mob_occupant.hellbound)
mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src)
// DNA manipulators cannot operate on severed heads or brains
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 0183fcecd4..1081cb5fa7 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -763,7 +763,7 @@
if(ishuman(user) && prob(40) && src.density)
var/mob/living/carbon/human/H = user
- if((H.has_trait(TRAIT_DUMB)) && Adjacent(user))
+ if((HAS_TRAIT(H, TRAIT_DUMB)) && Adjacent(user))
playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
if(!istype(H.head, /obj/item/clothing/head/helmet))
H.visible_message("[user] headbutts the airlock.", \
diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm
index 45ac999a6a..e8364d2271 100644
--- a/code/game/machinery/exp_cloner.dm
+++ b/code/game/machinery/exp_cloner.dm
@@ -42,11 +42,11 @@
icon_state = "pod_1"
//Get the clone body ready
maim_clone(H)
- H.add_trait(TRAIT_STABLEHEART, "cloning")
- H.add_trait(TRAIT_EMOTEMUTE, "cloning")
- H.add_trait(TRAIT_MUTE, "cloning")
- H.add_trait(TRAIT_NOBREATH, "cloning")
- H.add_trait(TRAIT_NOCRITDAMAGE, "cloning")
+ ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning")
+ ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning")
+ ADD_TRAIT(H, TRAIT_MUTE, "cloning")
+ ADD_TRAIT(H, TRAIT_NOBREATH, "cloning")
+ ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H)
@@ -268,7 +268,7 @@
scantemp = "Unable to locate valid genetic data."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
- if((mob_occupant.has_trait(TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
+ if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "Subject no longer contains the fundamental materials required to create a living clone."
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm
index 1f40672e05..0042da1c92 100644
--- a/code/game/machinery/harvester.dm
+++ b/code/game/machinery/harvester.dm
@@ -73,7 +73,7 @@
say("Subject is not organic.")
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, 1)
return
- if(!allow_living && !(C.stat == DEAD || C.has_trait(TRAIT_FAKEDEATH))) //I mean, the machines scanners arent advanced enough to tell you're alive
+ if(!allow_living && !(C.stat == DEAD || HAS_TRAIT(C, TRAIT_FAKEDEATH))) //I mean, the machines scanners arent advanced enough to tell you're alive
say("Subject is still alive.")
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, 1)
return
diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm
index 8a0658fd0f..a3250fe1b0 100644
--- a/code/game/machinery/limbgrower.dm
+++ b/code/game/machinery/limbgrower.dm
@@ -10,7 +10,6 @@
icon = 'icons/obj/machines/limbgrower.dmi'
icon_state = "limbgrower_idleoff"
density = TRUE
- container_type = OPENCONTAINER
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 100
@@ -34,7 +33,7 @@
)
/obj/machinery/limbgrower/Initialize()
- create_reagents(100)
+ create_reagents(100, OPENCONTAINER)
stored_research = new /datum/techweb/specialized/autounlocking/limbgrower
. = ..()
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index 911bb76bda..b0204ddeb8 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -485,7 +485,7 @@
threatcount += 4
if(shoot_unloyal)
- if (!perp.has_trait(TRAIT_MINDSHIELD))
+ if (!HAS_TRAIT(perp, TRAIT_MINDSHIELD))
threatcount += 4
return threatcount
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index b84db2ca8d..90166dacf0 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -51,6 +51,7 @@
/obj/machinery/suit_storage_unit/security
suit_type = /obj/item/clothing/suit/space/hardsuit/security
mask_type = /obj/item/clothing/mask/gas/sechailer
+ storage_type = /obj/item/tank/jetpack/oxygen/security
/obj/machinery/suit_storage_unit/hos
suit_type = /obj/item/clothing/suit/space/hardsuit/security/hos
diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm
index 99baad11ae..ba08109427 100644
--- a/code/game/mecha/equipment/tools/medical_tools.dm
+++ b/code/game/mecha/equipment/tools/medical_tools.dm
@@ -257,8 +257,7 @@
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Initialize()
. = ..()
- create_reagents(max_volume)
- reagents.set_reacting(FALSE)
+ create_reagents(max_volume, NO_REACT)
syringes = new
known_reagents = list("epinephrine"="Epinephrine","charcoal"="Charcoal")
processed_reagents = new
@@ -274,7 +273,7 @@
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/critfail()
..()
if(reagents)
- reagents.set_reacting(TRUE)
+ DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/mecha/medical/M)
if(..())
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index 1a3886c3df..80c92c7922 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -421,14 +421,13 @@
if(!istype(T))
return
var/datum/gas_mixture/GM = new
- GM.add_gas(/datum/gas/plasma)
if(prob(10))
- GM.gases[/datum/gas/plasma][MOLES] += 100
+ GM.gases[/datum/gas/plasma] += 100
GM.temperature = 1500+T0C //should be enough to start a fire
T.visible_message("[src] suddenly disgorges a cloud of heated plasma.")
qdel(src)
else
- GM.gases[/datum/gas/plasma][MOLES] += 5
+ GM.gases[/datum/gas/plasma] += 5
GM.temperature = istype(T) ? T.air.return_temperature() : T20C
T.visible_message("[src] suddenly disgorges a cloud of plasma.")
T.assume_air(GM)
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index d5de4a4898..4700dda60d 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -237,9 +237,8 @@
cabin_air = new
cabin_air.temperature = T20C
cabin_air.volume = 200
- cabin_air.add_gases(/datum/gas/oxygen, /datum/gas/nitrogen)
- cabin_air.gases[/datum/gas/oxygen][MOLES] = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature)
- cabin_air.gases[/datum/gas/nitrogen][MOLES] = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature)
+ cabin_air.gases[/datum/gas/oxygen] = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature)
+ cabin_air.gases[/datum/gas/nitrogen] = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature)
return cabin_air
/obj/mecha/proc/add_radio()
@@ -446,13 +445,13 @@
var/mob/living/L = user
if(!Adjacent(target))
if(selected && selected.is_ranged())
- if(L.has_trait(TRAIT_PACIFISM) && selected.harmful)
+ if(HAS_TRAIT(L, TRAIT_PACIFISM) && selected.harmful)
to_chat(user, "You don't want to harm other living beings!")
return
if(selected.action(target,params))
selected.start_cooldown()
else if(selected && selected.is_melee())
- if(isliving(target) && selected.harmful && L.has_trait(TRAIT_PACIFISM))
+ if(isliving(target) && selected.harmful && HAS_TRAIT(L, TRAIT_PACIFISM))
to_chat(user, "You don't want to harm other living beings!")
return
if(selected.action(target,params))
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index 07152b0310..d5aff99f32 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -72,7 +72,7 @@
..()
if(ishuman(O))
var/mob/living/carbon/human/H = O
- if(H.shoes && blood_state && bloodiness && !H.has_trait(TRAIT_LIGHT_STEP))
+ if(H.shoes && blood_state && bloodiness && !HAS_TRAIT(H, TRAIT_LIGHT_STEP))
var/obj/item/clothing/shoes/S = H.shoes
var/add_blood = 0
if(bloodiness >= BLOOD_GAIN_PER_STEP)
diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm
index f1a1655fb4..35f06c2768 100644
--- a/code/game/objects/effects/decals/cleanable/humans.dm
+++ b/code/game/objects/effects/decals/cleanable/humans.dm
@@ -60,7 +60,7 @@
/obj/effect/decal/cleanable/blood/gibs/Crossed(mob/living/L)
if(istype(L) && has_gravity(loc))
- playsound(loc, 'sound/effects/gib_step.ogg', L.has_trait(TRAIT_LIGHT_STEP) ? 20 : 50, 1)
+ playsound(loc, 'sound/effects/gib_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 20 : 50, 1)
. = ..()
/obj/effect/decal/cleanable/blood/gibs/proc/streak(list/directions)
diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm
index 264715e2ac..10ee73915c 100644
--- a/code/game/objects/effects/effect_system/effects_foam.dm
+++ b/code/game/objects/effects/effect_system/effects_foam.dm
@@ -1,347 +1,347 @@
-// Foam
-// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin.
-#define ALUMINUM_FOAM 1
-#define IRON_FOAM 2
-#define RESIN_FOAM 3
-
-
-/obj/effect/particle_effect/foam
- name = "foam"
- icon_state = "foam"
- opacity = 0
- anchored = TRUE
- density = FALSE
- layer = EDGED_TURF_LAYER
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- var/amount = 3
- animate_movement = 0
- var/metal = 0
- var/lifetime = 40
- var/reagent_divisor = 7
- var/static/list/blacklisted_turfs = typecacheof(list(
- /turf/open/space/transit,
- /turf/open/chasm,
- /turf/open/lava))
-
-/obj/effect/particle_effect/foam/firefighting
- name = "firefighting foam"
- lifetime = 20 //doesn't last as long as normal foam
- amount = 0 //no spread
- var/absorbed_plasma = 0
-
-/obj/effect/particle_effect/foam/firefighting/MakeSlippery()
- return
-
-/obj/effect/particle_effect/foam/firefighting/process()
- ..()
-
- var/turf/open/T = get_turf(src)
- var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T)
- if(hotspot && istype(T) && T.air)
- qdel(hotspot)
- var/datum/gas_mixture/G = T.air
- var/plas_amt = min(30,G.gases[/datum/gas/plasma][MOLES]) //Absorb some plasma
- G.gases[/datum/gas/plasma][MOLES] -= plas_amt
- absorbed_plasma += plas_amt
- if(G.temperature > T20C)
- G.temperature = max(G.temperature/2,T20C)
- G.garbage_collect()
- T.air_update_turf()
-
-/obj/effect/particle_effect/foam/firefighting/kill_foam()
- STOP_PROCESSING(SSfastprocess, src)
-
- if(absorbed_plasma)
- var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src))
- if(!P)
- P = new(loc)
- P.reagents.add_reagent("stable_plasma", absorbed_plasma)
-
- flick("[icon_state]-disolve", src)
- QDEL_IN(src, 5)
-
-/obj/effect/particle_effect/foam/firefighting/foam_mob(mob/living/L)
- if(!istype(L))
- return
- L.adjust_fire_stacks(-2)
- L.ExtinguishMob()
-
-/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- return
-
-/obj/effect/particle_effect/foam/metal
- name = "aluminium foam"
- metal = ALUMINUM_FOAM
- icon_state = "mfoam"
-
-/obj/effect/particle_effect/foam/metal/MakeSlippery()
- return
-
-/obj/effect/particle_effect/foam/metal/smart
- name = "smart foam"
-
-/obj/effect/particle_effect/foam/metal/iron
- name = "iron foam"
- metal = IRON_FOAM
-
-/obj/effect/particle_effect/foam/metal/resin
- name = "resin foam"
- metal = RESIN_FOAM
-
-/obj/effect/particle_effect/foam/long_life
- lifetime = 150
-
-/obj/effect/particle_effect/foam/Initialize()
- . = ..()
- MakeSlippery()
- create_reagents(1000) //limited by the size of the reagent holder anyway.
- START_PROCESSING(SSfastprocess, src)
- playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3)
-
-/obj/effect/particle_effect/foam/proc/MakeSlippery()
- AddComponent(/datum/component/slippery, 100)
-
-/obj/effect/particle_effect/foam/Destroy()
- STOP_PROCESSING(SSfastprocess, src)
- return ..()
-
-
-/obj/effect/particle_effect/foam/proc/kill_foam()
- STOP_PROCESSING(SSfastprocess, src)
- switch(metal)
- if(ALUMINUM_FOAM)
- new /obj/structure/foamedmetal(get_turf(src))
- if(IRON_FOAM)
- new /obj/structure/foamedmetal/iron(get_turf(src))
- if(RESIN_FOAM)
- new /obj/structure/foamedmetal/resin(get_turf(src))
- flick("[icon_state]-disolve", src)
- QDEL_IN(src, 5)
-
-/obj/effect/particle_effect/foam/smart/kill_foam() //Smart foam adheres to area borders for walls
- STOP_PROCESSING(SSfastprocess, src)
- if(metal)
- var/turf/T = get_turf(src)
- if(isspaceturf(T)) //Block up any exposed space
- T.PlaceOnTop(/turf/open/floor/plating/foam)
- for(var/direction in GLOB.cardinals)
- var/turf/cardinal_turf = get_step(T, direction)
- if(get_area(cardinal_turf) != get_area(T)) //We're at an area boundary, so let's block off this turf!
- new/obj/structure/foamedmetal(T)
- break
- flick("[icon_state]-disolve", src)
- QDEL_IN(src, 5)
-
-/obj/effect/particle_effect/foam/process()
- lifetime--
- if(lifetime < 1)
- kill_foam()
- return
-
- var/fraction = 1/initial(reagent_divisor)
- for(var/obj/O in range(0,src))
- if(O.type == src.type)
- continue
- if(isturf(O.loc))
- var/turf/T = O.loc
- if(T.intact && O.level == 1) //hidden under the floor
- continue
- if(lifetime % reagent_divisor)
- reagents.reaction(O, VAPOR, fraction)
- var/hit = 0
- for(var/mob/living/L in range(0,src))
- hit += foam_mob(L)
- if(hit)
- lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate.
- var/T = get_turf(src)
- if(lifetime % reagent_divisor)
- reagents.reaction(T, VAPOR, fraction)
-
- if(--amount < 0)
- return
- spread_foam()
-
-/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L)
- if(lifetime<1)
- return 0
- if(!istype(L))
- return 0
- var/fraction = 1/initial(reagent_divisor)
- if(lifetime % reagent_divisor)
- reagents.reaction(L, VAPOR, fraction)
- lifetime--
- return 1
-
-/obj/effect/particle_effect/foam/proc/spread_foam()
- var/turf/t_loc = get_turf(src)
- for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
- var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam!
- if(foundfoam)
- continue
-
- if(is_type_in_typecache(T, blacklisted_turfs))
- continue
-
- for(var/mob/living/L in T)
- foam_mob(L)
- var/obj/effect/particle_effect/foam/F = new src.type(T)
- F.amount = amount
- reagents.copy_to(F, (reagents.total_volume))
- F.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
- F.metal = metal
-
-
-/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated
- kill_foam()
-
-
-/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- return
-
-
-///////////////////////////////////////////////
-//FOAM EFFECT DATUM
-/datum/effect_system/foam_spread
- var/amount = 10 // the size of the foam spread.
- var/obj/chemholder
- effect_type = /obj/effect/particle_effect/foam
- var/metal = 0
-
-
-/datum/effect_system/foam_spread/metal
- effect_type = /obj/effect/particle_effect/foam/metal
-
-
-/datum/effect_system/foam_spread/metal/smart
- effect_type = /obj/effect/particle_effect/foam/smart
-
-
-/datum/effect_system/foam_spread/long
- effect_type = /obj/effect/particle_effect/foam/long_life
-
-/datum/effect_system/foam_spread/New()
- ..()
- chemholder = new /obj()
- var/datum/reagents/R = new/datum/reagents(1000)
- chemholder.reagents = R
- R.my_atom = chemholder
-
-/datum/effect_system/foam_spread/Destroy()
- qdel(chemholder)
- chemholder = null
- return ..()
-
-/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null)
- if(isturf(loca))
- location = loca
- else
- location = get_turf(loca)
-
- amount = round(sqrt(amt / 2), 1)
- carry.copy_to(chemholder, carry.total_volume)
-
-/datum/effect_system/foam_spread/metal/set_up(amt=5, loca, datum/reagents/carry = null, metaltype)
- ..()
- metal = metaltype
-
-/datum/effect_system/foam_spread/start()
- var/obj/effect/particle_effect/foam/F = new effect_type(location)
- var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
- chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount)
- F.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY)
- F.amount = amount
- F.metal = metal
-
-
-//////////////////////////////////////////////////////////
-// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break
-/obj/structure/foamedmetal
- icon = 'icons/effects/effects.dmi'
- icon_state = "metalfoam"
- density = TRUE
- opacity = 1 // changed in New()
- anchored = TRUE
- layer = EDGED_TURF_LAYER
- resistance_flags = FIRE_PROOF | ACID_PROOF
- name = "foamed metal"
- desc = "A lightweight foamed metal wall."
- gender = PLURAL
- max_integrity = 20
- CanAtmosPass = ATMOS_PASS_DENSITY
-
-/obj/structure/foamedmetal/Initialize()
- . = ..()
- air_update_turf(1)
-
-/obj/structure/foamedmetal/Move()
- var/turf/T = loc
- . = ..()
- move_update_air(T)
-
-/obj/structure/foamedmetal/attack_paw(mob/user)
- return attack_hand(user)
-
-/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
- playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
-
-/obj/structure/foamedmetal/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- user.changeNext_move(CLICK_CD_MELEE)
- user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
- to_chat(user, "You hit [src] but bounce off it!")
- playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
-
-/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target)
- return !density
-
-/obj/structure/foamedmetal/iron
- max_integrity = 50
- icon_state = "ironfoam"
-
-//Atmos Backpack Resin, transparent, prevents atmos and filters the air
-/obj/structure/foamedmetal/resin
- name = "\improper ATMOS Resin"
- desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature."
- opacity = FALSE
- icon_state = "atmos_resin"
- alpha = 120
- max_integrity = 10
-
-/obj/structure/foamedmetal/resin/Initialize()
- . = ..()
- if(isopenturf(loc))
- var/turf/open/O = loc
- O.ClearWet()
- if(O.air)
- var/datum/gas_mixture/G = O.air
- G.temperature = 293.15
- for(var/obj/effect/hotspot/H in O)
- qdel(H)
- var/list/G_gases = G.gases
- for(var/I in G_gases)
- if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen)
- continue
- G_gases[I][MOLES] = 0
- G.garbage_collect()
- O.air_update_turf()
- for(var/obj/machinery/atmospherics/components/unary/U in O)
- if(!U.welded)
- U.welded = TRUE
- U.update_icon()
- U.visible_message("[U] sealed shut!")
- for(var/mob/living/L in O)
- L.ExtinguishMob()
- for(var/obj/item/Item in O)
- Item.extinguish()
-
-/obj/structure/foamedmetal/resin/CanPass(atom/movable/mover, turf/target)
- if(istype(mover) && (mover.pass_flags & PASSGLASS))
- return TRUE
- . = ..()
-
-#undef ALUMINUM_FOAM
-#undef IRON_FOAM
-#undef RESIN_FOAM
+// Foam
+// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin.
+#define ALUMINUM_FOAM 1
+#define IRON_FOAM 2
+#define RESIN_FOAM 3
+
+
+/obj/effect/particle_effect/foam
+ name = "foam"
+ icon_state = "foam"
+ opacity = 0
+ anchored = TRUE
+ density = FALSE
+ layer = EDGED_TURF_LAYER
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ var/amount = 3
+ animate_movement = 0
+ var/metal = 0
+ var/lifetime = 40
+ var/reagent_divisor = 7
+ var/static/list/blacklisted_turfs = typecacheof(list(
+ /turf/open/space/transit,
+ /turf/open/chasm,
+ /turf/open/lava))
+
+/obj/effect/particle_effect/foam/firefighting
+ name = "firefighting foam"
+ lifetime = 20 //doesn't last as long as normal foam
+ amount = 0 //no spread
+ var/absorbed_plasma = 0
+
+/obj/effect/particle_effect/foam/firefighting/MakeSlippery()
+ return
+
+/obj/effect/particle_effect/foam/firefighting/process()
+ ..()
+
+ var/turf/open/T = get_turf(src)
+ var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T)
+ if(hotspot && istype(T) && T.air)
+ qdel(hotspot)
+ var/datum/gas_mixture/G = T.air
+ var/plas_amt = min(30,G.gases[/datum/gas/plasma]) //Absorb some plasma
+ G.gases[/datum/gas/plasma] -= plas_amt
+ absorbed_plasma += plas_amt
+ if(G.temperature > T20C)
+ G.temperature = max(G.temperature/2,T20C)
+ GAS_GARBAGE_COLLECT(G.gases)
+ T.air_update_turf()
+
+/obj/effect/particle_effect/foam/firefighting/kill_foam()
+ STOP_PROCESSING(SSfastprocess, src)
+
+ if(absorbed_plasma)
+ var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src))
+ if(!P)
+ P = new(loc)
+ P.reagents.add_reagent("stable_plasma", absorbed_plasma)
+
+ flick("[icon_state]-disolve", src)
+ QDEL_IN(src, 5)
+
+/obj/effect/particle_effect/foam/firefighting/foam_mob(mob/living/L)
+ if(!istype(L))
+ return
+ L.adjust_fire_stacks(-2)
+ L.ExtinguishMob()
+
+/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ return
+
+/obj/effect/particle_effect/foam/metal
+ name = "aluminium foam"
+ metal = ALUMINUM_FOAM
+ icon_state = "mfoam"
+
+/obj/effect/particle_effect/foam/metal/MakeSlippery()
+ return
+
+/obj/effect/particle_effect/foam/metal/smart
+ name = "smart foam"
+
+/obj/effect/particle_effect/foam/metal/iron
+ name = "iron foam"
+ metal = IRON_FOAM
+
+/obj/effect/particle_effect/foam/metal/resin
+ name = "resin foam"
+ metal = RESIN_FOAM
+
+/obj/effect/particle_effect/foam/long_life
+ lifetime = 150
+
+/obj/effect/particle_effect/foam/Initialize()
+ . = ..()
+ MakeSlippery()
+ create_reagents(1000) //limited by the size of the reagent holder anyway.
+ START_PROCESSING(SSfastprocess, src)
+ playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3)
+
+/obj/effect/particle_effect/foam/proc/MakeSlippery()
+ AddComponent(/datum/component/slippery, 100)
+
+/obj/effect/particle_effect/foam/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+
+/obj/effect/particle_effect/foam/proc/kill_foam()
+ STOP_PROCESSING(SSfastprocess, src)
+ switch(metal)
+ if(ALUMINUM_FOAM)
+ new /obj/structure/foamedmetal(get_turf(src))
+ if(IRON_FOAM)
+ new /obj/structure/foamedmetal/iron(get_turf(src))
+ if(RESIN_FOAM)
+ new /obj/structure/foamedmetal/resin(get_turf(src))
+ flick("[icon_state]-disolve", src)
+ QDEL_IN(src, 5)
+
+/obj/effect/particle_effect/foam/smart/kill_foam() //Smart foam adheres to area borders for walls
+ STOP_PROCESSING(SSfastprocess, src)
+ if(metal)
+ var/turf/T = get_turf(src)
+ if(isspaceturf(T)) //Block up any exposed space
+ T.PlaceOnTop(/turf/open/floor/plating/foam)
+ for(var/direction in GLOB.cardinals)
+ var/turf/cardinal_turf = get_step(T, direction)
+ if(get_area(cardinal_turf) != get_area(T)) //We're at an area boundary, so let's block off this turf!
+ new/obj/structure/foamedmetal(T)
+ break
+ flick("[icon_state]-disolve", src)
+ QDEL_IN(src, 5)
+
+/obj/effect/particle_effect/foam/process()
+ lifetime--
+ if(lifetime < 1)
+ kill_foam()
+ return
+
+ var/fraction = 1/initial(reagent_divisor)
+ for(var/obj/O in range(0,src))
+ if(O.type == src.type)
+ continue
+ if(isturf(O.loc))
+ var/turf/T = O.loc
+ if(T.intact && O.level == 1) //hidden under the floor
+ continue
+ if(lifetime % reagent_divisor)
+ reagents.reaction(O, VAPOR, fraction)
+ var/hit = 0
+ for(var/mob/living/L in range(0,src))
+ hit += foam_mob(L)
+ if(hit)
+ lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate.
+ var/T = get_turf(src)
+ if(lifetime % reagent_divisor)
+ reagents.reaction(T, VAPOR, fraction)
+
+ if(--amount < 0)
+ return
+ spread_foam()
+
+/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L)
+ if(lifetime<1)
+ return 0
+ if(!istype(L))
+ return 0
+ var/fraction = 1/initial(reagent_divisor)
+ if(lifetime % reagent_divisor)
+ reagents.reaction(L, VAPOR, fraction)
+ lifetime--
+ return 1
+
+/obj/effect/particle_effect/foam/proc/spread_foam()
+ var/turf/t_loc = get_turf(src)
+ for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
+ var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam!
+ if(foundfoam)
+ continue
+
+ if(is_type_in_typecache(T, blacklisted_turfs))
+ continue
+
+ for(var/mob/living/L in T)
+ foam_mob(L)
+ var/obj/effect/particle_effect/foam/F = new src.type(T)
+ F.amount = amount
+ reagents.copy_to(F, (reagents.total_volume))
+ F.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
+ F.metal = metal
+
+
+/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated
+ kill_foam()
+
+
+/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ return
+
+
+///////////////////////////////////////////////
+//FOAM EFFECT DATUM
+/datum/effect_system/foam_spread
+ var/amount = 10 // the size of the foam spread.
+ var/obj/chemholder
+ effect_type = /obj/effect/particle_effect/foam
+ var/metal = 0
+
+
+/datum/effect_system/foam_spread/metal
+ effect_type = /obj/effect/particle_effect/foam/metal
+
+
+/datum/effect_system/foam_spread/metal/smart
+ effect_type = /obj/effect/particle_effect/foam/smart
+
+
+/datum/effect_system/foam_spread/long
+ effect_type = /obj/effect/particle_effect/foam/long_life
+
+/datum/effect_system/foam_spread/New()
+ ..()
+ chemholder = new /obj()
+ var/datum/reagents/R = new/datum/reagents(1000)
+ chemholder.reagents = R
+ R.my_atom = chemholder
+
+/datum/effect_system/foam_spread/Destroy()
+ qdel(chemholder)
+ chemholder = null
+ return ..()
+
+/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null)
+ if(isturf(loca))
+ location = loca
+ else
+ location = get_turf(loca)
+
+ amount = round(sqrt(amt / 2), 1)
+ carry.copy_to(chemholder, carry.total_volume)
+
+/datum/effect_system/foam_spread/metal/set_up(amt=5, loca, datum/reagents/carry = null, metaltype)
+ ..()
+ metal = metaltype
+
+/datum/effect_system/foam_spread/start()
+ var/obj/effect/particle_effect/foam/F = new effect_type(location)
+ var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
+ chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount)
+ F.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY)
+ F.amount = amount
+ F.metal = metal
+
+
+//////////////////////////////////////////////////////////
+// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break
+/obj/structure/foamedmetal
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "metalfoam"
+ density = TRUE
+ opacity = 1 // changed in New()
+ anchored = TRUE
+ layer = EDGED_TURF_LAYER
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ name = "foamed metal"
+ desc = "A lightweight foamed metal wall."
+ gender = PLURAL
+ max_integrity = 20
+ CanAtmosPass = ATMOS_PASS_DENSITY
+
+/obj/structure/foamedmetal/Initialize()
+ . = ..()
+ air_update_turf(1)
+
+/obj/structure/foamedmetal/Move()
+ var/turf/T = loc
+ . = ..()
+ move_update_air(T)
+
+/obj/structure/foamedmetal/attack_paw(mob/user)
+ return attack_hand(user)
+
+/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
+ playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
+
+/obj/structure/foamedmetal/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ user.changeNext_move(CLICK_CD_MELEE)
+ user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
+ to_chat(user, "You hit [src] but bounce off it!")
+ playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
+
+/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target)
+ return !density
+
+/obj/structure/foamedmetal/iron
+ max_integrity = 50
+ icon_state = "ironfoam"
+
+//Atmos Backpack Resin, transparent, prevents atmos and filters the air
+/obj/structure/foamedmetal/resin
+ name = "\improper ATMOS Resin"
+ desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature."
+ opacity = FALSE
+ icon_state = "atmos_resin"
+ alpha = 120
+ max_integrity = 10
+
+/obj/structure/foamedmetal/resin/Initialize()
+ . = ..()
+ if(isopenturf(loc))
+ var/turf/open/O = loc
+ O.ClearWet()
+ if(O.air)
+ var/datum/gas_mixture/G = O.air
+ G.temperature = 293.15
+ for(var/obj/effect/hotspot/H in O)
+ qdel(H)
+ var/list/G_gases = G.gases
+ for(var/I in G_gases)
+ if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen)
+ continue
+ G_gases[I] = 0
+ GAS_GARBAGE_COLLECT(G.gases)
+ O.air_update_turf()
+ for(var/obj/machinery/atmospherics/components/unary/U in O)
+ if(!U.welded)
+ U.welded = TRUE
+ U.update_icon()
+ U.visible_message("[U] sealed shut!")
+ for(var/mob/living/L in O)
+ L.ExtinguishMob()
+ for(var/obj/item/Item in O)
+ Item.extinguish()
+
+/obj/structure/foamedmetal/resin/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover) && (mover.pass_flags & PASSGLASS))
+ return TRUE
+ . = ..()
+
+#undef ALUMINUM_FOAM
+#undef IRON_FOAM
+#undef RESIN_FOAM
diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm
index e8e833890b..79deac475b 100644
--- a/code/game/objects/effects/effect_system/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/effects_smoke.dm
@@ -1,329 +1,328 @@
-/////////////////////////////////////////////
-//// SMOKE SYSTEMS
-/////////////////////////////////////////////
-
-/obj/effect/particle_effect/smoke
- name = "smoke"
- icon = 'icons/effects/96x96.dmi'
- icon_state = "smoke"
- pixel_x = -32
- pixel_y = -32
- opacity = 0
- layer = FLY_LAYER
- anchored = TRUE
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- animate_movement = 0
- var/amount = 4
- var/lifetime = 5
- var/opaque = 1 //whether the smoke can block the view when in enough amount
-
-
-/obj/effect/particle_effect/smoke/proc/fade_out(frames = 16)
- if(alpha == 0) //Handle already transparent case
- return
- if(frames == 0)
- frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame".
- var/step = alpha / frames
- for(var/i = 0, i < frames, i++)
- alpha -= step
- if(alpha < 160)
- set_opacity(0) //if we were blocking view, we aren't now because we're fading out
- stoplag()
-
-/obj/effect/particle_effect/smoke/Initialize()
- . = ..()
- create_reagents(500)
- START_PROCESSING(SSobj, src)
-
-
-/obj/effect/particle_effect/smoke/Destroy()
- STOP_PROCESSING(SSobj, src)
- return ..()
-
-/obj/effect/particle_effect/smoke/proc/kill_smoke()
- STOP_PROCESSING(SSobj, src)
- INVOKE_ASYNC(src, .proc/fade_out)
- QDEL_IN(src, 10)
-
-/obj/effect/particle_effect/smoke/process()
- lifetime--
- if(lifetime < 1)
- kill_smoke()
- return 0
- for(var/mob/living/L in range(0,src))
- smoke_mob(L)
- return 1
-
-/obj/effect/particle_effect/smoke/proc/smoke_mob(mob/living/carbon/C)
- if(!istype(C))
- return 0
- if(lifetime<1)
- return 0
- if(C.internal != null || C.has_smoke_protection())
- return 0
- if(C.smoke_delay)
- return 0
- C.smoke_delay++
- addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10)
- return 1
-
-/obj/effect/particle_effect/smoke/proc/remove_smoke_delay(mob/living/carbon/C)
- if(C)
- C.smoke_delay = 0
-
-/obj/effect/particle_effect/smoke/proc/spread_smoke()
- var/turf/t_loc = get_turf(src)
- if(!t_loc)
- return
- var/list/newsmokes = list()
- for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
- var/obj/effect/particle_effect/smoke/foundsmoke = locate() in T //Don't spread smoke where there's already smoke!
- if(foundsmoke)
- continue
- for(var/mob/living/L in T)
- smoke_mob(L)
- var/obj/effect/particle_effect/smoke/S = new type(T)
- reagents.copy_to(S, reagents.total_volume)
- S.setDir(pick(GLOB.cardinals))
- S.amount = amount-1
- S.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
- S.lifetime = lifetime
- if(S.amount>0)
- if(opaque)
- S.set_opacity(TRUE)
- newsmokes.Add(S)
-
- if(newsmokes.len)
- spawn(1) //the smoke spreads rapidly but not instantly
- for(var/obj/effect/particle_effect/smoke/SM in newsmokes)
- SM.spread_smoke()
-
-
-/datum/effect_system/smoke_spread
- var/amount = 10
- effect_type = /obj/effect/particle_effect/smoke
-
-/datum/effect_system/smoke_spread/set_up(radius = 5, loca)
- if(isturf(loca))
- location = loca
- else
- location = get_turf(loca)
- amount = radius
-
-/datum/effect_system/smoke_spread/start()
- if(holder)
- location = get_turf(holder)
- var/obj/effect/particle_effect/smoke/S = new effect_type(location)
- S.amount = amount
- if(S.amount)
- S.spread_smoke()
-
-
-/////////////////////////////////////////////
-// Bad smoke
-/////////////////////////////////////////////
-
-/obj/effect/particle_effect/smoke/bad
- lifetime = 8
-
-/obj/effect/particle_effect/smoke/bad/smoke_mob(mob/living/carbon/M)
- if(..())
- M.drop_all_held_items()
- M.adjustOxyLoss(1)
- M.emote("cough")
- return 1
-
-/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, turf/target)
- if(istype(mover, /obj/item/projectile/beam))
- var/obj/item/projectile/beam/B = mover
- B.damage = (B.damage/2)
- return 1
-
-
-
-/datum/effect_system/smoke_spread/bad
- effect_type = /obj/effect/particle_effect/smoke/bad
-
-/////////////////////////////////////////////
-// Nanofrost smoke
-/////////////////////////////////////////////
-
-/obj/effect/particle_effect/smoke/freezing
- name = "nanofrost smoke"
- color = "#B2FFFF"
- opaque = 0
-
-/datum/effect_system/smoke_spread/freezing
- effect_type = /obj/effect/particle_effect/smoke/freezing
- var/blast = 0
- var/temperature = 2
- var/weldvents = TRUE
- var/distcheck = TRUE
-
-/datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A)
- if(isopenturf(A))
- var/turf/open/T = A
- if(T.air)
- var/datum/gas_mixture/G = T.air
- if(!distcheck || get_dist(T, location) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air
- G.temperature = temperature
- T.air_update_turf()
- for(var/obj/effect/hotspot/H in T)
- qdel(H)
- var/list/G_gases = G.gases
- if(G_gases[/datum/gas/plasma])
- G.assert_gas(/datum/gas/nitrogen)
- G_gases[/datum/gas/nitrogen][MOLES] += (G_gases[/datum/gas/plasma][MOLES])
- G_gases[/datum/gas/plasma][MOLES] = 0
- G.garbage_collect()
- if (weldvents)
- for(var/obj/machinery/atmospherics/components/unary/U in T)
- if(!isnull(U.welded) && !U.welded) //must be an unwelded vent pump or vent scrubber.
- U.welded = TRUE
- U.update_icon()
- U.visible_message("[U] was frozen shut!")
- for(var/mob/living/L in T)
- L.ExtinguishMob()
- for(var/obj/item/Item in T)
- Item.extinguish()
-
-/datum/effect_system/smoke_spread/freezing/set_up(radius = 5, loca, blast_radius = 0)
- ..()
- blast = blast_radius
-
-/datum/effect_system/smoke_spread/freezing/start()
- if(blast)
- for(var/turf/T in RANGE_TURFS(blast, location))
- Chilled(T)
- ..()
-
-/datum/effect_system/smoke_spread/freezing/decon
- temperature = 293.15
- distcheck = FALSE
- weldvents = FALSE
-
-
-/////////////////////////////////////////////
-// Sleep smoke
-/////////////////////////////////////////////
-
-/obj/effect/particle_effect/smoke/sleeping
- color = "#9C3636"
- lifetime = 10
-
-/obj/effect/particle_effect/smoke/sleeping/smoke_mob(mob/living/carbon/M)
- if(..())
- M.Sleeping(200)
- M.emote("cough")
- return 1
-
-/datum/effect_system/smoke_spread/sleeping
- effect_type = /obj/effect/particle_effect/smoke/sleeping
-
-/////////////////////////////////////////////
-// Chem smoke
-/////////////////////////////////////////////
-
-/obj/effect/particle_effect/smoke/chem
- lifetime = 10
-
-
-/obj/effect/particle_effect/smoke/chem/process()
- if(..())
- var/turf/T = get_turf(src)
- var/fraction = 1/initial(lifetime)
- for(var/atom/movable/AM in T)
- if(AM.type == src.type)
- continue
- if(T.intact && AM.level == 1) //hidden under the floor
- continue
- reagents.reaction(AM, TOUCH, fraction)
-
- reagents.reaction(T, TOUCH, fraction)
- return 1
-
-/obj/effect/particle_effect/smoke/chem/smoke_mob(mob/living/carbon/M)
- if(lifetime<1)
- return 0
- if(!istype(M))
- return 0
- var/mob/living/carbon/C = M
- if(C.internal != null || C.has_smoke_protection())
- return 0
- var/fraction = 1/initial(lifetime)
- reagents.copy_to(C, fraction*reagents.total_volume)
- reagents.reaction(M, INGEST, fraction)
- return 1
-
-
-
-/datum/effect_system/smoke_spread/chem
- var/obj/chemholder
- effect_type = /obj/effect/particle_effect/smoke/chem
-
-/datum/effect_system/smoke_spread/chem/New()
- ..()
- chemholder = new /obj()
- var/datum/reagents/R = new/datum/reagents(500)
- chemholder.reagents = R
- R.my_atom = chemholder
-
-/datum/effect_system/smoke_spread/chem/Destroy()
- qdel(chemholder)
- chemholder = null
- return ..()
-
-/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, radius = 1, loca, silent = FALSE)
- if(isturf(loca))
- location = loca
- else
- location = get_turf(loca)
- amount = radius
- carry.copy_to(chemholder, carry.total_volume)
-
- if(!silent)
- var/contained = ""
- for(var/reagent in carry.reagent_list)
- contained += " [reagent] "
- if(contained)
- contained = "\[[contained]\]"
-
- var/where = "[AREACOORD(location)]"
- if(carry.my_atom.fingerprintslast)
- var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast)
- var/more = ""
- if(M)
- more = "[ADMIN_LOOKUPFLW(M)] "
- message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. Key: [more ? more : carry.my_atom.fingerprintslast].")
- log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last touched by [carry.my_atom.fingerprintslast].")
- else
- message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. No associated key.")
- log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
-
-
-/datum/effect_system/smoke_spread/chem/start()
- var/mixcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
- if(holder)
- location = get_turf(holder)
- var/obj/effect/particle_effect/smoke/chem/S = new effect_type(location)
-
- if(chemholder.reagents.total_volume > 1) // can't split 1 very well
- chemholder.reagents.copy_to(S, chemholder.reagents.total_volume)
-
- if(mixcolor)
- S.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with
- S.amount = amount
- if(S.amount)
- S.spread_smoke() //calling process right now so the smoke immediately attacks mobs.
-
-
-/////////////////////////////////////////////
-// Transparent smoke
-/////////////////////////////////////////////
-
-//Same as the base type, but the smoke produced is not opaque
-/datum/effect_system/smoke_spread/transparent
- effect_type = /obj/effect/particle_effect/smoke/transparent
-
-/obj/effect/particle_effect/smoke/transparent
- opaque = FALSE
+/////////////////////////////////////////////
+//// SMOKE SYSTEMS
+/////////////////////////////////////////////
+
+/obj/effect/particle_effect/smoke
+ name = "smoke"
+ icon = 'icons/effects/96x96.dmi'
+ icon_state = "smoke"
+ pixel_x = -32
+ pixel_y = -32
+ opacity = 0
+ layer = FLY_LAYER
+ anchored = TRUE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ animate_movement = 0
+ var/amount = 4
+ var/lifetime = 5
+ var/opaque = 1 //whether the smoke can block the view when in enough amount
+
+
+/obj/effect/particle_effect/smoke/proc/fade_out(frames = 16)
+ if(alpha == 0) //Handle already transparent case
+ return
+ if(frames == 0)
+ frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame".
+ var/step = alpha / frames
+ for(var/i = 0, i < frames, i++)
+ alpha -= step
+ if(alpha < 160)
+ set_opacity(0) //if we were blocking view, we aren't now because we're fading out
+ stoplag()
+
+/obj/effect/particle_effect/smoke/Initialize()
+ . = ..()
+ create_reagents(500)
+ START_PROCESSING(SSobj, src)
+
+
+/obj/effect/particle_effect/smoke/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/effect/particle_effect/smoke/proc/kill_smoke()
+ STOP_PROCESSING(SSobj, src)
+ INVOKE_ASYNC(src, .proc/fade_out)
+ QDEL_IN(src, 10)
+
+/obj/effect/particle_effect/smoke/process()
+ lifetime--
+ if(lifetime < 1)
+ kill_smoke()
+ return 0
+ for(var/mob/living/L in range(0,src))
+ smoke_mob(L)
+ return 1
+
+/obj/effect/particle_effect/smoke/proc/smoke_mob(mob/living/carbon/C)
+ if(!istype(C))
+ return 0
+ if(lifetime<1)
+ return 0
+ if(C.internal != null || C.has_smoke_protection())
+ return 0
+ if(C.smoke_delay)
+ return 0
+ C.smoke_delay++
+ addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10)
+ return 1
+
+/obj/effect/particle_effect/smoke/proc/remove_smoke_delay(mob/living/carbon/C)
+ if(C)
+ C.smoke_delay = 0
+
+/obj/effect/particle_effect/smoke/proc/spread_smoke()
+ var/turf/t_loc = get_turf(src)
+ if(!t_loc)
+ return
+ var/list/newsmokes = list()
+ for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
+ var/obj/effect/particle_effect/smoke/foundsmoke = locate() in T //Don't spread smoke where there's already smoke!
+ if(foundsmoke)
+ continue
+ for(var/mob/living/L in T)
+ smoke_mob(L)
+ var/obj/effect/particle_effect/smoke/S = new type(T)
+ reagents.copy_to(S, reagents.total_volume)
+ S.setDir(pick(GLOB.cardinals))
+ S.amount = amount-1
+ S.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
+ S.lifetime = lifetime
+ if(S.amount>0)
+ if(opaque)
+ S.set_opacity(TRUE)
+ newsmokes.Add(S)
+
+ if(newsmokes.len)
+ spawn(1) //the smoke spreads rapidly but not instantly
+ for(var/obj/effect/particle_effect/smoke/SM in newsmokes)
+ SM.spread_smoke()
+
+
+/datum/effect_system/smoke_spread
+ var/amount = 10
+ effect_type = /obj/effect/particle_effect/smoke
+
+/datum/effect_system/smoke_spread/set_up(radius = 5, loca)
+ if(isturf(loca))
+ location = loca
+ else
+ location = get_turf(loca)
+ amount = radius
+
+/datum/effect_system/smoke_spread/start()
+ if(holder)
+ location = get_turf(holder)
+ var/obj/effect/particle_effect/smoke/S = new effect_type(location)
+ S.amount = amount
+ if(S.amount)
+ S.spread_smoke()
+
+
+/////////////////////////////////////////////
+// Bad smoke
+/////////////////////////////////////////////
+
+/obj/effect/particle_effect/smoke/bad
+ lifetime = 8
+
+/obj/effect/particle_effect/smoke/bad/smoke_mob(mob/living/carbon/M)
+ if(..())
+ M.drop_all_held_items()
+ M.adjustOxyLoss(1)
+ M.emote("cough")
+ return 1
+
+/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover, /obj/item/projectile/beam))
+ var/obj/item/projectile/beam/B = mover
+ B.damage = (B.damage/2)
+ return 1
+
+
+
+/datum/effect_system/smoke_spread/bad
+ effect_type = /obj/effect/particle_effect/smoke/bad
+
+/////////////////////////////////////////////
+// Nanofrost smoke
+/////////////////////////////////////////////
+
+/obj/effect/particle_effect/smoke/freezing
+ name = "nanofrost smoke"
+ color = "#B2FFFF"
+ opaque = 0
+
+/datum/effect_system/smoke_spread/freezing
+ effect_type = /obj/effect/particle_effect/smoke/freezing
+ var/blast = 0
+ var/temperature = 2
+ var/weldvents = TRUE
+ var/distcheck = TRUE
+
+/datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A)
+ if(isopenturf(A))
+ var/turf/open/T = A
+ if(T.air)
+ var/datum/gas_mixture/G = T.air
+ if(!distcheck || get_dist(T, location) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air
+ G.temperature = temperature
+ T.air_update_turf()
+ for(var/obj/effect/hotspot/H in T)
+ qdel(H)
+ var/list/G_gases = G.gases
+ if(G_gases[/datum/gas/plasma])
+ G_gases[/datum/gas/nitrogen] += (G_gases[/datum/gas/plasma])
+ G_gases[/datum/gas/plasma] = 0
+ GAS_GARBAGE_COLLECT(G.gases)
+ if (weldvents)
+ for(var/obj/machinery/atmospherics/components/unary/U in T)
+ if(!isnull(U.welded) && !U.welded) //must be an unwelded vent pump or vent scrubber.
+ U.welded = TRUE
+ U.update_icon()
+ U.visible_message("[U] was frozen shut!")
+ for(var/mob/living/L in T)
+ L.ExtinguishMob()
+ for(var/obj/item/Item in T)
+ Item.extinguish()
+
+/datum/effect_system/smoke_spread/freezing/set_up(radius = 5, loca, blast_radius = 0)
+ ..()
+ blast = blast_radius
+
+/datum/effect_system/smoke_spread/freezing/start()
+ if(blast)
+ for(var/turf/T in RANGE_TURFS(blast, location))
+ Chilled(T)
+ ..()
+
+/datum/effect_system/smoke_spread/freezing/decon
+ temperature = 293.15
+ distcheck = FALSE
+ weldvents = FALSE
+
+
+/////////////////////////////////////////////
+// Sleep smoke
+/////////////////////////////////////////////
+
+/obj/effect/particle_effect/smoke/sleeping
+ color = "#9C3636"
+ lifetime = 10
+
+/obj/effect/particle_effect/smoke/sleeping/smoke_mob(mob/living/carbon/M)
+ if(..())
+ M.Sleeping(200)
+ M.emote("cough")
+ return 1
+
+/datum/effect_system/smoke_spread/sleeping
+ effect_type = /obj/effect/particle_effect/smoke/sleeping
+
+/////////////////////////////////////////////
+// Chem smoke
+/////////////////////////////////////////////
+
+/obj/effect/particle_effect/smoke/chem
+ lifetime = 10
+
+
+/obj/effect/particle_effect/smoke/chem/process()
+ if(..())
+ var/turf/T = get_turf(src)
+ var/fraction = 1/initial(lifetime)
+ for(var/atom/movable/AM in T)
+ if(AM.type == src.type)
+ continue
+ if(T.intact && AM.level == 1) //hidden under the floor
+ continue
+ reagents.reaction(AM, TOUCH, fraction)
+
+ reagents.reaction(T, TOUCH, fraction)
+ return 1
+
+/obj/effect/particle_effect/smoke/chem/smoke_mob(mob/living/carbon/M)
+ if(lifetime<1)
+ return 0
+ if(!istype(M))
+ return 0
+ var/mob/living/carbon/C = M
+ if(C.internal != null || C.has_smoke_protection())
+ return 0
+ var/fraction = 1/initial(lifetime)
+ reagents.copy_to(C, fraction*reagents.total_volume)
+ reagents.reaction(M, INGEST, fraction)
+ return 1
+
+
+
+/datum/effect_system/smoke_spread/chem
+ var/obj/chemholder
+ effect_type = /obj/effect/particle_effect/smoke/chem
+
+/datum/effect_system/smoke_spread/chem/New()
+ ..()
+ chemholder = new /obj()
+ var/datum/reagents/R = new/datum/reagents(500)
+ chemholder.reagents = R
+ R.my_atom = chemholder
+
+/datum/effect_system/smoke_spread/chem/Destroy()
+ qdel(chemholder)
+ chemholder = null
+ return ..()
+
+/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, radius = 1, loca, silent = FALSE)
+ if(isturf(loca))
+ location = loca
+ else
+ location = get_turf(loca)
+ amount = radius
+ carry.copy_to(chemholder, carry.total_volume)
+
+ if(!silent)
+ var/contained = ""
+ for(var/reagent in carry.reagent_list)
+ contained += " [reagent] "
+ if(contained)
+ contained = "\[[contained]\]"
+
+ var/where = "[AREACOORD(location)]"
+ if(carry.my_atom.fingerprintslast)
+ var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast)
+ var/more = ""
+ if(M)
+ more = "[ADMIN_LOOKUPFLW(M)] "
+ message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. Key: [more ? more : carry.my_atom.fingerprintslast].")
+ log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last touched by [carry.my_atom.fingerprintslast].")
+ else
+ message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. No associated key.")
+ log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
+
+
+/datum/effect_system/smoke_spread/chem/start()
+ var/mixcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
+ if(holder)
+ location = get_turf(holder)
+ var/obj/effect/particle_effect/smoke/chem/S = new effect_type(location)
+
+ if(chemholder.reagents.total_volume > 1) // can't split 1 very well
+ chemholder.reagents.copy_to(S, chemholder.reagents.total_volume)
+
+ if(mixcolor)
+ S.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with
+ S.amount = amount
+ if(S.amount)
+ S.spread_smoke() //calling process right now so the smoke immediately attacks mobs.
+
+
+/////////////////////////////////////////////
+// Transparent smoke
+/////////////////////////////////////////////
+
+//Same as the base type, but the smoke produced is not opaque
+/datum/effect_system/smoke_spread/transparent
+ effect_type = /obj/effect/particle_effect/smoke/transparent
+
+/obj/effect/particle_effect/smoke/transparent
+ opaque = FALSE
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index 12a72685bb..7e8094c9e7 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -170,7 +170,7 @@
if(!victim.client || !istype(victim))
return
to_chat(victim, "You feel fast!")
- victim.add_trait(TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
+ ADD_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
sleep(duration)
- victim.remove_trait(TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
+ REMOVE_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
to_chat(victim, "You slow down.")
diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm
index b1bb3e6b4d..65395d534a 100644
--- a/code/game/objects/effects/spawners/bombspawner.dm
+++ b/code/game/objects/effects/spawners/bombspawner.dm
@@ -1,6 +1,6 @@
#define CELSIUS_TO_KELVIN(T_K) ((T_K) + T0C)
-#define OPTIMAL_TEMP_K_PLA_BURN_SCALE(PRESSURE_P,PRESSURE_O,TEMP_O) (((PRESSURE_P) * GLOB.meta_gas_info[/datum/gas/plasma][META_GAS_SPECIFIC_HEAT]) / (((PRESSURE_P) * GLOB.meta_gas_info[/datum/gas/plasma][META_GAS_SPECIFIC_HEAT] + (PRESSURE_O) * GLOB.meta_gas_info[/datum/gas/oxygen][META_GAS_SPECIFIC_HEAT]) / PLASMA_UPPER_TEMPERATURE - (PRESSURE_O) * GLOB.meta_gas_info[/datum/gas/oxygen][META_GAS_SPECIFIC_HEAT] / CELSIUS_TO_KELVIN(TEMP_O)))
+#define OPTIMAL_TEMP_K_PLA_BURN_SCALE(PRESSURE_P,PRESSURE_O,TEMP_O) (((PRESSURE_P) * GLOB.meta_gas_specific_heats[/datum/gas/plasma]) / (((PRESSURE_P) * GLOB.meta_gas_specific_heats[/datum/gas/plasma] + (PRESSURE_O) * GLOB.meta_gas_specific_heats[/datum/gas/oxygen]) / PLASMA_UPPER_TEMPERATURE - (PRESSURE_O) * GLOB.meta_gas_specific_heats[/datum/gas/oxygen] / CELSIUS_TO_KELVIN(TEMP_O)))
#define OPTIMAL_TEMP_K_PLA_BURN_RATIO(PRESSURE_P,PRESSURE_O,TEMP_O) (CELSIUS_TO_KELVIN(TEMP_O) * PLASMA_OXYGEN_FULLBURN * (PRESSURE_P) / (PRESSURE_O))
/obj/effect/spawner/newbomb
@@ -19,12 +19,10 @@
var/obj/item/tank/internals/plasma/PT = new(V)
var/obj/item/tank/internals/oxygen/OT = new(V)
- PT.air_contents.assert_gas(/datum/gas/plasma)
- PT.air_contents.gases[/datum/gas/plasma][MOLES] = pressure_p*PT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_p))
+ PT.air_contents.gases[/datum/gas/plasma] = pressure_p*PT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_p))
PT.air_contents.temperature = CELSIUS_TO_KELVIN(temp_p)
- OT.air_contents.assert_gas(/datum/gas/oxygen)
- OT.air_contents.gases[/datum/gas/oxygen][MOLES] = pressure_o*OT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_o))
+ OT.air_contents.gases[/datum/gas/oxygen] = pressure_o*OT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_o))
OT.air_contents.temperature = CELSIUS_TO_KELVIN(temp_o)
V.tank_one = PT
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 9314faab27..3fbbab087f 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -109,6 +109,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
+
/obj/item/Initialize()
materials = typelist("materials", materials)
@@ -256,7 +257,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
can_handle_hot = TRUE
else if(C.gloves && (C.gloves.max_heat_protection_temperature > 360))
can_handle_hot = TRUE
- else if(C.has_trait(TRAIT_RESISTHEAT) || C.has_trait(TRAIT_RESISTHEATHANDS))
+ else if(HAS_TRAIT(C, TRAIT_RESISTHEAT) || HAS_TRAIT(C, TRAIT_RESISTHEATHANDS))
can_handle_hot = TRUE
if(can_handle_hot)
@@ -449,10 +450,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return 0
/obj/item/proc/eyestab(mob/living/carbon/M, mob/living/carbon/user)
- if(user.has_trait(TRAIT_PACIFISM))
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "You don't want to harm [M]!")
return
- if(user.has_trait(TRAIT_CLUMSY) && prob(50))
+ if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
M = user
var/is_human_victim = 0
var/obj/item/bodypart/affecting = M.get_bodypart(BODY_ZONE_HEAD)
@@ -523,7 +524,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.adjust_blurriness(15)
if(M.stat != DEAD)
to_chat(M, "Your eyes start to bleed profusely!")
- if(!(M.has_trait(TRAIT_BLIND) || M.has_trait(TRAIT_NEARSIGHT)))
+ if(!(HAS_TRAIT(M, TRAIT_BLIND) || HAS_TRAIT(M, TRAIT_NEARSIGHT)))
to_chat(M, "You become nearsighted!")
M.become_nearsighted(EYE_DAMAGE)
if(prob(50))
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index 7881c277ff..38d64be99c 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -161,13 +161,18 @@ RLD
user.visible_message("[user] sets the RCD to 'Wall' and points it down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide..")
return (BRUTELOSS)
-/obj/item/construction/rcd/verb/toggle_window_type()
- set name = "Toggle Window Type"
+/obj/item/construction/rcd/verb/toggle_window_type_verb()
+ set name = "RCD : Toggle Window Type"
set category = "Object"
- set src in usr // What does this do?
+ set src in view(1)
+ if(!usr.canUseTopic(src, BE_CLOSE))
+ return
+
+ toggle_window_type(usr)
+
+/obj/item/construction/rcd/proc/toggle_window_type(mob/user)
var/window_type_name
-
if (window_type == /obj/structure/window/fulltile)
window_type = /obj/structure/window/reinforced/fulltile
window_type_name = "reinforced glass"
@@ -175,17 +180,14 @@ RLD
window_type = /obj/structure/window/fulltile
window_type_name = "glass"
- to_chat(usr, "You change \the [src]'s window mode to [window_type_name].")
+ to_chat(user, "You change \the [src]'s window mode to [window_type_name].")
-/obj/item/construction/rcd/verb/change_airlock_access()
- set name = "Change Airlock Access"
- set category = "Object"
- set src in usr
+/obj/item/construction/rcd/verb/change_airlock_access(mob/user)
- if (!ishuman(usr) && !usr.has_unlimited_silicon_privilege)
- return ..(usr)
+ if (!ishuman(user) && !user.has_unlimited_silicon_privilege)
+ return
- var/t1 = text("")
+ var/t1 = ""
if(use_one_access)
@@ -216,24 +218,23 @@ RLD
t1 += "
According to \the [src], you are now in \"[html_encode(A.name)]\".
" . += "" @@ -140,12 +140,10 @@ legend = FALSE -/obj/item/areaeditor/proc/get_area() - var/turf/T = get_turf(usr) - var/area/A = T.loc - return A -/obj/item/areaeditor/proc/get_area_type(area/A = get_area()) +/obj/item/areaeditor/proc/get_area_type(area/A) + if(!A) + A = get_area(usr) if(A.outdoors) return AREA_SPACE var/list/SPECIALS = list( @@ -183,7 +181,7 @@ return "" /obj/item/areaeditor/proc/edit_area() - var/area/A = get_area() + var/area/A = get_area(usr) var/prevname = "[A.name]" var/str = stripped_input(usr,"New area name:", "Area Creation", "", MAX_NAME_LEN) if(!str || !length(str) || str==prevname) //cancel diff --git a/code/game/objects/items/body_egg.dm b/code/game/objects/items/body_egg.dm index a8f5894b7c..80fc0f43fd 100644 --- a/code/game/objects/items/body_egg.dm +++ b/code/game/objects/items/body_egg.dm @@ -16,7 +16,7 @@ /obj/item/organ/body_egg/Insert(var/mob/living/carbon/M, special = 0) ..() - owner.add_trait(TRAIT_XENO_HOST, TRAIT_GENERIC) + ADD_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC) START_PROCESSING(SSobj, src) owner.med_hud_set_status() INVOKE_ASYNC(src, .proc/AddInfectionImages, owner) @@ -24,7 +24,7 @@ /obj/item/organ/body_egg/Remove(var/mob/living/carbon/M, special = 0) STOP_PROCESSING(SSobj, src) if(owner) - owner.remove_trait(TRAIT_XENO_HOST, TRAIT_GENERIC) + REMOVE_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC) owner.med_hud_set_status() INVOKE_ASYNC(src, .proc/RemoveInfectionImages, owner) ..() diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm index f7c37715aa..344e7c5472 100644 --- a/code/game/objects/items/chrono_eraser.dm +++ b/code/game/objects/items/chrono_eraser.dm @@ -248,9 +248,8 @@ /obj/effect/chrono_field/return_air() //we always have nominal air and temperature var/datum/gas_mixture/GM = new - GM.add_gases(/datum/gas/oxygen, /datum/gas/nitrogen) - GM.gases[/datum/gas/oxygen][MOLES] = MOLES_O2STANDARD - GM.gases[/datum/gas/nitrogen][MOLES] = MOLES_N2STANDARD + GM.gases[/datum/gas/oxygen] = MOLES_O2STANDARD + GM.gases[/datum/gas/nitrogen] = MOLES_N2STANDARD GM.temperature = T20C return GM diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 1ad7974fc1..d64f5b57b8 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -102,7 +102,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM icon_state = "cigoff" throw_speed = 0.5 item_state = "cigoff" - container_type = INJECTABLE w_class = WEIGHT_CLASS_TINY body_parts_covered = null grind_results = list() @@ -123,8 +122,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/Initialize() . = ..() - create_reagents(chem_volume) - reagents.set_reacting(FALSE) // so it doesn't react until you light it + create_reagents(chem_volume, INJECTABLE | NO_REACT) // so it doesn't react until you light it if(list_reagents) reagents.add_reagent_list(list_reagents) if(starts_lit) @@ -184,7 +182,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM qdel(src) return // allowing reagents to react after being lit - reagents.set_reacting(TRUE) + DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) reagents.handle_reactions() icon_state = icon_on item_state = icon_on @@ -325,7 +323,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM list_reagents = list("space_drugs" = 15, "lipolicide" = 35) /obj/item/clothing/mask/cigarette/rollie/mindbreaker - list_reagents = list("mindbreaker" = 35, "lipolicide" = 15) + list_reagents = list("mindbreaker" = 35, "lipolicide" = 15) /obj/item/cigbutt/roach name = "roach" @@ -720,8 +718,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/vape/Initialize(mapload, param_color) . = ..() - create_reagents(chem_volume) - reagents.set_reacting(FALSE) // so it doesn't react until you light it + DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) reagents.add_reagent("nicotine", 50) if(!icon_state) if(!param_color) @@ -790,13 +787,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(reagents.total_volume > 0) to_chat(user, "You empty [src] of all reagents.") reagents.clear_reagents() - return /obj/item/clothing/mask/vape/equipped(mob/user, slot) if(slot == SLOT_WEAR_MASK) if(!screw) to_chat(user, "You start puffing on the vape.") - reagents.set_reacting(TRUE) + DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) START_PROCESSING(SSobj, src) else //it will not start if the vape is opened. to_chat(user, "You need to close the cap first!") @@ -804,7 +800,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/vape/dropped(mob/user) var/mob/living/carbon/C = user if(C.get_item_by_slot(SLOT_WEAR_MASK) == src) - reagents.set_reacting(FALSE) + ENABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) STOP_PROCESSING(SSobj, src) /obj/item/clothing/mask/vape/proc/hand_reagents()//had to rename to avoid duplicate error diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 30089f298f..99d6c874e8 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -254,7 +254,7 @@ cost = 0 if(ishuman(user)) var/mob/living/carbon/human/H = user - if (H.has_trait(TRAIT_TAGGER)) + if (HAS_TRAIT(H, TRAIT_TAGGER)) cost *= 0.5 var/charges_used = use_charges(user, cost) if(!charges_used) diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index ba4a0ffae8..55e75b3992 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -444,7 +444,7 @@ /obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/H) var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain) - return (!H.suiciding && !(H.has_trait(TRAIT_NOCLONE)) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain) + return (!H.suiciding && !(HAS_TRAIT(H, TRAIT_NOCLONE)) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain) /obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H) if(req_defib) @@ -585,7 +585,7 @@ shock_touching(30, H) var/failed - if (H.suiciding || (H.has_trait(TRAIT_NOCLONE))) + if (H.suiciding || (HAS_TRAIT(H, TRAIT_NOCLONE))) failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Recovery of patient impossible. Further attempts futile." else if (H.hellbound) failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's soul appears to be on another plane of existence. Further attempts futile." diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 3b55bf093f..79c90b2a2f 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -221,12 +221,16 @@ GLOBAL_LIST_EMPTY(PDAs) overlay.icon_state = "[current_overlays[PDA_OVERLAY_PAI]][pai.pai ? "" : "_off"]" add_overlay(new /mutable_appearance(overlay)) -/obj/item/pda/MouseDrop(obj/over_object, src_location, over_location) +/obj/item/pda/MouseDrop(mob/over, src_location, over_location) var/mob/M = usr - if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src)) + if((M == over) && usr.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return attack_self(M) return ..() +/obj/item/pda/attack_self_tk(mob/user) + to_chat(user, "The PDA's capacitive touch screen doesn't seem to respond!") + return + /obj/item/pda/interact(mob/user) if(!user.IsAdvancedToolUser()) to_chat(user, "You don't have the dexterity to do this!") @@ -408,9 +412,9 @@ GLOBAL_LIST_EMPTY(PDAs) if (total_moles) for(var/id in env_gases) - var/gas_level = env_gases[id][MOLES]/total_moles + var/gas_level = env_gases[id]/total_moles if(gas_level > 0) - dat += "[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_level*100, 0.01)]%It really is that easy! Good luck! - +