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/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index dcd2c47cb2..60c91e51bb 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -515,10 +515,13 @@
/turf/closed/wall,
/area/security/main)
"abq" = (
-/turf/closed/wall,
+/turf/closed/wall/r_wall,
/area/crew_quarters/heads/hos)
"abr" = (
/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/door/poddoor/preopen{
+ id = "hos"
+ },
/turf/open/floor/plating,
/area/crew_quarters/heads/hos)
"abs" = (
@@ -846,8 +849,13 @@
},
/obj/structure/table/wood,
/obj/item/reagent_containers/food/drinks/bottle/vodka/badminka,
-/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass,
-/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass,
+/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass{
+ pixel_x = -5;
+ pixel_y = 5
+ },
+/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass{
+ pixel_x = -5
+ },
/turf/open/floor/carpet,
/area/crew_quarters/heads/hos)
"abX" = (
@@ -1449,6 +1457,9 @@
"adm" = (
/obj/structure/disposalpipe/segment,
/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/door/poddoor/preopen{
+ id = "hos"
+ },
/turf/open/floor/plating,
/area/crew_quarters/heads/hos)
"adn" = (
@@ -1673,6 +1684,12 @@
"adM" = (
/obj/structure/cable{
icon_state = "4-8"
+ },
+/obj/machinery/button/door{
+ id = "hos";
+ name = "HoS Office Shutters";
+ pixel_y = -25;
+
},
/turf/open/floor/carpet,
/area/crew_quarters/heads/hos)
@@ -2053,6 +2070,9 @@
"aex" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/spawner/structure/window/reinforced,
+/obj/machinery/door/poddoor/preopen{
+ id = "hos"
+ },
/turf/open/floor/plating,
/area/crew_quarters/heads/hos)
"aey" = (
@@ -11691,7 +11711,7 @@
/area/maintenance/port/fore)
"aAW" = (
/obj/structure/rack,
-/obj/item/tank/jetpack/carbondioxide,
+/obj/item/tank/jetpack/carbondioxide/eva,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
@@ -11815,7 +11835,7 @@
/obj/machinery/light{
dir = 8
},
-/obj/item/tank/jetpack/carbondioxide,
+/obj/item/tank/jetpack/carbondioxide/eva,
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
@@ -56882,12 +56902,6 @@
/obj/item/pen,
/turf/open/floor/plasteel/white,
/area/science/circuit)
-"ium" = (
-/mob/living/simple_animal/bot/cleanbot{
- name = "C.L.E.A.N."
- },
-/turf/open/floor/plasteel/white,
-/area/medical/medbay/central)
"izv" = (
/obj/machinery/vending/clothing,
/obj/machinery/light/small{
@@ -57122,6 +57136,12 @@
},
/turf/open/floor/plating,
/area/construction/mining/aux_base)
+"lKX" = (
+/mob/living/simple_animal/bot/cleanbot{
+ name = "C.L.E.A.N."
+ },
+/turf/open/floor/plasteel/white,
+/area/medical/medbay/central)
"lMg" = (
/obj/effect/turf_decal/stripes/line{
dir = 9
@@ -88468,7 +88488,7 @@ aaa
aaf
aaf
aaa
-abp
+adR
abP
aco
acO
@@ -88982,7 +89002,7 @@ aaa
aaa
aaf
aaa
-abp
+adR
abO
acq
acq
@@ -89496,15 +89516,15 @@ aaa
aaa
aaa
aaf
-abp
+adR
abR
abP
abP
abP
abP
-abp
-abp
-abp
+adR
+adR
+adR
agA
afU
ahF
@@ -94188,7 +94208,7 @@ blm
bmL
boi
bpw
-ium
+lKX
bsx
btX
bvj
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index c8e551b9fe..402633f42b 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -79373,12 +79373,12 @@
},
/obj/structure/window/reinforced,
/obj/structure/rack,
-/obj/item/tank/jetpack/carbondioxide{
+/obj/item/tank/jetpack/carbondioxide/eva{
pixel_x = 4;
pixel_y = -1
},
-/obj/item/tank/jetpack/carbondioxide,
-/obj/item/tank/jetpack/carbondioxide{
+/obj/item/tank/jetpack/carbondioxide/eva,
+/obj/item/tank/jetpack/carbondioxide/eva{
pixel_x = -4;
pixel_y = 1
},
@@ -80186,11 +80186,11 @@
/area/engine/storage)
"cEi" = (
/obj/structure/table/reinforced,
-/obj/item/tank/jetpack/carbondioxide{
+/obj/item/tank/jetpack/carbondioxide/eva{
pixel_x = 3;
pixel_y = 3
},
-/obj/item/tank/jetpack/carbondioxide,
+/obj/item/tank/jetpack/carbondioxide/eva,
/obj/machinery/power/apc{
dir = 4;
name = "Engineering Storage APC";
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 78ffa3881c..1bcb5c20a8 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -47699,12 +47699,12 @@
},
/obj/structure/window/reinforced,
/obj/structure/rack,
-/obj/item/tank/jetpack/carbondioxide{
+/obj/item/tank/jetpack/carbondioxide/eva{
pixel_x = 4;
pixel_y = -1
},
-/obj/item/tank/jetpack/carbondioxide,
-/obj/item/tank/jetpack/carbondioxide{
+/obj/item/tank/jetpack/carbondioxide/eva,
+/obj/item/tank/jetpack/carbondioxide/eva{
pixel_x = -4;
pixel_y = 1
},
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index f9792a736e..7935a2a3f9 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -16464,8 +16464,8 @@
/area/storage/eva)
"aNt" = (
/obj/structure/rack,
-/obj/item/tank/jetpack/carbondioxide,
-/obj/item/tank/jetpack/carbondioxide{
+/obj/item/tank/jetpack/carbondioxide/eva,
+/obj/item/tank/jetpack/carbondioxide/eva{
pixel_x = -4;
pixel_y = 1
},
@@ -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 3841a086e9..3b67625191 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -136,6 +136,7 @@
#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_KEY_CHANGE "mob_key_change" //from base of /mob/transfer_key()
+#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 be58b64f41..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"
@@ -262,6 +266,15 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
GLOBAL_LIST_INIT(pda_styles, list(MONO, VT, ORBITRON, SHARE))
+//pda icon reskins
+#define PDA_SKIN_CLASSIC "Classic"
+#define PDA_SKIN_ALT "Holographic"
+#define PDA_SKIN_RUGGED "Rugged"
+#define PDA_SKIN_MODERN "Modern"
+
+GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_SKIN_ALT = 'icons/obj/pda_alt.dmi',
+ PDA_SKIN_RUGGED = 'icons/obj/pda_rugged.dmi', PDA_SKIN_MODERN = 'icons/obj/pda_modern.dmi'))
+
//Color Defines
#define OOC_COLOR "#002eb8"
#define AOOC_COLOR "#b8002e"
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/reactions.dm b/code/__DEFINES/reactions.dm
index b72a14468f..1c36120a0c 100644
--- a/code/__DEFINES/reactions.dm
+++ b/code/__DEFINES/reactions.dm
@@ -23,6 +23,11 @@
#define STIMULUM_ABSOLUTE_DROP 0.00000335
#define REACTION_OPPRESSION_THRESHOLD 5
#define NOBLIUM_FORMATION_ENERGY 2e9 //1 Mole of Noblium takes the planck energy to condense.
+//Research point amounts
+#define NOBLIUM_RESEARCH_AMOUNT 1000
+#define BZ_RESEARCH_AMOUNT 150
+#define MIASMA_RESEARCH_AMOUNT 160
+#define STIMULUM_RESEARCH_AMOUNT 50
//Plasma fusion properties
#define FUSION_ENERGY_THRESHOLD 3e9 //Amount of energy it takes to start a fusion reaction
#define FUSION_TEMPERATURE_THRESHOLD 1000 //Temperature required to start a fusion reaction
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..d490a76611 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,15 @@
#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"
+#define TRAIT_STRONG_GRABBER "strong_grabber"
+#define TRAIT_CALCIUM_HEALER "calcium_healer"
+ //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 +138,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 +165,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 133d7eefc1..8f206f6765 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/mobs.dm b/code/__HELPERS/mobs.dm
index 51c814a5f9..9eb5400c52 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -170,7 +170,7 @@
"balls_amount" = 2,
"balls_sack_size" = BALLS_SACK_SIZE_DEF,
"balls_size" = BALLS_SIZE_DEF,
- "balls_shape" = "Pair",
+ "balls_shape" = "Single",
"balls_cum_rate" = CUM_RATE,
"balls_cum_mult" = CUM_RATE_MULT,
"balls_efficiency" = CUM_EFFICIENCY,
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..0bd99825a2 100644
--- a/code/_globalvars/lists/maintenance_loot.dm
+++ b/code/_globalvars/lists/maintenance_loot.dm
@@ -44,6 +44,7 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/item/flashlight = 4,
/obj/item/flashlight/pen = 1,
/obj/item/flashlight/glowstick/random = 4,
+ /obj/effect/spawner/lootdrop/mre = 3,
/obj/item/multitool = 2,
/obj/item/radio/off = 2,
/obj/item/t_scanner = 5,
@@ -109,5 +110,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/_globalvars/misc.dm b/code/_globalvars/misc.dm
index fa0ecf117d..e7b2ae6cbe 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -18,3 +18,12 @@ GLOBAL_LIST_EMPTY(powernets)
GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes
GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
+
+// All religion stuff
+GLOBAL_VAR(religion)
+GLOBAL_VAR(deity)
+GLOBAL_VAR(bible_name)
+GLOBAL_VAR(bible_icon_state)
+GLOBAL_VAR(bible_item_state)
+GLOBAL_VAR(holy_weapon_type)
+GLOBAL_VAR(holy_armor_type)
\ No newline at end of file
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 0c01468712..7a495b95e7 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -23,6 +23,9 @@
return
next_click = world.time + 1
+ if(!can_interact_with(A))
+ return
+
if(multicam_on)
var/turf/T = get_turf(A)
if(T)
@@ -60,7 +63,6 @@
controlled_mech.click_action(A, src, params) //Override AI normal click behavior.
return
- return
if(modifiers["shift"])
ShiftClickOn(A)
return
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/religion.dm b/code/controllers/subsystem/religion.dm
deleted file mode 100644
index 1c3cd76da4..0000000000
--- a/code/controllers/subsystem/religion.dm
+++ /dev/null
@@ -1,11 +0,0 @@
-SUBSYSTEM_DEF(religion)
- name = "Religion"
- flags = SS_NO_FIRE|SS_NO_INIT
-
- var/religion
- var/deity
- var/bible_name
- var/bible_icon_state
- var/bible_item_state
- var/holy_weapon_type
- var/holy_armor_type
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 6a2f8682a5..59893e1cf4 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.dm b/code/datums/martial.dm
index 2bc01e0bf6..ae8f92a342 100644
--- a/code/datums/martial.dm
+++ b/code/datums/martial.dm
@@ -5,6 +5,7 @@
var/current_target
var/datum/martial_art/base // The permanent style. This will be null unless the martial art is temporary
var/deflection_chance = 0 //Chance to deflect projectiles
+ var/reroute_deflection = FALSE //Delete the bullet, or actually deflect it in some direction?
var/block_chance = 0 //Chance to block melee attacks using items while on throw mode.
var/restraining = 0 //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not
var/help_verb
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..5f19c37b99 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -7,6 +7,7 @@
/datum/martial_art/the_sleeping_carp
name = "The Sleeping Carp"
deflection_chance = 100
+ reroute_deflection = TRUE
no_guns = TRUE
allow_temp_override = FALSE
help_verb = /mob/living/carbon/human/proc/sleeping_carp_help
@@ -179,7 +180,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..b2b03fb56b 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -117,6 +117,16 @@
description = "I'm missing my family heirloom...\n"
mood_change = -4
+/datum/mood_event/loud_gong
+ description = "That loud gong noise really hurt my ears!\n"
+ mood_change = -3
+ timeout = 1200
+
+/datum/mood_event/spooked
+ description = "The rattling of those bones...It still haunts me.\n"
+ mood_change = -4
+ timeout = 2400
+
//These are unused so far but I want to remember them to use them later
/datum/mood_event/cloned_corpse
description = "I recently saw my own corpse...\n"
@@ -125,3 +135,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/datums/wires/microwave.dm b/code/datums/wires/microwave.dm
new file mode 100644
index 0000000000..8c74abfa46
--- /dev/null
+++ b/code/datums/wires/microwave.dm
@@ -0,0 +1,27 @@
+/datum/wires/microwave
+ holder_type = /obj/machinery/microwave
+ proper_name = "Microwave"
+
+/datum/wires/microwave/New(atom/holder)
+ wires = list(
+ WIRE_ACTIVATE
+ )
+ ..()
+
+/datum/wires/microwave/interactable(mob/user)
+ . = FALSE
+ var/obj/machinery/microwave/M = holder
+ if(M.panel_open)
+ . = TRUE
+
+/datum/wires/microwave/on_pulse(wire)
+ var/obj/machinery/microwave/M = holder
+ switch(wire)
+ if(WIRE_ACTIVATE)
+ M.cook()
+
+/datum/wires/microwave/on_cut(wire, mend)
+ var/obj/machinery/microwave/M = holder
+ switch(wire)
+ if(WIRE_ACTIVATE)
+ M.wire_disabled = !mend
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/PDApainter.dm b/code/game/machinery/PDApainter.dm
index 53aebc53dc..45a3b59661 100644
--- a/code/game/machinery/PDApainter.dm
+++ b/code/game/machinery/PDApainter.dm
@@ -35,15 +35,14 @@
/obj/item/pda/clear,
/obj/item/pda/syndicate,
/obj/item/pda/chameleon,
- /obj/item/pda/chameleon/broken)
+ /obj/item/pda/chameleon/broken,
+ /obj/item/pda/lieutenant)
- for(var/P in typesof(/obj/item/pda) - blocked)
- var/obj/item/pda/D = new P
-
- //D.name = "PDA Style [colorlist.len+1]" //Gotta set the name, otherwise it all comes up as "PDA"
- D.name = D.icon_state //PDAs don't have unique names, but using the sprite names works.
-
- src.colorlist += D
+ for(var/A in typesof(/obj/item/pda) - blocked)
+ var/obj/item/pda/P = A
+ var/PDA_name = initial(P.name)
+ colorlist += PDA_name
+ colorlist[PDA_name] = list(initial(P.icon_state), initial(P.desc), initial(P.overlays_offsets), initial(P.overlays_icons))
/obj/machinery/pdapainter/Destroy()
QDEL_NULL(storedpda)
@@ -108,22 +107,20 @@
if(.)
return
- if(storedpda)
- var/obj/item/pda/P
- P = input(user, "Select your color!", "PDA Painting") as null|anything in colorlist
- if(!P)
- return
- if(!in_range(src, user))
- return
- if(!storedpda)//is the pda still there?
- return
- storedpda.icon_state = P.icon_state
- storedpda.desc = P.desc
- ejectpda()
-
- else
+ if(!storedpda)
to_chat(user, "[src] is empty.")
-
+ return
+ var/choice = input(user, "Select the new skin!", "PDA Painting") as null|anything in colorlist
+ if(!choice || !storedpda || !in_range(src, user))
+ return
+ var/list/P = colorlist[choice]
+ storedpda.icon_state = P[1]
+ storedpda.desc = P[2]
+ storedpda.overlays_offsets = P[3]
+ storedpda.overlays_icons = P[4]
+ storedpda.set_new_overlays()
+ storedpda.update_icon()
+ ejectpda()
/obj/machinery/pdapainter/verb/ejectpda()
set name = "Eject PDA"
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index ac975c2ffd..7da6cec9cd 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -168,9 +168,11 @@ Class Procs:
update_icon()
updateUsrDialog()
-/obj/machinery/proc/dropContents()
+/obj/machinery/proc/dropContents(list/subset = null)
var/turf/T = get_turf(src)
for(var/atom/movable/A in contents)
+ if(subset && !(A in subset))
+ continue
A.forceMove(T)
if(isliving(A))
var/mob/living/L = A
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..8d0cfb95e8 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,64 @@
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,
+
+ /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
@@ -66,20 +81,32 @@
// If it's a generic arcade machine, pick a random arcade
// circuit board for it and make the new machine
if(!circuit)
- var/choice = pick(subtypesof(/obj/item/circuitboard/computer/arcade))
- var/obj/item/circuitboard/CB = new choice()
+ var/list/gameodds = list(/obj/item/circuitboard/computer/arcade/battle = 33,
+ /obj/item/circuitboard/computer/arcade/orion_trail = 33,
+ /obj/item/circuitboard/computer/arcade/minesweeper = 33,
+ /obj/item/circuitboard/computer/arcade/amputation = 2)
+ var/thegame = pickweight(gameodds)
+ var/obj/item/circuitboard/CB = new thegame()
new CB.build_path(loc, CB)
return INITIALIZE_HINT_QDEL
Reset()
-/obj/machinery/computer/arcade/proc/prizevend(mob/user)
+/obj/machinery/computer/arcade/proc/prizevend(mob/user, list/rarity_classes)
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)
if(!contents.len)
- var/prizeselect = pickweight(prizes)
+ var/list/toy_raffle
+ if(rarity_classes)
+ for(var/A in prizes)
+ if(prizes[A] in rarity_classes)
+ LAZYSET(toy_raffle, A, prizes[A])
+ if(!toy_raffle)
+ toy_raffle = prizes
+ var/prizeselect = pickweight(toy_raffle)
new prizeselect(src)
var/atom/movable/prize = pick(contents)
@@ -104,1020 +131,3 @@
empprize = pickweight(prizes)
new empprize(loc)
explosion(loc, -1, 0, 1+num_of_prizes, flame_range = 1+num_of_prizes)
-
-
-// ** BATTLE ** //
-
-
-/obj/machinery/computer/arcade/battle
- name = "arcade machine"
- desc = "Does not support Pinball."
- icon_state = "arcade"
- circuit = /obj/item/circuitboard/computer/arcade/battle
- var/enemy_name = "Space Villain"
- var/temp = "Winners don't use space drugs" //Temporary message, for attack messages, etc
- var/player_hp = 30 //Player health/attack points
- var/player_mp = 10
- var/enemy_hp = 45 //Enemy health/attack points
- var/enemy_mp = 20
- var/gameover = FALSE
- var/blocked = FALSE //Player cannot attack/heal while set
- var/turtle = 0
-
-/obj/machinery/computer/arcade/battle/Reset()
- var/name_action
- var/name_part1
- var/name_part2
-
- name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ", "Pwn ", "Own ", "Ban ")
-
- name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ")
- name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "slime", "Griefer", "ERPer", "Lizard Man", "Unicorn", "Bloopers")
-
- enemy_name = replacetext((name_part1 + name_part2), "the ", "")
- name = (name_action + name_part1 + name_part2)
-
-/obj/machinery/computer/arcade/battle/ui_interact(mob/user)
- . = ..()
- var/dat = "Close"
- dat += "
Crew Management:
" - - //Buy crew - if(food >= 10 && fuel >= 10) - eventdat += "Hire a New Crewmember (-10FU, -10FO)
" - else - eventdat += "You cannot afford a new crewmember.
" - - //Sell crew - if(settlers.len > 1) - eventdat += "Sell Crew for Fuel and Food (+7FU, +7FO)
" - else - eventdat += "You have no other crew to sell.
" - - //BUY/SELL STUFF - eventdat += "Spare Parts:
" - - //Engine parts - if(fuel > 5) - eventdat += "" - else - eventdat += "You cannot afford engine parts." - - //Hull plates - if(fuel > 5) - eventdat += "
" - else - eventdat += "You cannot afford hull plates." - - //Electronics - if(fuel > 5) - eventdat += "
" - else - eventdat += "You cannot afford spare electronics." - - //Trade - if(fuel > 5) - eventdat += "
Trade Fuel for Food (-5FU,+5FO)
" - else - eventdat += "You don't have 5FU to trade.
5) - eventdat += "Trade Food for Fuel (+5FU,-5FO)
" - else - eventdat += "You don't have 5FO to trade.
!! Raid Spaceport !!" - - eventdat += "" - - -//Add Random/Specific crewmember -/obj/machinery/computer/arcade/orion_trail/proc/add_crewmember(var/specific = "") - var/newcrew = "" - if(specific) - newcrew = specific - else - if(prob(50)) - newcrew = pick(GLOB.first_names_male) - else - newcrew = pick(GLOB.first_names_female) - if(newcrew) - settlers += newcrew - alive++ - return newcrew - - -//Remove Random/Specific crewmember -/obj/machinery/computer/arcade/orion_trail/proc/remove_crewmember(var/specific = "", var/dont_remove = "") - var/list/safe2remove = settlers - var/removed = "" - if(dont_remove) - safe2remove -= dont_remove - if(specific && specific != dont_remove) - safe2remove = list(specific) - else - removed = pick(safe2remove) - - if(removed) - if(lings_aboard && prob(40*lings_aboard)) //if there are 2 lings you're twice as likely to get one, obviously - lings_aboard = max(0,--lings_aboard) - settlers -= removed - alive-- - return removed - - -/obj/machinery/computer/arcade/orion_trail/proc/win(mob/user) - gameStatus = ORION_STATUS_START - say("Congratulations, you made it to Orion!") - if(obj_flags & EMAGGED) - new /obj/item/orion_ship(loc) - message_admins("[ADMIN_LOOKUPFLW(usr)] made it to Orion on an emagged machine and got an explosive toy ship.") - log_game("[key_name(usr)] made it to Orion on an emagged machine and got an explosive toy ship.") - else - prizevend(user) - obj_flags &= ~EMAGGED - name = "The Orion Trail" - desc = "Learn how our ancestors got to Orion, and have fun in the process!" - -/obj/machinery/computer/arcade/orion_trail/emag_act(mob/user) - if(obj_flags & EMAGGED) - return - to_chat(user, "You override the cheat code menu and skip to Cheat #[rand(1, 50)]: Realism Mode.") - name = "The Orion Trail: Realism Edition" - desc = "Learn how our ancestors got to Orion, and try not to die in the process!" - newgame() - obj_flags |= EMAGGED - -/mob/living/simple_animal/hostile/syndicate/ranged/smg/orion - name = "spaceport security" - desc = "Premier corporate security forces for all spaceports found along the Orion Trail." - faction = list("orion") - loot = list() - del_on_death = TRUE - -/obj/item/orion_ship - name = "model settler ship" - desc = "A model spaceship, it looks like those used back in the day when travelling to Orion! It even has a miniature FX-293 reactor, which was renowned for its instability and tendency to explode..." - icon = 'icons/obj/toy.dmi' - icon_state = "ship" - w_class = WEIGHT_CLASS_SMALL - var/active = 0 //if the ship is on - -/obj/item/orion_ship/examine(mob/user) - ..() - if(!(in_range(user, src))) - return - if(!active) - to_chat(user, "There's a little switch on the bottom. It's flipped down.") - else - to_chat(user, "There's a little switch on the bottom. It's flipped up.") - -/obj/item/orion_ship/attack_self(mob/user) //Minibomb-level explosion. Should probably be more because of how hard it is to survive the machine! Also, just over a 5-second fuse - if(active) - return - - message_admins("[ADMIN_LOOKUPFLW(usr)] primed an explosive Orion ship for detonation at [AREACOORD(usr)].") - log_game("[key_name(usr)] primed an explosive Orion ship for detonation at [AREACOORD(usr)].") - - to_chat(user, "You flip the switch on the underside of [src].") - active = 1 - visible_message("[src] softly beeps and whirs to life!") - playsound(loc, 'sound/machines/defib_SaftyOn.ogg', 25, 1) - say("This is ship ID #[rand(1,1000)] to Orion Port Authority. We're coming in for landing, over.") - sleep(20) - visible_message("[src] begins to vibrate...") - say("Uh, Port? Having some issues with our reactor, could you check it out? Over.") - sleep(30) - say("Oh, God! Code Eight! CODE EIGHT! IT'S GONNA BL-") - playsound(loc, 'sound/machines/buzz-sigh.ogg', 25, 1) - sleep(3.6) - visible_message("[src] explodes!") - explosion(loc, 2,4,8, flame_range = 16) - qdel(src) - - -#undef ORION_TRAIL_WINTURN -#undef ORION_TRAIL_RAIDERS -#undef ORION_TRAIL_FLUX -#undef ORION_TRAIL_ILLNESS -#undef ORION_TRAIL_BREAKDOWN -#undef ORION_TRAIL_LING -#undef ORION_TRAIL_LING_ATTACK -#undef ORION_TRAIL_MALFUNCTION -#undef ORION_TRAIL_COLLISION -#undef ORION_TRAIL_SPACEPORT -#undef ORION_TRAIL_BLACKHOLE - -#undef ORION_STATUS_START -#undef ORION_STATUS_NORMAL -#undef ORION_STATUS_GAMEOVER -#undef ORION_STATUS_MARKET diff --git a/code/game/machinery/computer/arcade/battle.dm b/code/game/machinery/computer/arcade/battle.dm new file mode 100644 index 0000000000..ded9cf95f6 --- /dev/null +++ b/code/game/machinery/computer/arcade/battle.dm @@ -0,0 +1,206 @@ +// ** BATTLE ** // + + +/obj/machinery/computer/arcade/battle + name = "arcade machine" + desc = "Does not support Pinball." + icon_state = "arcade" + circuit = /obj/item/circuitboard/computer/arcade/battle + var/enemy_name = "Space Villain" + var/temp = "Winners don't use space drugs" //Temporary message, for attack messages, etc + var/player_hp = 30 //Player health/attack points + var/player_mp = 10 + var/enemy_hp = 45 //Enemy health/attack points + var/enemy_mp = 20 + var/gameover = FALSE + 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 + var/name_part2 + + name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ", "Pwn ", "Own ", "Ban ") + + name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ") + name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "slime", "Griefer", "ERPer", "Lizard Man", "Unicorn", "Bloopers") + + enemy_name = replacetext((name_part1 + name_part2), "the ", "") + name = (name_action + name_part1 + name_part2) + +/obj/machinery/computer/arcade/battle/ui_interact(mob/user) + . = ..() + var/dat = "Close" + dat += "| [MINESWEEPERIMG(flag)] | " + if(0) + if(game_status != MINESWEEPER_GAME_PLAYING) + web += "[MINESWEEPERIMG(mine)] | " + else + web += "[MINESWEEPERIMG(hidden)] | " //Make unique hrefs for every square + if(1 to 9) + if(game_status != MINESWEEPER_GAME_PLAYING) + web += "[MINESWEEPERIMG(hidden)] | " + else + web += "[MINESWEEPERIMG(hidden)] | " //Make unique hrefs for every square + if(10) + web += "[MINESWEEPERIMG(minehit)] | " + if(11) + web += "[MINESWEEPERIMG(empty)] | " + if(12) + web += "[MINESWEEPERIMG(1)] | " + if(13) + web += "[MINESWEEPERIMG(2)] | " + if(14) + web += "[MINESWEEPERIMG(3)] | " + if(15) + web += "[MINESWEEPERIMG(4)] | " + if(16) + web += "[MINESWEEPERIMG(5)] | " + if(17) + web += "[MINESWEEPERIMG(6)] | " + if(18) + web += "[MINESWEEPERIMG(7)] | " + if(19) + web += "[MINESWEEPERIMG(8)] | " + web += "" + web += "
Crew Management:
" + + //Buy crew + if(food >= 10 && fuel >= 10) + eventdat += "Hire a New Crewmember (-10FU, -10FO)
" + else + eventdat += "You cannot afford a new crewmember.
" + + //Sell crew + if(settlers.len > 1) + eventdat += "Sell Crew for Fuel and Food (+7FU, +7FO)
" + else + eventdat += "You have no other crew to sell.
" + + //BUY/SELL STUFF + eventdat += "Spare Parts:
" + + //Engine parts + if(fuel > 5) + eventdat += "" + else + eventdat += "You cannot afford engine parts." + + //Hull plates + if(fuel > 5) + eventdat += "
" + else + eventdat += "You cannot afford hull plates." + + //Electronics + if(fuel > 5) + eventdat += "
" + else + eventdat += "You cannot afford spare electronics." + + //Trade + if(fuel > 5) + eventdat += "
Trade Fuel for Food (-5FU,+5FO)
" + else + eventdat += "You don't have 5FU to trade.
5) + eventdat += "Trade Food for Fuel (+5FU,-5FO)
" + else + eventdat += "You don't have 5FO to trade.
!! Raid Spaceport !!" + + eventdat += "" + + +//Add Random/Specific crewmember +/obj/machinery/computer/arcade/orion_trail/proc/add_crewmember(var/specific = "") + var/newcrew = "" + if(specific) + newcrew = specific + else + if(prob(50)) + newcrew = pick(GLOB.first_names_male) + else + newcrew = pick(GLOB.first_names_female) + if(newcrew) + settlers += newcrew + alive++ + return newcrew + + +//Remove Random/Specific crewmember +/obj/machinery/computer/arcade/orion_trail/proc/remove_crewmember(var/specific = "", var/dont_remove = "") + var/list/safe2remove = settlers + var/removed = "" + if(dont_remove) + safe2remove -= dont_remove + if(specific && specific != dont_remove) + safe2remove = list(specific) + else + removed = pick(safe2remove) + + if(removed) + if(lings_aboard && prob(40*lings_aboard)) //if there are 2 lings you're twice as likely to get one, obviously + lings_aboard = max(0,--lings_aboard) + settlers -= removed + alive-- + return removed + + +/obj/machinery/computer/arcade/orion_trail/proc/win(mob/user) + gameStatus = ORION_STATUS_START + say("Congratulations, you made it to Orion!") + if(obj_flags & EMAGGED) + new /obj/item/orion_ship(loc) + message_admins("[ADMIN_LOOKUPFLW(usr)] made it to Orion on an emagged machine and got an explosive toy ship.") + log_game("[key_name(usr)] made it to Orion on an emagged machine and got an explosive toy ship.") + else + prizevend(user) + obj_flags &= ~EMAGGED + name = "The Orion Trail" + desc = "Learn how our ancestors got to Orion, and have fun in the process!" + +/obj/machinery/computer/arcade/orion_trail/emag_act(mob/user) + if(obj_flags & EMAGGED) + return + to_chat(user, "You override the cheat code menu and skip to Cheat #[rand(1, 50)]: Realism Mode.") + name = "The Orion Trail: Realism Edition" + desc = "Learn how our ancestors got to Orion, and try not to die in the process!" + newgame() + obj_flags |= EMAGGED + +/mob/living/simple_animal/hostile/syndicate/ranged/smg/orion + name = "spaceport security" + desc = "Premier corporate security forces for all spaceports found along the Orion Trail." + faction = list("orion") + loot = list() + del_on_death = TRUE + +/obj/item/orion_ship + name = "model settler ship" + desc = "A model spaceship, it looks like those used back in the day when travelling to Orion! It even has a miniature FX-293 reactor, which was renowned for its instability and tendency to explode..." + icon = 'icons/obj/toy.dmi' + icon_state = "ship" + w_class = WEIGHT_CLASS_SMALL + var/active = 0 //if the ship is on + +/obj/item/orion_ship/examine(mob/user) + ..() + if(!(in_range(user, src))) + return + if(!active) + to_chat(user, "There's a little switch on the bottom. It's flipped down.") + else + to_chat(user, "There's a little switch on the bottom. It's flipped up.") + +/obj/item/orion_ship/attack_self(mob/user) //Minibomb-level explosion. Should probably be more because of how hard it is to survive the machine! Also, just over a 5-second fuse + if(active) + return + + message_admins("[ADMIN_LOOKUPFLW(usr)] primed an explosive Orion ship for detonation at [AREACOORD(usr)].") + log_game("[key_name(usr)] primed an explosive Orion ship for detonation at [AREACOORD(usr)].") + + to_chat(user, "You flip the switch on the underside of [src].") + active = 1 + visible_message("[src] softly beeps and whirs to life!") + playsound(loc, 'sound/machines/defib_SaftyOn.ogg', 25, 1) + say("This is ship ID #[rand(1,1000)] to Orion Port Authority. We're coming in for landing, over.") + sleep(20) + visible_message("[src] begins to vibrate...") + say("Uh, Port? Having some issues with our reactor, could you check it out? Over.") + sleep(30) + say("Oh, God! Code Eight! CODE EIGHT! IT'S GONNA BL-") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 25, 1) + sleep(3.6) + visible_message("[src] explodes!") + explosion(loc, 2,4,8, flame_range = 16) + qdel(src) + +#undef ORION_TRAIL_WINTURN +#undef ORION_TRAIL_RAIDERS +#undef ORION_TRAIL_FLUX +#undef ORION_TRAIL_ILLNESS +#undef ORION_TRAIL_BREAKDOWN +#undef ORION_TRAIL_LING +#undef ORION_TRAIL_LING_ATTACK +#undef ORION_TRAIL_MALFUNCTION +#undef ORION_TRAIL_COLLISION +#undef ORION_TRAIL_SPACEPORT +#undef ORION_TRAIL_BLACKHOLE + +#undef ORION_STATUS_START +#undef ORION_STATUS_NORMAL +#undef ORION_STATUS_GAMEOVER +#undef ORION_STATUS_MARKET 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 4d0ec9f1d9..2bcbd02cf2 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/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index 4a77274d23..0e543a3642 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -214,6 +214,20 @@ /obj/item/aiModule/core/full/damaged ) +/obj/effect/spawner/lootdrop/mre + name = "random MRE" + icon = 'icons/obj/storage.dmi' + icon_state = "mre" + +/obj/effect/spawner/lootdrop/mre/Initialize() + for(var/A in subtypesof(/obj/item/storage/box/mre)) + var/obj/item/storage/box/mre/M = A + var/our_chance = initial(M.spawner_chance) + if(our_chance) + LAZYSET(loot, M, our_chance) + return ..() + + // Tech storage circuit board spawners // For these, make sure that lootcount equals the number of list items diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9314faab27..2af7be2564 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)) @@ -685,7 +686,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) ..() /obj/item/proc/microwave_act(obj/machinery/microwave/M) - if(M && M.dirty < 100) + if(istype(M) && M.dirty < 100) M.dirty++ /obj/item/proc/on_mob_death(mob/living/L, gibbed) 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 += "\n" - var/datum/browser/popup = new(usr, "airlock_electronics", "Access Control", 900, 500) + var/datum/browser/popup = new(user, "rcd_access", "Access Control", 900, 500) popup.set_content(t1) - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() - onclose(usr, "airlock") + onclose(user, "rcd_access") /obj/item/construction/rcd/Topic(href, href_list) ..() if (usr.stat || usr.restrained()) return if (href_list["close"]) - usr << browse(null, "window=airlock") + usr << browse(null, "window=rcd_access") return if (href_list["access"]) toggle_access(href_list["access"]) - - change_airlock_access() + change_airlock_access(usr) /obj/item/construction/rcd/proc/toggle_access(acc) if (acc == "all") @@ -253,16 +254,77 @@ RLD if (!conf_access.len) conf_access = null -/obj/item/construction/rcd/verb/change_airlock_setting() - set name = "Change Airlock Setting" - set category = "Object" - set src in usr +/obj/item/construction/rcd/proc/get_airlock_image(airlock_type) + var/obj/machinery/door/airlock/proto = airlock_type + var/ic = initial(proto.icon) + var/mutable_appearance/MA = mutable_appearance(ic, "closed") + if(!initial(proto.glass)) + MA.overlays += "fill_closed" + //Not scaling these down to button size because they look horrible then, instead just bumping up radius. + return MA - var/airlockcat = input(usr, "Select whether the airlock is solid or glass.") in list("Solid", "Glass") +/obj/item/construction/rcd/proc/check_menu(mob/living/user) + if(!istype(user)) + return FALSE + if(user.incapacitated() || !user.Adjacent(src)) + return FALSE + return TRUE + +/obj/item/construction/rcd/proc/change_airlock_setting(mob/user) + if(!user) + return + + var/list/solid_or_glass_choices = list( + "Solid" = get_airlock_image(/obj/machinery/door/airlock), + "Glass" = get_airlock_image(/obj/machinery/door/airlock/glass) + ) + + var/list/solid_choices = list( + "Standard" = get_airlock_image(/obj/machinery/door/airlock), + "Public" = get_airlock_image(/obj/machinery/door/airlock/public), + "Engineering" = get_airlock_image(/obj/machinery/door/airlock/engineering), + "Atmospherics" = get_airlock_image(/obj/machinery/door/airlock/atmos), + "Security" = get_airlock_image(/obj/machinery/door/airlock/security), + "Command" = get_airlock_image(/obj/machinery/door/airlock/command), + "Medical" = get_airlock_image(/obj/machinery/door/airlock/medical), + "Research" = get_airlock_image(/obj/machinery/door/airlock/research), + "Freezer" = get_airlock_image(/obj/machinery/door/airlock/freezer), + "Science" = get_airlock_image(/obj/machinery/door/airlock/science), + "Virology" = get_airlock_image(/obj/machinery/door/airlock/virology), + "Mining" = get_airlock_image(/obj/machinery/door/airlock/mining), + "Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance), + "External" = get_airlock_image(/obj/machinery/door/airlock/external), + "External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external), + "Airtight Hatch" = get_airlock_image(/obj/machinery/door/airlock/hatch), + "Maintenance Hatch" = get_airlock_image(/obj/machinery/door/airlock/maintenance_hatch) + ) + + var/list/glass_choices = list( + "Standard" = get_airlock_image(/obj/machinery/door/airlock/glass), + "Public" = get_airlock_image(/obj/machinery/door/airlock/public/glass), + "Engineering" = get_airlock_image(/obj/machinery/door/airlock/engineering/glass), + "Atmospherics" = get_airlock_image(/obj/machinery/door/airlock/atmos/glass), + "Security" = get_airlock_image(/obj/machinery/door/airlock/security/glass), + "Command" = get_airlock_image(/obj/machinery/door/airlock/command/glass), + "Medical" = get_airlock_image(/obj/machinery/door/airlock/medical/glass), + "Research" = get_airlock_image(/obj/machinery/door/airlock/research/glass), + "Science" = get_airlock_image(/obj/machinery/door/airlock/science/glass), + "Virology" = get_airlock_image(/obj/machinery/door/airlock/virology/glass), + "Mining" = get_airlock_image(/obj/machinery/door/airlock/mining/glass), + "Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/glass), + "External" = get_airlock_image(/obj/machinery/door/airlock/external/glass), + "External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external/glass) + ) + + var/airlockcat = show_radial_menu(user, src, solid_or_glass_choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE) + if(!check_menu(user)) + return switch(airlockcat) if("Solid") if(advanced_airlock_setting == 1) - var/airlockpaint = input(usr, "Select the type of the airlock.") in list("Standard", "Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Freezer", "Science", "Virology", "Mining", "Maintenance", "External", "External Maintenance", "Airtight Hatch", "Maintenance Hatch") + var/airlockpaint = show_radial_menu(user, src, solid_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE) + if(!check_menu(user)) + return switch(airlockpaint) if("Standard") airlock_type = /obj/machinery/door/airlock @@ -305,7 +367,9 @@ RLD if("Glass") if(advanced_airlock_setting == 1) - var/airlockpaint = input(usr, "Select the type of the airlock.") in list("Standard", "Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Science", "Virology", "Mining", "Maintenance", "External", "External Maintenance") + var/airlockpaint = show_radial_menu(user, src , glass_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE) + if(!check_menu(user)) + return switch(airlockpaint) if("Standard") airlock_type = /obj/machinery/door/airlock/glass @@ -356,8 +420,8 @@ RLD playsound(src.loc, 'sound/machines/click.ogg', 50, 1) return TRUE -/obj/item/construction/rcd/New() - ..() +/obj/item/construction/rcd/Initialize() + . = ..() GLOB.rcd_list += src /obj/item/construction/rcd/Destroy() @@ -366,19 +430,46 @@ RLD /obj/item/construction/rcd/attack_self(mob/user) ..() - switch(mode) - if(1) - mode = 2 - to_chat(user, "You change RCD's mode to 'Airlock'.") - if(2) - mode = 3 - to_chat(user, "You change RCD's mode to 'Deconstruct'.") - if(3) - mode = 4 - to_chat(user, "You change RCD's mode to 'Grilles & Windows'.") - if(4) - mode = 1 - to_chat(user, "You change RCD's mode to 'Floor & Walls'.") + var/list/choices = list( + "Airlock" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlock"), + "Deconstruct" = image(icon= 'icons/mob/radial.dmi', icon_state = "delete"), + "Grilles & Windows" = image(icon = 'icons/mob/radial.dmi', icon_state = "grillewindow"), + "Floors & Walls" = image(icon = 'icons/mob/radial.dmi', icon_state = "wallfloor") + ) + if(mode == RCD_AIRLOCK) + choices += list( + "Change Access" = image(icon = 'icons/mob/radial.dmi', icon_state = "access"), + "Change Airlock Type" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlocktype") + ) + else if(mode == RCD_WINDOWGRILLE) + choices += list( + "Change Window Type" = image(icon = 'icons/mob/radial.dmi', icon_state = "windowtype") + ) + var/choice = show_radial_menu(user,src,choices, custom_check = CALLBACK(src,.proc/check_menu,user)) + if(!check_menu(user)) + return + switch(choice) + if("Floors & Walls") + mode = RCD_FLOORWALL + if("Airlock") + mode = RCD_AIRLOCK + if("Deconstruct") + mode = RCD_DECONSTRUCT + if("Grilles & Windows") + mode = RCD_WINDOWGRILLE + if("Change Access") + change_airlock_access(user) + return + if("Change Airlock Type") + change_airlock_setting(user) + return + if("Change Window Type") + toggle_window_type(user) + return + else + return + playsound(src, 'sound/effects/pop.ogg', 50, 0) + to_chat(user, "You change RCD's mode to '[choice]'.") /obj/item/construction/rcd/proc/target_check(atom/A, mob/user) // only returns true for stuff the device can actually work with if((isturf(A) && A.density && mode==RCD_DECONSTRUCT) || (isturf(A) && !A.density) || (istype(A, /obj/machinery/door/airlock) && mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/grille) || (istype(A, /obj/structure/window) && mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/girder)) diff --git a/code/game/objects/items/RCL.dm b/code/game/objects/items/RCL.dm index bc1b128c69..cea8165e02 100644 --- a/code/game/objects/items/RCL.dm +++ b/code/game/objects/items/RCL.dm @@ -14,13 +14,14 @@ w_class = WEIGHT_CLASS_NORMAL var/max_amount = 90 var/active = FALSE - actions_types = list(/datum/action/item_action/rcl) + actions_types = list(/datum/action/item_action/rcl_col,/datum/action/item_action/rcl_gui) var/list/colors = list("red", "yellow", "green", "blue", "pink", "orange", "cyan", "white") var/current_color_index = 1 var/ghetto = FALSE lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' var/datum/component/mobhook + var/datum/radial_menu/persistent/wiring_gui_menu /obj/item/twohanded/rcl/attackby(obj/item/W, mob/user) if(istype(W, /obj/item/stack/cable_coil)) @@ -85,7 +86,8 @@ /obj/item/twohanded/rcl/Destroy() QDEL_NULL(loaded) last = null - setActive(FALSE, null) // setactive(FALSE) removes mobhook + QDEL_NULL(mobhook) + QDEL_NULL(wiring_gui_menu) return ..() /obj/item/twohanded/rcl/update_icon() @@ -115,20 +117,28 @@ if(loaded) QDEL_NULL(loaded) loaded = null + QDEL_NULL(wiring_gui_menu) unwield(user) - setActive(wielded, user) + active = wielded return TRUE return FALSE +/obj/item/twohanded/rcl/pickup(mob/user) + ..() + getMobhook(user) + + + /obj/item/twohanded/rcl/dropped(mob/wearer) ..() if(mobhook) - setActive(FALSE, mobhook.parent) + active = FALSE + QDEL_NULL(mobhook) last = null /obj/item/twohanded/rcl/attack_self(mob/user) ..() - setActive(wielded, user) + active = wielded if(!active) last = null else if(!last) @@ -137,17 +147,24 @@ last = C break -/obj/item/twohanded/rcl/proc/setActive(toggle, mob/user) - active = toggle - if (active && user) - if (mobhook && mobhook.parent != user) +obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook) + if(to_hook) + if(mobhook && mobhook.parent != to_hook) QDEL_NULL(mobhook) if (!mobhook) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/trigger))) + mobhook = to_hook.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/trigger))) else QDEL_NULL(mobhook) /obj/item/twohanded/rcl/proc/trigger(mob/user) + if(active) + layCable(user) + if(wiring_gui_menu) //update the wire options as you move + wiringGuiUpdate(user) + + +//previous contents of trigger(), lays cable each time the player moves +/obj/item/twohanded/rcl/proc/layCable(mob/user) if(!isturf(user.loc)) return if(is_empty(user, 0)) @@ -156,7 +173,7 @@ if(prob(2) && ghetto) //Give ghetto RCLs a 2% chance to jam, requiring it to be reactviated manually. to_chat(user, "[src]'s wires jam!") - setActive(FALSE, user) + active = FALSE return else if(last) @@ -179,6 +196,91 @@ is_empty(user) //If we've run out, display message update_icon() +//searches the current tile for a stub cable of the same colour +/obj/item/twohanded/rcl/proc/findLinkingCable(mob/user) + var/turf/T + if(!isturf(user.loc)) + return + + T = get_turf(user) + if(T.intact || !T.can_have_cabling()) + return + + for(var/obj/structure/cable/C in T) + if(!C) + continue + if(C.cable_color != GLOB.cable_colors[colors[current_color_index]]) + continue + if(C.d1 == 0) + return C + break + return + + +/obj/item/twohanded/rcl/proc/wiringGuiGenerateChoices(mob/user) + var/fromdir = 0 + var/obj/structure/cable/linkingCable = findLinkingCable(user) + if(linkingCable) + fromdir = linkingCable.d2 + + var/list/wiredirs = list("1","5","4","6","2","10","8","9") + for(var/icondir in wiredirs) + var/dirnum = text2num(icondir) + var/cablesuffix = "[min(fromdir,dirnum)]-[max(fromdir,dirnum)]" + if(fromdir == dirnum) //cables can't loop back on themselves + cablesuffix = "invalid" + var/image/img = image(icon = 'icons/mob/radial.dmi', icon_state = "cable_[cablesuffix]") + img.color = GLOB.cable_colors[colors[current_color_index]] + wiredirs[icondir] = img + return wiredirs + +/obj/item/twohanded/rcl/proc/showWiringGui(mob/user) + var/list/choices = wiringGuiGenerateChoices(user) + + wiring_gui_menu = show_radial_menu_persistent(user, src , choices, select_proc = CALLBACK(src, .proc/wiringGuiReact, user), radius = 42) + +/obj/item/twohanded/rcl/proc/wiringGuiUpdate(mob/user) + if(!wiring_gui_menu) + return + + wiring_gui_menu.entry_animation = FALSE //stop the open anim from playing each time we update + var/list/choices = wiringGuiGenerateChoices(user) + + wiring_gui_menu.change_choices(choices,FALSE) + + +//Callback used to respond to interactions with the wiring menu +/obj/item/twohanded/rcl/proc/wiringGuiReact(mob/living/user,choice) + if(!choice) //close on a null choice (the center button) + QDEL_NULL(wiring_gui_menu) + return + + choice = text2num(choice) + + if(!isturf(user.loc)) + return + if(is_empty(user, 0)) + to_chat(user, "\The [src] is empty!") + return + + var/turf/T = get_turf(user) + if(T.intact || !T.can_have_cabling()) + return + + loaded.item_color = colors[current_color_index] + + var/obj/structure/cable/linkingCable = findLinkingCable(user) + if(linkingCable) + if(choice != linkingCable.d2) + loaded.cable_join(linkingCable, user, FALSE, choice) + last = null + else + last = loaded.place_turf(get_turf(src), user, choice) + + is_empty(user) //If we've run out, display message + + wiringGuiUpdate(user) + /obj/item/twohanded/rcl/pre_loaded/Initialize() //Comes preloaded with cable, for testing stuff . = ..() @@ -192,12 +294,21 @@ update_icon() /obj/item/twohanded/rcl/ui_action_click(mob/user, action) - if(istype(action, /datum/action/item_action/rcl)) + if(istype(action, /datum/action/item_action/rcl_col)) current_color_index++; if (current_color_index > colors.len) current_color_index = 1 var/cwname = colors[current_color_index] to_chat(user, "Color changed to [cwname]!") + if(loaded) + loaded.item_color= colors[current_color_index] + if(wiring_gui_menu) + wiringGuiUpdate(user) + else if(istype(action, /datum/action/item_action/rcl_gui)) + if(wiring_gui_menu) //The menu is already open, close it + QDEL_NULL(wiring_gui_menu) + else //open the menu + showWiringGui(user) /obj/item/twohanded/rcl/ghetto actions_types = list() diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm index 41ddc22106..0549ebc474 100644 --- a/code/game/objects/items/RPD.dm +++ b/code/game/objects/items/RPD.dm @@ -331,7 +331,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( //make sure what we're clicking is valid for the current category var/static/list/make_pipe_whitelist if(!make_pipe_whitelist) - make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe)) + make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe, /obj/structure/window, /obj/structure/grille)) var/can_make_pipe = (isturf(A) || is_type_in_typecache(A, make_pipe_whitelist)) . = FALSE diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index ab877ff97a..699efaac2e 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -59,7 +59,7 @@ /obj/item/areaeditor/blueprints/attack_self(mob/user) . = ..() if(!legend) - var/area/A = get_area() + var/area/A = get_area(user) if(get_area_type() == AREA_STATION) . += "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..000c52ae43 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" @@ -709,9 +707,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM item_state = null w_class = WEIGHT_CLASS_TINY var/chem_volume = 100 - var/vapetime = 0 //this so it won't puff out clouds every tick - var/screw = 0 // kinky - var/super = 0 //for the fattest vapes dude. + var/vapetime = FALSE //this so it won't puff out clouds every tick + var/screw = FALSE // kinky + var/super = FALSE //for the fattest vapes dude. /obj/item/clothing/mask/vape/suicide_act(mob/user) user.visible_message("[user] is puffin hard on dat vape, [user.p_they()] trying to join the vape life on a whole notha plane!")//it doesn't give you cancer, it is cancer @@ -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 + create_reagents(chem_volume, NO_REACT) // so it doesn't react until you light it reagents.add_reagent("nicotine", 50) if(!icon_state) if(!param_color) @@ -730,52 +727,48 @@ CIGARETTE PACKETS ARE IN FANCY.DM item_state = "[param_color]_vape" /obj/item/clothing/mask/vape/attackby(obj/item/O, mob/user, params) - if(O.is_drainable()) - if(reagents.total_volume < chem_volume) - if(O.reagents.total_volume > 0) - O.reagents.trans_to(src,25) - to_chat(user, "You add the contents of [O] to [src].") - else - to_chat(user, "[O] is empty!") - else - to_chat(user, "[src] can't hold anymore reagents!") - - if(istype(O, /obj/item/screwdriver)) + if(O.tool_behaviour == TOOL_SCREWDRIVER) if(!screw) - screw = 1 + screw = TRUE to_chat(user, "You open the cap on [src].") - if(super) + ENABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER) + if(obj_flags & EMAGGED) + add_overlay("vapeopen_high") + else if(super) add_overlay("vapeopen_med") else add_overlay("vapeopen_low") else - screw = 0 + screw = FALSE to_chat(user, "You close the cap on [src].") + DISABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER) cut_overlays() - if(istype(O, /obj/item/multitool)) + if(O.tool_behaviour == TOOL_MULTITOOL) if(screw && !(obj_flags & EMAGGED))//also kinky if(!super) cut_overlays() - super = 1 + super = TRUE to_chat(user, "You increase the voltage of [src].") add_overlay("vapeopen_med") else cut_overlays() - super = 0 + super = FALSE to_chat(user, "You decrease the voltage of [src].") add_overlay("vapeopen_low") if(screw && (obj_flags & EMAGGED)) to_chat(user, "[src] can't be modified!") + else + ..() /obj/item/clothing/mask/vape/emag_act(mob/user)// I WON'T REGRET WRITTING THIS, SURLY. if(screw) if(!(obj_flags & EMAGGED)) cut_overlays() obj_flags |= EMAGGED - super = 0 + super = FALSE to_chat(user, "You maximize the voltage of [src].") add_overlay("vapeopen_high") var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect @@ -790,13 +783,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 +796,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/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index 26f00c730e..a1ee62e2eb 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -123,6 +123,14 @@ name = "Orion Trail (Computer Board)" build_path = /obj/machinery/computer/arcade/orion_trail +/obj/item/circuitboard/computer/arcade/minesweeper + name = "Minesweeper (Computer Board)" + build_path = /obj/machinery/computer/arcade/minesweeper + +/obj/item/circuitboard/computer/arcade/amputation + name = "Mediborg's Amputation Adventure (Computer Board)" + build_path = /obj/machinery/computer/arcade/amputation + /obj/item/circuitboard/computer/turbine_control name = "Turbine control (Computer Board)" build_path = /obj/machinery/computer/turbine_computer 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 7d3d36c5b2..79c90b2a2f 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -10,6 +10,15 @@ GLOBAL_LIST_EMPTY(PDAs) #define PDA_SCANNER_HALOGEN 4 #define PDA_SCANNER_GAS 5 #define PDA_SPAM_DELAY 2 MINUTES +#define PDA_STANDARD_OVERLAYS list("pda-r", "blank", "id_overlay", "insert_overlay", "light_overlay", "pai_overlay") + +//pda icon overlays list defines +#define PDA_OVERLAY_ALERT 1 +#define PDA_OVERLAY_SCREEN 2 +#define PDA_OVERLAY_ID 3 +#define PDA_OVERLAY_ITEM 4 +#define PDA_OVERLAY_LIGHT 5 +#define PDA_OVERLAY_PAI 6 /obj/item/pda name = "\improper PDA" @@ -31,7 +40,8 @@ GLOBAL_LIST_EMPTY(PDAs) var/default_cartridge = 0 // Access level defined by cartridge var/obj/item/cartridge/cartridge = null //current cartridge var/mode = 0 //Controls what menu the PDA will display. 0 is hub; the rest are either built in or based on cartridge. - var/icon_alert = "pda-r" //Icon to be overlayed for message alerts. Taken from the pda icon file. + var/list/overlays_icons = list('icons/obj/pda_alt.dmi' = list("pda-r", "screen_default", "id_overlay", "insert_overlay", "light_overlay", "pai_overlay")) + var/current_overlays = PDA_STANDARD_OVERLAYS var/font_index = 0 //This int tells DM which font is currently selected and lets DM know when the last font has been selected so that it can cycle back to the first font when "toggle font" is pressed again. var/font_mode = "font-family:monospace;" //The currently selected font. var/background_color = "#808000" //The currently selected background color. @@ -78,7 +88,9 @@ GLOBAL_LIST_EMPTY(PDAs) var/list/contained_item = list(/obj/item/pen, /obj/item/toy/crayon, /obj/item/lipstick, /obj/item/flashlight/pen, /obj/item/clothing/mask/cigarette) var/obj/item/inserted_item //Used for pen, crayon, and lipstick insertion or removal. Same as above. - var/overlays_x_offset = 0 //x offset to use for certain overlays + var/list/overlays_offsets // offsets to use for certain overlays + var/overlays_x_offset = 0 + var/overlays_y_offset = 0 var/underline_flag = TRUE //flag for underline @@ -91,15 +103,13 @@ GLOBAL_LIST_EMPTY(PDAs) return BRUTELOSS /obj/item/pda/examine(mob/user) - ..() - if(!id && !inserted_item) - return - - if(id) - to_chat(user, "Alt-click to remove the id.") - + . = ..() + var/dat = id ? "Alt-click to remove the id." : "" if(inserted_item && (!isturf(loc))) - to_chat(user, "Ctrl-click to remove [inserted_item].") + dat += "\nCtrl-click to remove [inserted_item]." + if(LAZYLEN(GLOB.pda_reskins)) + dat += "\nCtrl-shift-click it to reskin it." + to_chat(user, dat) /obj/item/pda/Initialize() . = ..() @@ -115,28 +125,71 @@ GLOBAL_LIST_EMPTY(PDAs) inserted_item = new /obj/item/pen(src) update_icon() +/obj/item/pda/CtrlShiftClick(mob/living/user) + . = ..() + if(GLOB.pda_reskins && user.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) + reskin_obj(user) + +/obj/item/pda/reskin_obj(mob/M) + if(!LAZYLEN(GLOB.pda_reskins)) + return + var/dat = "Reskin options for [name]:" + for(var/V in GLOB.pda_reskins) + var/output = icon2html(GLOB.pda_reskins[V], M, icon_state) + dat += "\n[V]: [output]" + to_chat(M, dat) + + var/choice = input(M, "Choose the a reskin for [src]","Reskin Object") as null|anything in GLOB.pda_reskins + var/new_icon = GLOB.pda_reskins[choice] + if(QDELETED(src) || isnull(new_icon) || new_icon == icon || M.incapacitated() || !in_range(M,src)) + return + icon = new_icon + set_new_overlays() + update_icon() + to_chat(M, "[src] is now skinned as '[choice]'.") + +/obj/item/pda/proc/set_new_overlays() + if(!overlays_offsets || !(icon in overlays_offsets)) + overlays_x_offset = 0 + overlays_y_offset = 0 + else + var/list/new_offsets = overlays_offsets[icon] + if(new_offsets) + overlays_x_offset = new_offsets[1] + overlays_y_offset = new_offsets[2] + if(!(icon in overlays_icons)) + current_overlays = PDA_STANDARD_OVERLAYS + return + current_overlays = overlays_icons[icon] + /obj/item/pda/equipped(mob/user, slot) . = ..() - if(!equipped) - if(user.client) - background_color = user.client.prefs.pda_color - switch(user.client.prefs.pda_style) - if(MONO) - font_index = MODE_MONO - font_mode = FONT_MONO - if(SHARE) - font_index = MODE_SHARE - font_mode = FONT_SHARE - if(ORBITRON) - font_index = MODE_ORBITRON - font_mode = FONT_ORBITRON - if(VT) - font_index = MODE_VT - font_mode = FONT_VT - else - font_index = MODE_MONO - font_mode = FONT_MONO - equipped = TRUE + if(equipped) + return + if(user.client) + background_color = user.client.prefs.pda_color + switch(user.client.prefs.pda_style) + if(MONO) + font_index = MODE_MONO + font_mode = FONT_MONO + if(SHARE) + font_index = MODE_SHARE + font_mode = FONT_SHARE + if(ORBITRON) + font_index = MODE_ORBITRON + font_mode = FONT_ORBITRON + if(VT) + font_index = MODE_VT + font_mode = FONT_VT + else + font_index = MODE_MONO + font_mode = FONT_MONO + var/pref_skin = GLOB.pda_reskins[user.client.prefs.pda_skin] + if(icon != pref_skin) + icon = pref_skin + set_new_overlays() + update_icon() + equipped = TRUE /obj/item/pda/proc/update_label() name = "PDA-[owner] ([ownjob])" //Name generalisation @@ -150,33 +203,34 @@ GLOBAL_LIST_EMPTY(PDAs) /obj/item/pda/GetID() return id -/obj/item/pda/update_icon() +/obj/item/pda/update_icon(alert = FALSE) cut_overlays() + add_overlay(alert ? current_overlays[PDA_OVERLAY_ALERT] : current_overlays[PDA_OVERLAY_SCREEN]) var/mutable_appearance/overlay = new() overlay.pixel_x = overlays_x_offset if(id) - overlay.icon_state = "id_overlay" + overlay.icon_state = current_overlays[PDA_OVERLAY_ID] add_overlay(new /mutable_appearance(overlay)) if(inserted_item) - overlay.icon_state = "insert_overlay" + overlay.icon_state = current_overlays[PDA_OVERLAY_ITEM] add_overlay(new /mutable_appearance(overlay)) if(fon) - overlay.icon_state = "light_overlay" + overlay.icon_state = current_overlays[PDA_OVERLAY_LIGHT] add_overlay(new /mutable_appearance(overlay)) if(pai) - if(pai.pai) - overlay.icon_state = "pai_overlay" - add_overlay(new /mutable_appearance(overlay)) - else - overlay.icon_state = "pai_off_overlay" - add_overlay(new /mutable_appearance(overlay)) + 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!") @@ -358,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! - +