mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 20:16:55 +01:00
Merge branch 'master' into my-nanomaps-cant-be-this-cute
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
# dmdoc
|
||||
[DOCUMENTATION]: https://codedocs.paradisestation.org/
|
||||
|
||||
[BYOND]: https://secure.byond.com/
|
||||
|
||||
[DMDOC]: https://github.com/AffectedArc07/ParaSpacemanDMM/tree/master/src/dmdoc
|
||||
|
||||
[DMDOC] is a documentation generator for DreamMaker, the scripting language
|
||||
of the [BYOND] game engine. It produces simple static HTML files based on
|
||||
documented files, macros, types, procs, and vars.
|
||||
|
||||
We use **dmdoc** to generate [DOCUMENTATION] for our code, and that documentation
|
||||
is automatically generated and built on every new commit to the master branch
|
||||
|
||||
This gives new developers a clickable reference [DOCUMENTATION] they can browse to better help
|
||||
gain understanding of the Paradise codebase structure and api reference.
|
||||
|
||||
## Documenting code on Paradise
|
||||
We use block comments to document procs and classes, and we use `///` line comments
|
||||
when documenting individual variables.
|
||||
|
||||
Documentation is not required at Paradise, but it is highly recommended that all new code be covered with DMdoc code, according to the [Specifications](#Specification)
|
||||
|
||||
We also recommend that when you touch older code, you document the functions that you
|
||||
have touched in the process of updating that code
|
||||
|
||||
### Specification
|
||||
A class *should* always be autodocumented, and all public functions *should* be documented
|
||||
|
||||
All class level defined variables *should* be documented
|
||||
|
||||
Internal functions *can* be documented, but may not be
|
||||
|
||||
A public function is any function that a developer might reasonably call while using
|
||||
or interacting with your object. Internal functions are helper functions that your
|
||||
public functions rely on to implement logic
|
||||
|
||||
|
||||
### Documenting a proc
|
||||
When documenting a proc, we give a short one line description (as this is shown
|
||||
next to the proc definition in the list of all procs for a type or global
|
||||
namespace), then a longer paragraph which will be shown when the user clicks on
|
||||
the proc to jump to it's definition
|
||||
```
|
||||
/**
|
||||
* Short description of the proc
|
||||
*
|
||||
* Longer detailed paragraph about the proc
|
||||
* including any relevant detail
|
||||
* Arguments:
|
||||
* * arg1 - Relevance of this argument
|
||||
* * arg2 - Relevance of this argument
|
||||
*/
|
||||
```
|
||||
|
||||
### Documenting a class
|
||||
We first give the name of the class as a header, this can be omitted if the name is
|
||||
just going to be the typepath of the class, as dmdoc uses that by default
|
||||
|
||||
Then we give a short oneline description of the class
|
||||
|
||||
Finally we give a longer multi paragraph description of the class and it's details
|
||||
```
|
||||
/**
|
||||
* # Classname (Can be omitted if it's just going to be the typepath)
|
||||
*
|
||||
* The short overview
|
||||
*
|
||||
* A longer
|
||||
* paragraph of functionality about the class
|
||||
* including any assumptions/special cases
|
||||
*
|
||||
*/
|
||||
```
|
||||
|
||||
### Documenting a variable/define
|
||||
Give a short explanation of what the variable, in the context of the class, or define is.
|
||||
```
|
||||
/// Type path of item to go in suit slot
|
||||
var/suit = null
|
||||
```
|
||||
|
||||
## Module level description of code
|
||||
Modules are the best way to describe the structure/intent of a package of code
|
||||
where you don't want to be tied to the formal layout of the class structure.
|
||||
|
||||
On Paradise we do this by adding markdown files inside the `code` directory
|
||||
that will also be rendered and added to the modules tree. The structure for
|
||||
these is deliberately not defined, so you can be as freeform and as wheeling as
|
||||
you would like.
|
||||
|
||||
[Here is a representative example of what you might write](https://codedocs.paradisestation.org/code/modules/keybindings/readme.html)
|
||||
|
||||
## Special variables
|
||||
You can use certain special template variables in DM DOC comments and they will be expanded
|
||||
```
|
||||
[DEFINE_NAME] - Expands to a link to the define definition if documented
|
||||
[/mob] - Expands to a link to the docs for the /mob class
|
||||
[/mob/proc/Dizzy] - Expands to a link that will take you to the /mob class and anchor you to the dizzy proc docs
|
||||
[/mob/var/stat] - Expands to a link that will take you to the /mob class and anchor you to the stat var docs
|
||||
```
|
||||
|
||||
You can customise the link name by using `[link name][link shorthand].`
|
||||
|
||||
eg. `[see more about dizzy here] [/mob/proc/Dizzy]`
|
||||
|
||||
This is very useful to quickly link to other parts of the autodoc code to expand
|
||||
upon a comment made, or reasoning about code
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Generate Documentation
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *" # Every day at the very start of the day
|
||||
|
||||
jobs:
|
||||
generate_docs:
|
||||
name: 'Generate Documentation'
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- name: 'Update Branch'
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
ref: master
|
||||
|
||||
- name: 'Generate Documentation'
|
||||
run: |
|
||||
./tools/github-actions/doc-generator
|
||||
touch dmdoc/.nojekyll
|
||||
# Nojekyll is important to disable jeykll syntax, which can mess with files that start with underscores
|
||||
|
||||
- name: 'Deploy Documentation'
|
||||
uses: crazy-max/ghaction-github-pages@v2
|
||||
with:
|
||||
keep_history: false
|
||||
build_dir: dmdoc
|
||||
jekyll: false
|
||||
fqdn: codedocs.paradisestation.org
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+2
-2
@@ -52,8 +52,6 @@ jobs:
|
||||
- libstdc++6:i386
|
||||
- libssl-dev:i386
|
||||
- gcc-multilib
|
||||
- g++-7
|
||||
- g++-7-multilib
|
||||
- pkg-config:i386
|
||||
- zlib1g-dev:i386
|
||||
cache:
|
||||
@@ -61,6 +59,8 @@ jobs:
|
||||
- $HOME/.cargo
|
||||
- $HOME/.rustup
|
||||
- $HOME/BYOND
|
||||
before_install:
|
||||
- 'sudo apt-get -qq update'
|
||||
install:
|
||||
- tools/travis/install_byond.sh
|
||||
- source $HOME/BYOND/byond/bin/byondsetup
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[langserver]
|
||||
dreamchecker = true
|
||||
|
||||
[code_standards]
|
||||
disallow_relative_type_definitions = true
|
||||
disallow_relative_proc_definitions = true
|
||||
@@ -47144,7 +47144,7 @@
|
||||
pixel_y = 3
|
||||
},
|
||||
/obj/item/circuitboard/powermonitor,
|
||||
/obj/item/circuitboard/stationalert_all{
|
||||
/obj/item/circuitboard/stationalert{
|
||||
pixel_x = 3;
|
||||
pixel_y = -3
|
||||
},
|
||||
|
||||
@@ -31415,7 +31415,7 @@
|
||||
pixel_x = -2;
|
||||
pixel_y = 2
|
||||
},
|
||||
/obj/item/circuitboard/stationalert_all{
|
||||
/obj/item/circuitboard/stationalert{
|
||||
pixel_x = 1;
|
||||
pixel_y = -1
|
||||
},
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"aL" = (
|
||||
/obj/structure/displaycase/captain,
|
||||
/obj/mecha/working/ripley/mining,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"aM" = (
|
||||
@@ -392,12 +392,6 @@
|
||||
/obj/structure/filingcabinet,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"UM" = (
|
||||
/obj/machinery/computer/monitor/secret{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Wg" = (
|
||||
/turf/simulated/wall/r_wall,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
@@ -484,7 +478,7 @@ HP
|
||||
tl
|
||||
PK
|
||||
gz
|
||||
UM
|
||||
HP
|
||||
Wg
|
||||
ak
|
||||
ak
|
||||
|
||||
@@ -0,0 +1,614 @@
|
||||
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
|
||||
"a" = (
|
||||
/turf/template_noop,
|
||||
/area/template_noop)
|
||||
"b" = (
|
||||
/obj/structure/disposalpipe/segment,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"c" = (
|
||||
/obj/structure/lattice,
|
||||
/obj/structure/disposalpipe/broken{
|
||||
dir = 1
|
||||
},
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"d" = (
|
||||
/obj/structure/lattice,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"e" = (
|
||||
/obj/structure/grille/broken,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"g" = (
|
||||
/obj/structure/disposalpipe/broken{
|
||||
dir = 4
|
||||
},
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"h" = (
|
||||
/obj/structure/disposalpipe/broken{
|
||||
dir = 8
|
||||
},
|
||||
/obj/item/stack/cable_coil/cut,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"l" = (
|
||||
/obj/item/stack/cable_coil/cut,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"m" = (
|
||||
/obj/effect/spawner/random_spawners/grille_often,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"n" = (
|
||||
/obj/effect/spawner/random_spawners/grille_maybe,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"o" = (
|
||||
/obj/random/tool,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"p" = (
|
||||
/obj/structure/girder/displaced,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"r" = (
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"t" = (
|
||||
/obj/structure/cable{
|
||||
d1 = 2;
|
||||
d2 = 8;
|
||||
icon_state = "2-8"
|
||||
},
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"u" = (
|
||||
/obj/structure/door_assembly/door_assembly_sec,
|
||||
/obj/item/airlock_electronics,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"v" = (
|
||||
/obj/structure/lattice,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"x" = (
|
||||
/obj/structure/disposalpipe/junction,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"y" = (
|
||||
/turf/simulated/floor/plating/burnt,
|
||||
/area/space)
|
||||
"z" = (
|
||||
/obj/item/stack/sheet/metal,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/space)
|
||||
"B" = (
|
||||
/obj/structure/lattice,
|
||||
/obj/item/stack/sheet/metal,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"C" = (
|
||||
/obj/structure/disposalpipe/broken{
|
||||
dir = 1
|
||||
},
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"D" = (
|
||||
/obj/structure/cable{
|
||||
d1 = 4;
|
||||
d2 = 8;
|
||||
icon_state = "4-8";
|
||||
pixel_y = 0;
|
||||
tag = ""
|
||||
},
|
||||
/turf/simulated/floor/plating/burnt,
|
||||
/area/space)
|
||||
"E" = (
|
||||
/obj/item/stack/rods,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"F" = (
|
||||
/turf/simulated/floor/plating,
|
||||
/area/space)
|
||||
"G" = (
|
||||
/obj/random/toolbox,
|
||||
/turf/simulated/floor/plating/burnt,
|
||||
/area/space)
|
||||
"I" = (
|
||||
/obj/structure/grille/broken,
|
||||
/obj/structure/lattice,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"J" = (
|
||||
/obj/structure/disposalpipe/broken,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"K" = (
|
||||
/obj/item/shard,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"N" = (
|
||||
/obj/structure/lattice,
|
||||
/obj/structure/lattice,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"O" = (
|
||||
/obj/machinery/power/apc/worn_out{
|
||||
pixel_y = -24
|
||||
},
|
||||
/obj/structure/cable,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/space)
|
||||
"Q" = (
|
||||
/obj/effect/decal/cleanable/shreds{
|
||||
pixel_x = 4;
|
||||
pixel_y = 3
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/space)
|
||||
"T" = (
|
||||
/obj/structure/girder,
|
||||
/turf/simulated/floor/plating/burnt,
|
||||
/area/space)
|
||||
"U" = (
|
||||
/obj/effect/spawner/random_barrier/wall_probably,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"V" = (
|
||||
/turf/simulated/wall,
|
||||
/area/space)
|
||||
"X" = (
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"Y" = (
|
||||
/obj/item/shard,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/space)
|
||||
"Z" = (
|
||||
/obj/item/stack/sheet/metal,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
|
||||
(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
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
d
|
||||
d
|
||||
d
|
||||
r
|
||||
r
|
||||
d
|
||||
r
|
||||
a
|
||||
a
|
||||
"}
|
||||
(3,1,1) = {"
|
||||
a
|
||||
d
|
||||
v
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(4,1,1) = {"
|
||||
a
|
||||
d
|
||||
X
|
||||
m
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
v
|
||||
Z
|
||||
X
|
||||
X
|
||||
d
|
||||
a
|
||||
"}
|
||||
(5,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
g
|
||||
F
|
||||
X
|
||||
E
|
||||
I
|
||||
X
|
||||
X
|
||||
v
|
||||
X
|
||||
F
|
||||
v
|
||||
v
|
||||
X
|
||||
X
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(6,1,1) = {"
|
||||
a
|
||||
r
|
||||
J
|
||||
x
|
||||
C
|
||||
E
|
||||
v
|
||||
F
|
||||
X
|
||||
E
|
||||
X
|
||||
v
|
||||
g
|
||||
Z
|
||||
X
|
||||
X
|
||||
F
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(7,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
y
|
||||
E
|
||||
X
|
||||
E
|
||||
Y
|
||||
X
|
||||
n
|
||||
X
|
||||
h
|
||||
E
|
||||
F
|
||||
X
|
||||
v
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(8,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
X
|
||||
B
|
||||
l
|
||||
p
|
||||
X
|
||||
X
|
||||
y
|
||||
p
|
||||
X
|
||||
X
|
||||
X
|
||||
E
|
||||
X
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(9,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
v
|
||||
X
|
||||
o
|
||||
X
|
||||
X
|
||||
Z
|
||||
l
|
||||
X
|
||||
E
|
||||
a
|
||||
X
|
||||
X
|
||||
V
|
||||
X
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(10,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
Z
|
||||
Q
|
||||
v
|
||||
X
|
||||
y
|
||||
v
|
||||
D
|
||||
y
|
||||
U
|
||||
X
|
||||
X
|
||||
E
|
||||
X
|
||||
X
|
||||
n
|
||||
r
|
||||
a
|
||||
"}
|
||||
(11,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
I
|
||||
v
|
||||
v
|
||||
X
|
||||
v
|
||||
t
|
||||
O
|
||||
V
|
||||
X
|
||||
X
|
||||
F
|
||||
E
|
||||
Z
|
||||
X
|
||||
d
|
||||
a
|
||||
"}
|
||||
(12,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
J
|
||||
b
|
||||
c
|
||||
v
|
||||
G
|
||||
V
|
||||
X
|
||||
E
|
||||
e
|
||||
X
|
||||
X
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(13,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
X
|
||||
V
|
||||
X
|
||||
Z
|
||||
X
|
||||
X
|
||||
X
|
||||
u
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
e
|
||||
Z
|
||||
r
|
||||
a
|
||||
"}
|
||||
(14,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
v
|
||||
X
|
||||
v
|
||||
N
|
||||
E
|
||||
E
|
||||
K
|
||||
X
|
||||
v
|
||||
o
|
||||
X
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(15,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
E
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
E
|
||||
J
|
||||
C
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
d
|
||||
a
|
||||
"}
|
||||
(16,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
E
|
||||
X
|
||||
T
|
||||
X
|
||||
Z
|
||||
X
|
||||
n
|
||||
v
|
||||
X
|
||||
z
|
||||
n
|
||||
X
|
||||
Z
|
||||
X
|
||||
d
|
||||
a
|
||||
"}
|
||||
(17,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
F
|
||||
X
|
||||
X
|
||||
X
|
||||
p
|
||||
X
|
||||
X
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(18,1,1) = {"
|
||||
a
|
||||
r
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
v
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
r
|
||||
a
|
||||
"}
|
||||
(19,1,1) = {"
|
||||
a
|
||||
a
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
d
|
||||
r
|
||||
d
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
r
|
||||
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
|
||||
"}
|
||||
@@ -0,0 +1,631 @@
|
||||
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
|
||||
"a" = (
|
||||
/turf/template_noop,
|
||||
/area/template_noop)
|
||||
"b" = (
|
||||
/turf/simulated/floor/plating/airless,
|
||||
/area/space)
|
||||
"c" = (
|
||||
/turf/simulated/floor/plasteel/airless,
|
||||
/area/space)
|
||||
"d" = (
|
||||
/turf/simulated/wall/r_wall,
|
||||
/area/space)
|
||||
"e" = (
|
||||
/obj/item/stack/cable_coil/cut,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"h" = (
|
||||
/obj/structure/girder,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"j" = (
|
||||
/obj/structure/grille/broken,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"l" = (
|
||||
/obj/structure/girder,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/space)
|
||||
"m" = (
|
||||
/obj/structure/grille/broken,
|
||||
/turf/template_noop,
|
||||
/area/space)
|
||||
"n" = (
|
||||
/obj/item/stack/cable_coil/cut,
|
||||
/turf/template_noop,
|
||||
/area/space)
|
||||
"o" = (
|
||||
/obj/machinery/door/airlock/command{
|
||||
max_integrity = 40
|
||||
},
|
||||
/turf/simulated/floor/plating/burnt,
|
||||
/area/space)
|
||||
"p" = (
|
||||
/mob/living/simple_animal/hostile/carp,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"q" = (
|
||||
/obj/structure/lattice,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"s" = (
|
||||
/obj/item/stack/rods,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"t" = (
|
||||
/obj/structure/door_assembly/door_assembly_com,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"u" = (
|
||||
/obj/item/clothing/head/bio_hood/virology,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"w" = (
|
||||
/obj/structure/lattice,
|
||||
/turf/template_noop,
|
||||
/area/space)
|
||||
"x" = (
|
||||
/turf/template_noop,
|
||||
/area/space)
|
||||
"y" = (
|
||||
/obj/structure/lattice,
|
||||
/obj/structure/door_assembly/door_assembly_vault{
|
||||
anchored = 1
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/space)
|
||||
"z" = (
|
||||
/obj/item/stack/rods,
|
||||
/turf/template_noop,
|
||||
/area/space)
|
||||
"A" = (
|
||||
/obj/structure/closet/crate,
|
||||
/obj/item/reagent_containers/glass/beaker/bluespace,
|
||||
/turf/simulated/floor/plasteel/airless,
|
||||
/area/space)
|
||||
"B" = (
|
||||
/obj/item/shard{
|
||||
icon_state = "small"
|
||||
},
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"C" = (
|
||||
/obj/item/stack/sheet/metal,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"D" = (
|
||||
/obj/effect/landmark/burnturf,
|
||||
/turf/simulated/floor/plating/airless,
|
||||
/area/space)
|
||||
"E" = (
|
||||
/obj/item/reagent_containers/glass/beaker/large,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"F" = (
|
||||
/obj/effect/landmark/burnturf,
|
||||
/turf/simulated/floor,
|
||||
/area/space)
|
||||
"G" = (
|
||||
/obj/structure/safe,
|
||||
/obj/item/stack/sheet/mineral/bananium{
|
||||
amount = 5
|
||||
},
|
||||
/obj/item/stack/ore/bluespace_crystal/refined{
|
||||
amount = 3
|
||||
},
|
||||
/obj/item/dnainjector/comic,
|
||||
/turf/simulated/floor/plasteel/airless,
|
||||
/area/space)
|
||||
"H" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/shard{
|
||||
icon_state = "medium"
|
||||
},
|
||||
/turf/simulated/floor/plasteel/airless,
|
||||
/area/space)
|
||||
"I" = (
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"J" = (
|
||||
/mob/living/simple_animal/hostile/carp,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"L" = (
|
||||
/obj/item/shard,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"M" = (
|
||||
/turf/simulated/floor,
|
||||
/area/space)
|
||||
"N" = (
|
||||
/obj/item/clothing/suit/bio_suit/virology,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"O" = (
|
||||
/obj/item/shard{
|
||||
icon_state = "small"
|
||||
},
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"P" = (
|
||||
/obj/item/reagent_containers/spray/cleaner,
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"R" = (
|
||||
/obj/item/stack/sheet/metal,
|
||||
/turf/template_noop,
|
||||
/area/space)
|
||||
"S" = (
|
||||
/obj/item/reagent_containers/spray/cleaner,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"T" = (
|
||||
/turf/simulated/wall,
|
||||
/area/space)
|
||||
"U" = (
|
||||
/obj/effect/landmark/burnturf,
|
||||
/turf/simulated/floor/plasteel/airless,
|
||||
/area/space)
|
||||
"V" = (
|
||||
/obj/structure/lattice,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"W" = (
|
||||
/obj/effect/landmark/burnturf,
|
||||
/turf/simulated/floor/plating/burnt,
|
||||
/area/space)
|
||||
"X" = (
|
||||
/turf/space,
|
||||
/area/space)
|
||||
"Y" = (
|
||||
/obj/structure/girder/reinforced,
|
||||
/turf/simulated/floor/plating/damaged,
|
||||
/area/space)
|
||||
"Z" = (
|
||||
/obj/machinery/computer/pandemic{
|
||||
circuit = /obj/effect/decal/cleanable/shreds
|
||||
},
|
||||
/turf/simulated/floor/plasteel/airless,
|
||||
/area/space)
|
||||
|
||||
(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
|
||||
d
|
||||
d
|
||||
d
|
||||
d
|
||||
d
|
||||
Y
|
||||
x
|
||||
S
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
C
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(3,1,1) = {"
|
||||
a
|
||||
d
|
||||
G
|
||||
A
|
||||
U
|
||||
F
|
||||
d
|
||||
z
|
||||
T
|
||||
T
|
||||
T
|
||||
T
|
||||
o
|
||||
T
|
||||
I
|
||||
p
|
||||
O
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(4,1,1) = {"
|
||||
a
|
||||
Y
|
||||
c
|
||||
U
|
||||
c
|
||||
U
|
||||
d
|
||||
X
|
||||
w
|
||||
M
|
||||
c
|
||||
U
|
||||
M
|
||||
T
|
||||
V
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(5,1,1) = {"
|
||||
a
|
||||
Y
|
||||
M
|
||||
F
|
||||
F
|
||||
q
|
||||
d
|
||||
z
|
||||
m
|
||||
F
|
||||
M
|
||||
F
|
||||
M
|
||||
T
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(6,1,1) = {"
|
||||
a
|
||||
d
|
||||
d
|
||||
y
|
||||
d
|
||||
d
|
||||
Y
|
||||
X
|
||||
w
|
||||
X
|
||||
n
|
||||
X
|
||||
w
|
||||
T
|
||||
I
|
||||
I
|
||||
I
|
||||
C
|
||||
I
|
||||
a
|
||||
"}
|
||||
(7,1,1) = {"
|
||||
a
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
P
|
||||
J
|
||||
X
|
||||
T
|
||||
T
|
||||
T
|
||||
x
|
||||
T
|
||||
I
|
||||
I
|
||||
V
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(8,1,1) = {"
|
||||
a
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
R
|
||||
X
|
||||
w
|
||||
X
|
||||
b
|
||||
x
|
||||
x
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(9,1,1) = {"
|
||||
a
|
||||
p
|
||||
s
|
||||
T
|
||||
m
|
||||
w
|
||||
T
|
||||
R
|
||||
X
|
||||
B
|
||||
X
|
||||
w
|
||||
X
|
||||
x
|
||||
z
|
||||
I
|
||||
s
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(10,1,1) = {"
|
||||
a
|
||||
s
|
||||
I
|
||||
T
|
||||
M
|
||||
F
|
||||
T
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
X
|
||||
x
|
||||
x
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(11,1,1) = {"
|
||||
a
|
||||
I
|
||||
I
|
||||
T
|
||||
c
|
||||
F
|
||||
T
|
||||
X
|
||||
X
|
||||
c
|
||||
F
|
||||
b
|
||||
j
|
||||
D
|
||||
T
|
||||
I
|
||||
I
|
||||
I
|
||||
t
|
||||
a
|
||||
"}
|
||||
(12,1,1) = {"
|
||||
a
|
||||
C
|
||||
I
|
||||
T
|
||||
X
|
||||
M
|
||||
N
|
||||
s
|
||||
I
|
||||
I
|
||||
L
|
||||
q
|
||||
q
|
||||
b
|
||||
T
|
||||
I
|
||||
s
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(13,1,1) = {"
|
||||
a
|
||||
I
|
||||
I
|
||||
l
|
||||
T
|
||||
T
|
||||
T
|
||||
I
|
||||
I
|
||||
u
|
||||
j
|
||||
W
|
||||
c
|
||||
U
|
||||
T
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(14,1,1) = {"
|
||||
a
|
||||
I
|
||||
s
|
||||
p
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
p
|
||||
I
|
||||
I
|
||||
c
|
||||
H
|
||||
Z
|
||||
T
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(15,1,1) = {"
|
||||
a
|
||||
V
|
||||
I
|
||||
I
|
||||
s
|
||||
V
|
||||
C
|
||||
I
|
||||
I
|
||||
s
|
||||
h
|
||||
T
|
||||
T
|
||||
T
|
||||
T
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(16,1,1) = {"
|
||||
a
|
||||
I
|
||||
I
|
||||
E
|
||||
I
|
||||
I
|
||||
V
|
||||
I
|
||||
O
|
||||
I
|
||||
V
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
C
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(17,1,1) = {"
|
||||
a
|
||||
I
|
||||
I
|
||||
C
|
||||
I
|
||||
e
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
e
|
||||
I
|
||||
V
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(18,1,1) = {"
|
||||
a
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
h
|
||||
I
|
||||
I
|
||||
C
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(19,1,1) = {"
|
||||
a
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
C
|
||||
I
|
||||
I
|
||||
I
|
||||
I
|
||||
a
|
||||
"}
|
||||
(20,1,1) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
@@ -0,0 +1,824 @@
|
||||
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
|
||||
"a" = (
|
||||
/turf/template_noop,
|
||||
/area/template_noop)
|
||||
"b" = (
|
||||
/obj/item/stack/rods,
|
||||
/turf/simulated/floor/plating/damaged,
|
||||
/area/template_noop)
|
||||
"c" = (
|
||||
/obj/item/trash/popcorn,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"d" = (
|
||||
/obj/effect/spawner/random_spawners/wall_rusted_maybe,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"e" = (
|
||||
/obj/item/poster/random_contraband,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"f" = (
|
||||
/obj/structure/lattice,
|
||||
/obj/item/stack/sheet/metal,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"g" = (
|
||||
/obj/item/paperplane,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"h" = (
|
||||
/obj/item/trash/can,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"i" = (
|
||||
/obj/item/stack/rods,
|
||||
/turf/template_noop,
|
||||
/area/template_noop)
|
||||
"k" = (
|
||||
/obj/item/shard,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"l" = (
|
||||
/obj/item/stack/cable_coil{
|
||||
amount = 10
|
||||
},
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"m" = (
|
||||
/turf/simulated/wall,
|
||||
/area/template_noop)
|
||||
"n" = (
|
||||
/obj/item/stack/sheet/glass,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"p" = (
|
||||
/obj/random/plushie,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"q" = (
|
||||
/obj/item/stack/rods,
|
||||
/obj/item/stack/sheet/metal,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"t" = (
|
||||
/obj/machinery/computer/arcade/battle,
|
||||
/turf/simulated/floor/plasteel/airless,
|
||||
/area/template_noop)
|
||||
"u" = (
|
||||
/obj/random/tool,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"v" = (
|
||||
/obj/item/trash/syndi_cakes,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"w" = (
|
||||
/obj/item/stack/tickets,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"x" = (
|
||||
/obj/structure/bookcase/random/fiction,
|
||||
/turf/simulated/floor/plating/damaged,
|
||||
/area/template_noop)
|
||||
"y" = (
|
||||
/obj/item/storage/pill_bottle/random_meds/labelled,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"z" = (
|
||||
/turf/simulated/floor/plating/damaged,
|
||||
/area/template_noop)
|
||||
"A" = (
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"B" = (
|
||||
/obj/item/stack/rods,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"D" = (
|
||||
/obj/item/paper,
|
||||
/obj/item/paper,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"F" = (
|
||||
/obj/random/tool,
|
||||
/turf/simulated/floor/plating/damaged,
|
||||
/area/template_noop)
|
||||
"G" = (
|
||||
/obj/item/poster/random_official,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"H" = (
|
||||
/obj/item/stack/sheet/wood,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"I" = (
|
||||
/obj/item/stack/rods,
|
||||
/obj/item/stack/rods,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"J" = (
|
||||
/obj/item/trash/pistachios,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"K" = (
|
||||
/obj/structure/lattice,
|
||||
/obj/structure/girder,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"L" = (
|
||||
/obj/structure/girder,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"M" = (
|
||||
/obj/item/stack/sheet/metal,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"O" = (
|
||||
/obj/structure/girder/displaced,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"S" = (
|
||||
/obj/structure/lattice,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"U" = (
|
||||
/obj/item/stack/sheet/wood,
|
||||
/obj/item/stack/sheet/wood,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"V" = (
|
||||
/obj/item/circuitboard/arcade,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"W" = (
|
||||
/obj/item/stack/tickets,
|
||||
/obj/item/stack/tickets,
|
||||
/obj/item/stack/tickets,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
"Z" = (
|
||||
/obj/item/paper,
|
||||
/turf/space,
|
||||
/area/template_noop)
|
||||
|
||||
(1,1,1) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
i
|
||||
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
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
i
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
i
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
(3,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(4,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
B
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
B
|
||||
B
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(5,1,1) = {"
|
||||
i
|
||||
a
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
w
|
||||
A
|
||||
M
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
i
|
||||
"}
|
||||
(6,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
I
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
B
|
||||
B
|
||||
M
|
||||
A
|
||||
A
|
||||
M
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(7,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
k
|
||||
A
|
||||
A
|
||||
O
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
m
|
||||
A
|
||||
w
|
||||
A
|
||||
M
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(8,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
B
|
||||
A
|
||||
M
|
||||
A
|
||||
A
|
||||
H
|
||||
A
|
||||
G
|
||||
n
|
||||
m
|
||||
A
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(9,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
m
|
||||
A
|
||||
w
|
||||
A
|
||||
M
|
||||
S
|
||||
A
|
||||
A
|
||||
d
|
||||
B
|
||||
M
|
||||
A
|
||||
O
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(10,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
w
|
||||
A
|
||||
A
|
||||
Z
|
||||
A
|
||||
W
|
||||
B
|
||||
S
|
||||
h
|
||||
M
|
||||
L
|
||||
A
|
||||
c
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(11,1,1) = {"
|
||||
a
|
||||
i
|
||||
B
|
||||
w
|
||||
A
|
||||
S
|
||||
A
|
||||
F
|
||||
A
|
||||
A
|
||||
S
|
||||
A
|
||||
Z
|
||||
A
|
||||
A
|
||||
A
|
||||
M
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(12,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
H
|
||||
L
|
||||
S
|
||||
m
|
||||
m
|
||||
b
|
||||
A
|
||||
A
|
||||
Z
|
||||
w
|
||||
B
|
||||
A
|
||||
i
|
||||
a
|
||||
"}
|
||||
(13,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
B
|
||||
O
|
||||
A
|
||||
B
|
||||
A
|
||||
M
|
||||
A
|
||||
D
|
||||
K
|
||||
z
|
||||
S
|
||||
H
|
||||
B
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(14,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
n
|
||||
A
|
||||
y
|
||||
f
|
||||
B
|
||||
A
|
||||
z
|
||||
B
|
||||
A
|
||||
m
|
||||
t
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(15,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
z
|
||||
H
|
||||
A
|
||||
A
|
||||
A
|
||||
S
|
||||
A
|
||||
q
|
||||
z
|
||||
z
|
||||
A
|
||||
A
|
||||
O
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(16,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
S
|
||||
A
|
||||
S
|
||||
U
|
||||
B
|
||||
B
|
||||
A
|
||||
A
|
||||
S
|
||||
A
|
||||
M
|
||||
B
|
||||
u
|
||||
A
|
||||
a
|
||||
i
|
||||
"}
|
||||
(17,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
M
|
||||
H
|
||||
w
|
||||
Z
|
||||
B
|
||||
x
|
||||
S
|
||||
B
|
||||
S
|
||||
A
|
||||
k
|
||||
J
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(18,1,1) = {"
|
||||
a
|
||||
a
|
||||
B
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
w
|
||||
B
|
||||
z
|
||||
A
|
||||
O
|
||||
A
|
||||
M
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(19,1,1) = {"
|
||||
i
|
||||
a
|
||||
A
|
||||
A
|
||||
M
|
||||
z
|
||||
S
|
||||
w
|
||||
S
|
||||
M
|
||||
A
|
||||
m
|
||||
p
|
||||
A
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(20,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
B
|
||||
A
|
||||
O
|
||||
H
|
||||
v
|
||||
A
|
||||
V
|
||||
H
|
||||
A
|
||||
B
|
||||
L
|
||||
A
|
||||
M
|
||||
A
|
||||
w
|
||||
a
|
||||
a
|
||||
"}
|
||||
(21,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
e
|
||||
M
|
||||
A
|
||||
w
|
||||
Z
|
||||
w
|
||||
B
|
||||
A
|
||||
w
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(22,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
M
|
||||
O
|
||||
m
|
||||
m
|
||||
L
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
q
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(23,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
B
|
||||
k
|
||||
A
|
||||
B
|
||||
A
|
||||
B
|
||||
g
|
||||
n
|
||||
A
|
||||
O
|
||||
A
|
||||
A
|
||||
B
|
||||
B
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(24,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
M
|
||||
A
|
||||
A
|
||||
l
|
||||
A
|
||||
w
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(25,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
w
|
||||
B
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
A
|
||||
w
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(26,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
B
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
B
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
a
|
||||
a
|
||||
"}
|
||||
(27,1,1) = {"
|
||||
a
|
||||
a
|
||||
B
|
||||
A
|
||||
w
|
||||
A
|
||||
B
|
||||
A
|
||||
w
|
||||
A
|
||||
B
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
w
|
||||
a
|
||||
a
|
||||
"}
|
||||
(28,1,1) = {"
|
||||
a
|
||||
a
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
w
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
A
|
||||
a
|
||||
i
|
||||
"}
|
||||
(29,1,1) = {"
|
||||
i
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
i
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
(30,1,1) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
i
|
||||
a
|
||||
a
|
||||
"}
|
||||
@@ -73,8 +73,7 @@
|
||||
},
|
||||
/mob/living/simple_animal/hostile/syndicate{
|
||||
desc = "A weary looking syndicate operative.";
|
||||
environment_smash = 0;
|
||||
faction = "syndicate"
|
||||
environment_smash = 0
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/ruin/powered)
|
||||
@@ -100,6 +99,12 @@
|
||||
/obj/item/tank/air,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/ruin/powered)
|
||||
"u" = (
|
||||
/obj/machinery/tcomms/relay/ruskie{
|
||||
network_id = "LISTENINGOUTPOST-RELAY"
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/ruin/powered)
|
||||
"w" = (
|
||||
/obj/machinery/light/small,
|
||||
/turf/simulated/floor/plasteel,
|
||||
@@ -923,7 +928,7 @@ b
|
||||
f
|
||||
f
|
||||
f
|
||||
c
|
||||
f
|
||||
f
|
||||
D
|
||||
m
|
||||
@@ -965,7 +970,7 @@ f
|
||||
f
|
||||
p
|
||||
Y
|
||||
f
|
||||
u
|
||||
f
|
||||
j
|
||||
i
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -68,7 +68,6 @@
|
||||
"an" = (
|
||||
/obj/machinery/navbeacon/invisible{
|
||||
codes_txt = "patrol;next_patrol=SDNW";
|
||||
invisibility = 100;
|
||||
location = "SDNE"
|
||||
},
|
||||
/turf/simulated/floor/plating/asteroid/airless,
|
||||
@@ -292,15 +291,13 @@
|
||||
"aU" = (
|
||||
/obj/machinery/navbeacon/invisible{
|
||||
codes_txt = "patrol;next_patrol=SDSW";
|
||||
invisibility = 100;
|
||||
location = "SDNW"
|
||||
},
|
||||
/turf/simulated/floor/plating/asteroid/airless,
|
||||
/area/syndicate_depot/outer)
|
||||
"aV" = (
|
||||
/obj/machinery/light{
|
||||
dir = 4;
|
||||
icon_state = "tube1"
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/plating/asteroid/airless,
|
||||
/area/syndicate_depot/outer)
|
||||
@@ -429,8 +426,7 @@
|
||||
/area/syndicate_depot/core)
|
||||
"bo" = (
|
||||
/obj/machinery/light{
|
||||
dir = 4;
|
||||
icon_state = "tube1"
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/spawner/random_spawners/syndicate/loot,
|
||||
/turf/simulated/floor/plasteel{
|
||||
@@ -512,7 +508,6 @@
|
||||
id = "syndi_depot_rear";
|
||||
idle_power_usage = 0;
|
||||
name = "mysterious button";
|
||||
normaldoorcontrol = 0;
|
||||
pixel_x = 24;
|
||||
use_power = 0
|
||||
},
|
||||
@@ -663,8 +658,8 @@
|
||||
/obj/machinery/turretid/syndicate{
|
||||
name = "external turret controls";
|
||||
pixel_x = -32;
|
||||
pixel_y = 0;
|
||||
req_access = list(150)
|
||||
req_access = null;
|
||||
req_access_txt = "150"
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "dark"
|
||||
@@ -745,9 +740,8 @@
|
||||
/area/syndicate_depot/core)
|
||||
"ce" = (
|
||||
/obj/machinery/light/small{
|
||||
tag = "icon-bulb1 (EAST)";
|
||||
icon_state = "bulb1";
|
||||
dir = 4
|
||||
dir = 4;
|
||||
tag = "icon-bulb1 (EAST)"
|
||||
},
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/syndicate_depot/core)
|
||||
@@ -757,7 +751,6 @@
|
||||
id = "syndi_depot_rear";
|
||||
idle_power_usage = 0;
|
||||
name = "mysterious button";
|
||||
normaldoorcontrol = 0;
|
||||
use_power = 0
|
||||
},
|
||||
/obj/structure/sign/poster/contraband/syndicate_recruitment,
|
||||
@@ -774,8 +767,8 @@
|
||||
/area/syndicate_depot/core)
|
||||
"ci" = (
|
||||
/obj/structure/cable{
|
||||
icon_state = "0-2";
|
||||
d2 = 2
|
||||
d2 = 2;
|
||||
icon_state = "0-2"
|
||||
},
|
||||
/obj/machinery/power/smes/upgraded{
|
||||
charge = 5e+006;
|
||||
@@ -845,7 +838,6 @@
|
||||
"cr" = (
|
||||
/obj/structure/sink{
|
||||
dir = 4;
|
||||
icon_state = "sink";
|
||||
pixel_x = 12
|
||||
},
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
@@ -1154,7 +1146,6 @@
|
||||
"dc" = (
|
||||
/obj/machinery/navbeacon/invisible{
|
||||
codes_txt = "patrol;next_patrol=SDSE";
|
||||
invisibility = 100;
|
||||
location = "SDSW"
|
||||
},
|
||||
/turf/simulated/floor/plating/asteroid/airless,
|
||||
@@ -1179,7 +1170,6 @@
|
||||
"df" = (
|
||||
/obj/machinery/navbeacon/invisible{
|
||||
codes_txt = "patrol;next_patrol=SDNE";
|
||||
invisibility = 100;
|
||||
location = "SDSE"
|
||||
},
|
||||
/turf/simulated/floor/plating/asteroid/airless,
|
||||
|
||||
@@ -152,12 +152,7 @@
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/unpowered)
|
||||
"az" = (
|
||||
/obj/item/spellbook/oneuse/charge{
|
||||
desc = "For the technology-hating wizard.";
|
||||
spell = /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech;
|
||||
spellname = "Disable Technology";
|
||||
used = 1
|
||||
},
|
||||
/obj/item/spellbook/oneuse/emp/used,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/unpowered)
|
||||
"aA" = (
|
||||
|
||||
@@ -35244,7 +35244,7 @@
|
||||
},
|
||||
/area/bridge)
|
||||
"bnW" = (
|
||||
/obj/machinery/computer/station_alert/all,
|
||||
/obj/machinery/computer/station_alert,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 0;
|
||||
icon_state = "yellow"
|
||||
@@ -72578,7 +72578,7 @@
|
||||
pixel_x = -2;
|
||||
pixel_y = 2
|
||||
},
|
||||
/obj/item/circuitboard/stationalert_all{
|
||||
/obj/item/circuitboard/stationalert{
|
||||
pixel_x = 1;
|
||||
pixel_y = -1
|
||||
},
|
||||
@@ -75846,7 +75846,7 @@
|
||||
pixel_x = 32;
|
||||
pixel_y = 0
|
||||
},
|
||||
/obj/machinery/computer/station_alert/all,
|
||||
/obj/machinery/computer/station_alert,
|
||||
/obj/structure/cable/yellow{
|
||||
d1 = 4;
|
||||
d2 = 8;
|
||||
@@ -77210,6 +77210,10 @@
|
||||
pixel_x = -22
|
||||
},
|
||||
/obj/item/stack/tape_roll,
|
||||
/obj/machinery/camera/motion{
|
||||
c_tag = "EVA Motion Sensor";
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "dark"
|
||||
},
|
||||
|
||||
@@ -4296,55 +4296,20 @@
|
||||
dir = 2
|
||||
},
|
||||
/area/centcom/control)
|
||||
"mE" = (
|
||||
/obj/structure/flora/ausbushes/lavendergrass,
|
||||
/turf/unsimulated/floor{
|
||||
icon_state = "grass1";
|
||||
name = "grass"
|
||||
},
|
||||
/area/centcom/specops)
|
||||
"mF" = (
|
||||
/obj/structure/flora/ausbushes/stalkybush,
|
||||
/turf/unsimulated/floor{
|
||||
icon_state = "grass1";
|
||||
name = "grass"
|
||||
},
|
||||
/area/centcom/specops)
|
||||
"mG" = (
|
||||
/obj/structure/flora/ausbushes/pointybush,
|
||||
/turf/unsimulated/floor{
|
||||
icon_state = "grass1";
|
||||
name = "grass"
|
||||
},
|
||||
/area/centcom/specops)
|
||||
"mH" = (
|
||||
/obj/structure/flora/ausbushes/ywflowers,
|
||||
/turf/unsimulated/floor{
|
||||
icon_state = "grass1";
|
||||
name = "grass"
|
||||
},
|
||||
/area/centcom/specops)
|
||||
"mI" = (
|
||||
/obj/structure/flora/ausbushes/brflowers,
|
||||
/turf/unsimulated/floor{
|
||||
icon_state = "grass1";
|
||||
name = "grass"
|
||||
},
|
||||
/area/centcom/specops)
|
||||
"mJ" = (
|
||||
/obj/structure/flora/ausbushes/sparsegrass,
|
||||
/turf/unsimulated/floor{
|
||||
icon_state = "grass1";
|
||||
name = "grass"
|
||||
},
|
||||
/area/centcom/specops)
|
||||
/area/centcom/control)
|
||||
"mK" = (
|
||||
/obj/structure/flora/ausbushes/reedbush,
|
||||
/turf/unsimulated/floor{
|
||||
icon_state = "grass1";
|
||||
name = "grass"
|
||||
},
|
||||
/area/centcom/specops)
|
||||
/area/centcom/control)
|
||||
"mL" = (
|
||||
/turf/unsimulated/floor{
|
||||
dir = 1;
|
||||
@@ -36255,7 +36220,7 @@ lH
|
||||
lH
|
||||
mu
|
||||
su
|
||||
mF
|
||||
mZ
|
||||
mY
|
||||
su
|
||||
nD
|
||||
@@ -36512,7 +36477,7 @@ mc
|
||||
lH
|
||||
lH
|
||||
su
|
||||
mE
|
||||
nd
|
||||
mX
|
||||
su
|
||||
nD
|
||||
@@ -36769,7 +36734,7 @@ mc
|
||||
lH
|
||||
lH
|
||||
su
|
||||
mH
|
||||
mY
|
||||
na
|
||||
su
|
||||
nD
|
||||
@@ -37026,7 +36991,7 @@ lH
|
||||
lH
|
||||
lH
|
||||
su
|
||||
mG
|
||||
WW
|
||||
mZ
|
||||
su
|
||||
nD
|
||||
@@ -37283,7 +37248,7 @@ lH
|
||||
mk
|
||||
mw
|
||||
su
|
||||
mJ
|
||||
na
|
||||
ne
|
||||
su
|
||||
nD
|
||||
|
||||
@@ -681,7 +681,7 @@
|
||||
req_access_txt = "2"
|
||||
},
|
||||
/obj/structure/cable{
|
||||
icon_state = "1-10"
|
||||
icon_state = "1-2"
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
@@ -858,18 +858,11 @@
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/mine/laborcamp/security)
|
||||
"ce" = (
|
||||
/obj/structure/cable{
|
||||
icon_state = "2-4"
|
||||
/obj/machinery/power/smes{
|
||||
charge = 5e+006
|
||||
},
|
||||
/obj/structure/cable{
|
||||
icon_state = "5-6"
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
"cf" = (
|
||||
/obj/machinery/power/terminal,
|
||||
/obj/structure/cable{
|
||||
icon_state = "0-8"
|
||||
icon_state = "0-4"
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
@@ -880,6 +873,9 @@
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
"ch" = (
|
||||
/obj/structure/cable{
|
||||
icon_state = "1-8"
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
"ci" = (
|
||||
@@ -1033,21 +1029,22 @@
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/mine/laborcamp)
|
||||
"cz" = (
|
||||
/obj/machinery/power/port_gen/pacman{
|
||||
anchored = 1
|
||||
},
|
||||
/obj/structure/cable,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
"cA" = (
|
||||
/obj/machinery/power/smes{
|
||||
charge = 5e+006
|
||||
/obj/machinery/power/terminal{
|
||||
dir = 1
|
||||
},
|
||||
/obj/structure/cable{
|
||||
icon_state = "0-4"
|
||||
},
|
||||
/obj/structure/reagent_dispensers/fueltank,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
"cA" = (
|
||||
/obj/structure/cable{
|
||||
icon_state = "0-9"
|
||||
d1 = 4;
|
||||
d2 = 8;
|
||||
icon_state = "4-8";
|
||||
pixel_x = 0;
|
||||
tag = ""
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
@@ -1056,7 +1053,13 @@
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
"cC" = (
|
||||
/obj/structure/reagent_dispensers/fueltank,
|
||||
/obj/machinery/power/port_gen/pacman{
|
||||
anchored = 1
|
||||
},
|
||||
/obj/structure/cable{
|
||||
d2 = 8;
|
||||
icon_state = "0-8"
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/mine/laborcamp)
|
||||
"cD" = (
|
||||
@@ -11202,7 +11205,7 @@ bm
|
||||
aq
|
||||
bB
|
||||
bM
|
||||
cf
|
||||
ch
|
||||
cA
|
||||
aq
|
||||
aj
|
||||
@@ -11460,7 +11463,7 @@ aq
|
||||
aq
|
||||
aq
|
||||
cg
|
||||
cB
|
||||
cA
|
||||
aq
|
||||
aj
|
||||
cQ
|
||||
@@ -11716,7 +11719,7 @@ aD
|
||||
aD
|
||||
aD
|
||||
aq
|
||||
ch
|
||||
cB
|
||||
cC
|
||||
aq
|
||||
aj
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -137,51 +137,56 @@
|
||||
return
|
||||
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/atmospherics/binary/passive_gate/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
user.set_machine(src)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 385, 115, state = state)
|
||||
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["on"] = on
|
||||
data["pressure"] = round(target_pressure)
|
||||
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
|
||||
/obj/machinery/atmospherics/binary/passive_gate/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"on" = on,
|
||||
"rate" = round(target_pressure),
|
||||
"max_rate" = MAX_OUTPUT_PRESSURE,
|
||||
"gas_unit" = "kPa",
|
||||
"step" = 10 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list)
|
||||
/obj/machinery/atmospherics/binary/passive_gate/tgui_act(action, list/params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
if(href_list["power"])
|
||||
switch(action)
|
||||
if("power")
|
||||
toggle()
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
return TRUE
|
||||
|
||||
if("max_rate")
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
. = TRUE
|
||||
|
||||
if("min_rate")
|
||||
target_pressure = 0
|
||||
. = TRUE
|
||||
|
||||
if("custom_rate")
|
||||
target_pressure = clamp(text2num(params["rate"]), 0 , MAX_OUTPUT_PRESSURE)
|
||||
. = TRUE
|
||||
if(.)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/proc/toggle()
|
||||
if(powered())
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
. = TRUE
|
||||
if(href_list["pressure"])
|
||||
var/pressure = href_list["pressure"]
|
||||
if(pressure == "max")
|
||||
pressure = MAX_OUTPUT_PRESSURE
|
||||
. = TRUE
|
||||
else if(pressure == "input")
|
||||
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
|
||||
if(!isnull(pressure))
|
||||
. = TRUE
|
||||
else if(text2num(pressure) != null)
|
||||
pressure = text2num(pressure)
|
||||
. = TRUE
|
||||
if(.)
|
||||
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
|
||||
update_icon()
|
||||
SSnanoui.update_uis(src)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/binary/passive_gate/attackby(obj/item/W, mob/user, params)
|
||||
if(!istype(W, /obj/item/wrench))
|
||||
|
||||
@@ -192,51 +192,51 @@ Thus, the two variables affect pump operation are set in New():
|
||||
return
|
||||
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/atmospherics/binary/pump/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
user.set_machine(src)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 385, 115, state = state)
|
||||
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["on"] = on
|
||||
data["pressure"] = round(target_pressure)
|
||||
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
|
||||
/obj/machinery/atmospherics/binary/pump/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"on" = on,
|
||||
"rate" = round(target_pressure),
|
||||
"max_rate" = MAX_OUTPUT_PRESSURE,
|
||||
"gas_unit" = "kPa",
|
||||
"step" = 10 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/Topic(href,href_list)
|
||||
/obj/machinery/atmospherics/binary/pump/tgui_act(action, list/params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
if(href_list["power"])
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
. = TRUE
|
||||
if(href_list["pressure"])
|
||||
var/pressure = href_list["pressure"]
|
||||
if(pressure == "max")
|
||||
pressure = MAX_OUTPUT_PRESSURE
|
||||
. = TRUE
|
||||
else if(pressure == "input")
|
||||
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
|
||||
if(!isnull(pressure))
|
||||
. = TRUE
|
||||
else if(text2num(pressure) != null)
|
||||
pressure = text2num(pressure)
|
||||
. = TRUE
|
||||
if(.)
|
||||
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
switch(action)
|
||||
if("power")
|
||||
toggle()
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
return TRUE
|
||||
|
||||
update_icon()
|
||||
SSnanoui.update_uis(src)
|
||||
if("max_rate")
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
. = TRUE
|
||||
|
||||
if("min_rate")
|
||||
target_pressure = 0
|
||||
. = TRUE
|
||||
|
||||
if("custom_rate")
|
||||
target_pressure = clamp(text2num(params["rate"]), 0 , MAX_OUTPUT_PRESSURE)
|
||||
. = TRUE
|
||||
if(.)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
|
||||
/obj/machinery/atmospherics/binary/pump/power_change()
|
||||
var/old_stat = stat
|
||||
|
||||
@@ -188,51 +188,51 @@ Thus, the two variables affect pump operation are set in New():
|
||||
return
|
||||
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/atmospherics/binary/volume_pump/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
user.set_machine(src)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 310, 115, state = state)
|
||||
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["on"] = on
|
||||
data["rate"] = round(transfer_rate)
|
||||
data["max_rate"] = round(MAX_TRANSFER_RATE)
|
||||
/obj/machinery/atmospherics/binary/volume_pump/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"on" = on,
|
||||
"rate" = round(transfer_rate),
|
||||
"max_rate" = round(MAX_TRANSFER_RATE),
|
||||
"gas_unit" = "L/s",
|
||||
"step" = 1 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/Topic(href,href_list)
|
||||
/obj/machinery/atmospherics/binary/volume_pump/tgui_act(action, list/params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
if(href_list["power"])
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
. = TRUE
|
||||
if(href_list["rate"])
|
||||
var/rate = href_list["rate"]
|
||||
if(rate == "max")
|
||||
rate = MAX_TRANSFER_RATE
|
||||
. = TRUE
|
||||
else if(rate == "input")
|
||||
rate = input("New transfer rate (0-[MAX_TRANSFER_RATE] L/s):", name, transfer_rate) as num|null
|
||||
if(!isnull(rate))
|
||||
. = TRUE
|
||||
else if(text2num(rate) != null)
|
||||
rate = text2num(rate)
|
||||
. = TRUE
|
||||
if(.)
|
||||
transfer_rate = clamp(rate, 0, MAX_TRANSFER_RATE)
|
||||
investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos")
|
||||
switch(action)
|
||||
if("power")
|
||||
toggle()
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
return TRUE
|
||||
|
||||
update_icon()
|
||||
SSnanoui.update_uis(src)
|
||||
if("max_rate")
|
||||
transfer_rate = MAX_TRANSFER_RATE
|
||||
. = TRUE
|
||||
|
||||
if("min_rate")
|
||||
transfer_rate = 0
|
||||
. = TRUE
|
||||
|
||||
if("custom_rate")
|
||||
transfer_rate = clamp(text2num(params["rate"]), 0 , MAX_TRANSFER_RATE)
|
||||
. = TRUE
|
||||
if(.)
|
||||
investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos")
|
||||
|
||||
/obj/machinery/atmospherics/binary/volume_pump/power_change()
|
||||
var/old_stat = stat
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
//--------------------------------------------
|
||||
// Omni device port types
|
||||
//--------------------------------------------
|
||||
#define ATM_NONE 0
|
||||
#define ATM_INPUT 1
|
||||
#define ATM_OUTPUT 2
|
||||
|
||||
#define ATM_O2 3
|
||||
#define ATM_N2 4
|
||||
#define ATM_CO2 5
|
||||
#define ATM_P 6 //Plasma
|
||||
#define ATM_N2O 7
|
||||
|
||||
//--------------------------------------------
|
||||
// Omni port datum
|
||||
//
|
||||
// Used by omni devices to manage connections
|
||||
// to other atmospheric objects.
|
||||
//--------------------------------------------
|
||||
/datum/omni_port
|
||||
var/obj/machinery/atmospherics/omni/master
|
||||
var/dir
|
||||
var/update = 1
|
||||
var/mode = 0
|
||||
var/concentration = 0
|
||||
var/con_lock = 0
|
||||
var/transfer_moles = 0
|
||||
var/datum/gas_mixture/air
|
||||
var/obj/machinery/atmospherics/node
|
||||
var/datum/pipeline/parent
|
||||
|
||||
/datum/omni_port/New(var/obj/machinery/atmospherics/omni/M, var/direction = NORTH)
|
||||
..()
|
||||
dir = direction
|
||||
if(istype(M))
|
||||
master = M
|
||||
air = new
|
||||
air.volume = 200
|
||||
|
||||
/datum/omni_port/proc/connect()
|
||||
if(node)
|
||||
return
|
||||
master.atmos_init()
|
||||
if(node)
|
||||
node.atmos_init()
|
||||
node.addMember(master)
|
||||
master.build_network()
|
||||
|
||||
/datum/omni_port/proc/disconnect()
|
||||
if(node)
|
||||
node.disconnect(master)
|
||||
node = null
|
||||
master.nullifyPipenet(parent)
|
||||
|
||||
//--------------------------------------------
|
||||
// Need to find somewhere else for these
|
||||
//--------------------------------------------
|
||||
|
||||
//returns a text string based on the direction flag input
|
||||
// if capitalize is true, it will return the string capitalized
|
||||
// otherwise it will return the direction string in lower case
|
||||
/proc/dir_name(var/dir, var/capitalize = 0)
|
||||
var/string = null
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
string = "North"
|
||||
if(SOUTH)
|
||||
string = "South"
|
||||
if(EAST)
|
||||
string = "East"
|
||||
if(WEST)
|
||||
string = "West"
|
||||
|
||||
if(!capitalize && string)
|
||||
string = lowertext(string)
|
||||
|
||||
return string
|
||||
|
||||
//returns a direction flag based on the string passed to it
|
||||
// case insensitive
|
||||
/proc/dir_flag(var/dir)
|
||||
dir = lowertext(dir)
|
||||
switch(dir)
|
||||
if("north")
|
||||
return NORTH
|
||||
if("south")
|
||||
return SOUTH
|
||||
if("east")
|
||||
return EAST
|
||||
if("west")
|
||||
return WEST
|
||||
else
|
||||
return 0
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
//--------------------------------------------
|
||||
// Gas filter - omni variant
|
||||
//--------------------------------------------
|
||||
/obj/machinery/atmospherics/omni/filter
|
||||
name = "omni gas filter"
|
||||
icon_state = "map_filter"
|
||||
|
||||
var/list/o_filters = new()
|
||||
var/datum/omni_port/input
|
||||
var/datum/omni_port/output
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/Destroy()
|
||||
input = null
|
||||
output = null
|
||||
o_filters.Cut()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/sort_ports()
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(P.update)
|
||||
if(output == P)
|
||||
output = null
|
||||
if(input == P)
|
||||
input = null
|
||||
if(o_filters.Find(P))
|
||||
o_filters -= P
|
||||
|
||||
P.air.volume = 200
|
||||
switch(P.mode)
|
||||
if(ATM_INPUT)
|
||||
input = P
|
||||
if(ATM_OUTPUT)
|
||||
output = P
|
||||
if(ATM_O2 to ATM_N2O)
|
||||
o_filters += P
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/error_check()
|
||||
if(!input || !output || !o_filters)
|
||||
return 1
|
||||
if(o_filters.len < 1 || o_filters.len > 2) //requires 1 or 2 o_filters ~otherwise why are you using a filter?
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/process_atmos()
|
||||
..()
|
||||
if(!on)
|
||||
return 0
|
||||
|
||||
if(!input || !output)
|
||||
return 0
|
||||
|
||||
var/datum/gas_mixture/output_air = output.air //BYOND doesn't like referencing "output.air.return_pressure()" so we need to make a direct reference
|
||||
var/datum/gas_mixture/input_air = input.air // it's completely happy with them if they're in a loop though i.e. "P.air.return_pressure()"... *shrug*
|
||||
|
||||
var/output_pressure = output_air.return_pressure()
|
||||
|
||||
if(output_pressure >= target_pressure)
|
||||
return 1
|
||||
for(var/datum/omni_port/P in o_filters)
|
||||
if(P.air.return_pressure() >= target_pressure)
|
||||
return 1
|
||||
|
||||
var/pressure_delta = target_pressure - output_pressure
|
||||
|
||||
if(input_air.return_temperature() > 0)
|
||||
input.transfer_moles = pressure_delta * output_air.volume / (input_air.return_temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
if(input.transfer_moles > 0)
|
||||
var/datum/gas_mixture/removed = input_air.remove(input.transfer_moles)
|
||||
|
||||
if(!removed)
|
||||
return 1
|
||||
|
||||
for(var/datum/omni_port/P in o_filters)
|
||||
var/datum/gas_mixture/filtered_out = new
|
||||
filtered_out.temperature = removed.return_temperature()
|
||||
|
||||
switch(P.mode)
|
||||
if(ATM_O2)
|
||||
filtered_out.oxygen = removed.oxygen
|
||||
removed.oxygen = 0
|
||||
if(ATM_N2)
|
||||
filtered_out.nitrogen = removed.nitrogen
|
||||
removed.nitrogen = 0
|
||||
if(ATM_CO2)
|
||||
filtered_out.carbon_dioxide = removed.carbon_dioxide
|
||||
removed.carbon_dioxide = 0
|
||||
if(ATM_P)
|
||||
filtered_out.toxins = removed.toxins
|
||||
removed.toxins = 0
|
||||
|
||||
filtered_out.agent_b = removed.agent_b
|
||||
removed.agent_b = 0
|
||||
if(ATM_N2O)
|
||||
filtered_out.sleeping_agent = removed.sleeping_agent
|
||||
removed.sleeping_agent = 0
|
||||
else
|
||||
filtered_out = null
|
||||
|
||||
P.air.merge(filtered_out)
|
||||
P.parent.update = 1
|
||||
|
||||
output_air.merge(removed)
|
||||
output.parent.update = 1
|
||||
|
||||
input.transfer_moles = 0
|
||||
input.parent.update = 1
|
||||
|
||||
return 1
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0)
|
||||
usr.set_machine(src)
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/ui_data(mob/user, datum/topic_state/state)
|
||||
var/data[0]
|
||||
|
||||
data["power"] = on
|
||||
data["config"] = configuring
|
||||
|
||||
var/portData[0]
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(!configuring && P.mode == 0)
|
||||
continue
|
||||
|
||||
var/input = 0
|
||||
var/output = 0
|
||||
var/filter = 1
|
||||
var/f_type = null
|
||||
switch(P.mode)
|
||||
if(ATM_INPUT)
|
||||
input = 1
|
||||
filter = 0
|
||||
if(ATM_OUTPUT)
|
||||
output = 1
|
||||
filter = 0
|
||||
if(ATM_O2 to ATM_N2O)
|
||||
f_type = mode_send_switch(P.mode)
|
||||
|
||||
portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \
|
||||
"input" = input, \
|
||||
"output" = output, \
|
||||
"filter" = filter, \
|
||||
"f_type" = f_type)
|
||||
|
||||
if(portData.len)
|
||||
data["ports"] = portData
|
||||
if(output)
|
||||
data["pressure"] = target_pressure
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/proc/mode_send_switch(var/mode = ATM_NONE)
|
||||
switch(mode)
|
||||
if(ATM_O2)
|
||||
return "Oxygen"
|
||||
if(ATM_N2)
|
||||
return "Nitrogen"
|
||||
if(ATM_CO2)
|
||||
return "Carbon Dioxide"
|
||||
if(ATM_P)
|
||||
return "Plasma" //*cough* Plasma *cough*
|
||||
if(ATM_N2O)
|
||||
return "Nitrous Oxide"
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
switch(href_list["command"])
|
||||
if("power")
|
||||
if(!configuring)
|
||||
on = !on
|
||||
else
|
||||
on = 0
|
||||
if("configure")
|
||||
configuring = !configuring
|
||||
if(configuring)
|
||||
on = 0
|
||||
|
||||
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
|
||||
if(configuring && !on)
|
||||
switch(href_list["command"])
|
||||
if("set_pressure")
|
||||
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num
|
||||
target_pressure = between(0, new_pressure, 4500)
|
||||
if("switch_mode")
|
||||
switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"]))
|
||||
if("switch_filter")
|
||||
var/new_filter = input(usr,"Select filter mode:","Change filter",href_list["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Plasma", "Nitrous Oxide")
|
||||
switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter))
|
||||
|
||||
update_icon()
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/proc/mode_return_switch(var/mode)
|
||||
switch(mode)
|
||||
if("Oxygen")
|
||||
return ATM_O2
|
||||
if("Nitrogen")
|
||||
return ATM_N2
|
||||
if("Carbon Dioxide")
|
||||
return ATM_CO2
|
||||
if("Plasma")
|
||||
return ATM_P
|
||||
if("Nitrous Oxide")
|
||||
return ATM_N2O
|
||||
if("in")
|
||||
return ATM_INPUT
|
||||
if("out")
|
||||
return ATM_OUTPUT
|
||||
if("None")
|
||||
return ATM_NONE
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/proc/switch_filter(var/dir, var/mode)
|
||||
//check they aren't trying to disable the input or output ~this can only happen if they hack the cached tmpl file
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(P.dir == dir)
|
||||
if(P.mode == ATM_INPUT || P.mode == ATM_OUTPUT)
|
||||
return
|
||||
|
||||
switch_mode(dir, mode)
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/proc/switch_mode(var/port, var/mode)
|
||||
if(mode == null || !port)
|
||||
return
|
||||
var/datum/omni_port/target_port = null
|
||||
var/list/other_ports = new()
|
||||
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(P.dir == port)
|
||||
target_port = P
|
||||
else
|
||||
other_ports += P
|
||||
|
||||
var/previous_mode = null
|
||||
if(target_port)
|
||||
previous_mode = target_port.mode
|
||||
target_port.mode = mode
|
||||
if(target_port.mode != previous_mode)
|
||||
handle_port_change(target_port)
|
||||
else
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
for(var/datum/omni_port/P in other_ports)
|
||||
if(P.mode == mode)
|
||||
var/old_mode = P.mode
|
||||
P.mode = previous_mode
|
||||
if(P.mode != old_mode)
|
||||
handle_port_change(P)
|
||||
|
||||
update_ports()
|
||||
|
||||
/obj/machinery/atmospherics/omni/filter/proc/handle_port_change(var/datum/omni_port/P)
|
||||
switch(P.mode)
|
||||
if(ATM_NONE)
|
||||
initialize_directions &= ~P.dir
|
||||
P.disconnect()
|
||||
else
|
||||
initialize_directions |= P.dir
|
||||
P.connect()
|
||||
P.update = 1
|
||||
@@ -1,291 +0,0 @@
|
||||
//--------------------------------------------
|
||||
// Gas mixer - omni variant
|
||||
//--------------------------------------------
|
||||
/obj/machinery/atmospherics/omni/mixer
|
||||
name = "omni gas mixer"
|
||||
icon_state = "map_mixer"
|
||||
|
||||
var/list/inputs = new()
|
||||
var/datum/omni_port/output
|
||||
|
||||
//setup tags for initial concentration values (must be decimal)
|
||||
var/tag_north_con
|
||||
var/tag_south_con
|
||||
var/tag_east_con
|
||||
var/tag_west_con
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/New()
|
||||
..()
|
||||
if(mapper_set())
|
||||
var/con = 0
|
||||
for(var/datum/omni_port/P in ports)
|
||||
switch(P.dir)
|
||||
if(NORTH)
|
||||
if(tag_north_con && tag_north == 1)
|
||||
P.concentration = tag_north_con
|
||||
con += max(0, tag_north_con)
|
||||
if(SOUTH)
|
||||
if(tag_south_con && tag_south == 1)
|
||||
P.concentration = tag_south_con
|
||||
con += max(0, tag_south_con)
|
||||
if(EAST)
|
||||
if(tag_east_con && tag_east == 1)
|
||||
P.concentration = tag_east_con
|
||||
con += max(0, tag_east_con)
|
||||
if(WEST)
|
||||
if(tag_west_con && tag_west == 1)
|
||||
P.concentration = tag_west_con
|
||||
con += max(0, tag_west_con)
|
||||
|
||||
//mappers who are bad at maths will be punished (total concentration must be 100%)
|
||||
if(con != 1)
|
||||
tag_north_con = null
|
||||
tag_south_con = null
|
||||
tag_east_con = null
|
||||
tag_west_con = null
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/Destroy()
|
||||
inputs.Cut()
|
||||
output = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/sort_ports()
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(P.update)
|
||||
if(output == P)
|
||||
output = null
|
||||
if(inputs.Find(P))
|
||||
inputs -= P
|
||||
|
||||
P.air.volume = 200
|
||||
switch(P.mode)
|
||||
if(ATM_INPUT)
|
||||
inputs += P
|
||||
if(ATM_OUTPUT)
|
||||
output = P
|
||||
|
||||
if(!mapper_set())
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
P.concentration = 1 / max(1, inputs.len)
|
||||
|
||||
if(output)
|
||||
output.air.volume *= 0.75 * inputs.len
|
||||
output.concentration = 1
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/proc/mapper_set()
|
||||
return (tag_north_con || tag_south_con || tag_east_con || tag_west_con)
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/error_check()
|
||||
if(!output || !inputs)
|
||||
return 1
|
||||
if(inputs.len < 2 || inputs.len > 3) //requires 2 or 3 inputs ~otherwise why are you using a mixer?
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/process_atmos()
|
||||
..()
|
||||
if(!on)
|
||||
return 0
|
||||
|
||||
var/datum/gas_mixture/output_air = output.air
|
||||
var/output_pressure = output_air.return_pressure()
|
||||
|
||||
|
||||
if(output_pressure >= target_pressure * 0.999)
|
||||
//No need to mix if target is already full! - 0.1% margin of error so we minimize processing minor gas volumes
|
||||
return 1
|
||||
|
||||
//Calculate necessary moles to transfer using PV=nRT
|
||||
|
||||
var/pressure_delta = target_pressure - output_pressure
|
||||
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
if(P.air.return_temperature() > 0)
|
||||
P.transfer_moles = (P.concentration * pressure_delta) * output_air.return_volume() / (P.air.return_temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
var/ratio_check = null
|
||||
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
if(!P.transfer_moles)
|
||||
return 1
|
||||
if(P.air.total_moles() < P.transfer_moles)
|
||||
ratio_check = 1
|
||||
continue
|
||||
|
||||
if(ratio_check)
|
||||
var/list/ratio_list = new()
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
ratio_list.Add(P.air.total_moles() / P.transfer_moles)
|
||||
|
||||
var/ratio = min(ratio_list)
|
||||
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
P.transfer_moles *= ratio
|
||||
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
if(P.transfer_moles > 0)
|
||||
output_air.merge(P.air.remove(P.transfer_moles))
|
||||
P.parent.update = 1
|
||||
P.transfer_moles = 0
|
||||
|
||||
output.parent.update = 1
|
||||
|
||||
return 1
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0)
|
||||
usr.set_machine(src)
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/ui_data(mob/user, datum/topic_state/state)
|
||||
var/data[0]
|
||||
|
||||
data["power"] = on
|
||||
data["config"] = configuring
|
||||
|
||||
var/portData[0]
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(!configuring && P.mode == 0)
|
||||
continue
|
||||
|
||||
var/input = 0
|
||||
var/output = 0
|
||||
switch(P.mode)
|
||||
if(ATM_INPUT)
|
||||
input = 1
|
||||
if(ATM_OUTPUT)
|
||||
output = 1
|
||||
|
||||
portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \
|
||||
"concentration" = P.concentration, \
|
||||
"input" = input, \
|
||||
"output" = output, \
|
||||
"con_lock" = P.con_lock)
|
||||
|
||||
if(portData.len)
|
||||
data["ports"] = portData
|
||||
if(output)
|
||||
data["pressure"] = target_pressure
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
switch(href_list["command"])
|
||||
if("power")
|
||||
if(!configuring)
|
||||
on = !on
|
||||
else
|
||||
on = 0
|
||||
if("configure")
|
||||
configuring = !configuring
|
||||
if(configuring)
|
||||
on = 0
|
||||
|
||||
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
|
||||
if(configuring && !on)
|
||||
switch(href_list["command"])
|
||||
if("set_pressure")
|
||||
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num
|
||||
target_pressure = between(0, new_pressure, 4500)
|
||||
if("switch_mode")
|
||||
switch_mode(dir_flag(href_list["dir"]), href_list["mode"])
|
||||
if("switch_con")
|
||||
change_concentration(dir_flag(href_list["dir"]))
|
||||
if("switch_conlock")
|
||||
con_lock(dir_flag(href_list["dir"]))
|
||||
|
||||
update_icon()
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE)
|
||||
if(mode != ATM_INPUT && mode != ATM_OUTPUT)
|
||||
switch(mode)
|
||||
if("in")
|
||||
mode = ATM_INPUT
|
||||
if("out")
|
||||
mode = ATM_OUTPUT
|
||||
else
|
||||
mode = ATM_NONE
|
||||
|
||||
for(var/datum/omni_port/P in ports)
|
||||
var/old_mode = P.mode
|
||||
if(P.dir == port)
|
||||
switch(mode)
|
||||
if(ATM_INPUT)
|
||||
if(P.mode == ATM_OUTPUT)
|
||||
return
|
||||
P.mode = mode
|
||||
if(ATM_OUTPUT)
|
||||
P.mode = mode
|
||||
if(ATM_NONE)
|
||||
if(P.mode == ATM_OUTPUT)
|
||||
return
|
||||
if(P.mode == ATM_INPUT && inputs.len > 2)
|
||||
P.mode = mode
|
||||
else if(P.mode == ATM_OUTPUT && mode == ATM_OUTPUT)
|
||||
P.mode = ATM_INPUT
|
||||
if(P.mode != old_mode)
|
||||
switch(P.mode)
|
||||
if(ATM_NONE)
|
||||
initialize_directions &= ~P.dir
|
||||
P.disconnect()
|
||||
else
|
||||
initialize_directions |= P.dir
|
||||
P.connect()
|
||||
P.update = 1
|
||||
|
||||
update_ports()
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH)
|
||||
tag_north_con = null
|
||||
tag_south_con = null
|
||||
tag_east_con = null
|
||||
tag_west_con = null
|
||||
|
||||
var/old_con = 0
|
||||
var/non_locked = 0
|
||||
var/remain_con = 1
|
||||
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
if(P.dir == port)
|
||||
old_con = P.concentration
|
||||
else if(!P.con_lock)
|
||||
non_locked++
|
||||
else
|
||||
remain_con -= P.concentration
|
||||
|
||||
//return if no adjustable ports
|
||||
if(non_locked < 1)
|
||||
return
|
||||
|
||||
var/new_con = (input(usr,"Enter a new concentration (0-[round(remain_con * 100, 0.5)])%","Concentration control", min(remain_con, old_con)*100) as num) / 100
|
||||
|
||||
//cap it between 0 and the max remaining concentration
|
||||
new_con = between(0, new_con, remain_con)
|
||||
|
||||
//new_con = min(remain_con, new_con)
|
||||
|
||||
//clamp remaining concentration so we don't go into negatives
|
||||
remain_con = max(0, remain_con - new_con)
|
||||
|
||||
//distribute remaining concentration between unlocked ports evenly
|
||||
remain_con /= max(1, non_locked)
|
||||
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
if(P.dir == port)
|
||||
P.concentration = new_con
|
||||
else if(!P.con_lock)
|
||||
P.concentration = remain_con
|
||||
|
||||
/obj/machinery/atmospherics/omni/mixer/proc/con_lock(var/port = NORTH)
|
||||
for(var/datum/omni_port/P in inputs)
|
||||
if(P.dir == port)
|
||||
P.con_lock = !P.con_lock
|
||||
@@ -1,302 +0,0 @@
|
||||
//--------------------------------------------
|
||||
// Base omni device
|
||||
//--------------------------------------------
|
||||
/obj/machinery/atmospherics/omni
|
||||
name = "omni device"
|
||||
icon = 'icons/atmos/omni_devices.dmi'
|
||||
icon_state = "base"
|
||||
use_power = IDLE_POWER_USE
|
||||
initialize_directions = 0
|
||||
|
||||
can_unwrench = 1
|
||||
|
||||
var/on = 0
|
||||
var/configuring = 0
|
||||
var/target_pressure = ONE_ATMOSPHERE
|
||||
|
||||
var/tag_north = ATM_NONE
|
||||
var/tag_south = ATM_NONE
|
||||
var/tag_east = ATM_NONE
|
||||
var/tag_west = ATM_NONE
|
||||
|
||||
var/overlays_on[5]
|
||||
var/overlays_off[5]
|
||||
var/overlays_error[2]
|
||||
var/underlays_current[4]
|
||||
|
||||
var/list/ports = new()
|
||||
|
||||
/obj/machinery/atmospherics/omni/New()
|
||||
..()
|
||||
icon_state = "base"
|
||||
|
||||
ports = new()
|
||||
for(var/d in GLOB.cardinal)
|
||||
var/datum/omni_port/new_port = new(src, d)
|
||||
switch(d)
|
||||
if(NORTH)
|
||||
new_port.mode = tag_north
|
||||
if(SOUTH)
|
||||
new_port.mode = tag_south
|
||||
if(EAST)
|
||||
new_port.mode = tag_east
|
||||
if(WEST)
|
||||
new_port.mode = tag_west
|
||||
if(new_port.mode > 0)
|
||||
initialize_directions |= d
|
||||
ports += new_port
|
||||
|
||||
build_icons()
|
||||
|
||||
/obj/machinery/atmospherics/omni/Destroy()
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(P.node)
|
||||
P.node.disconnect(src)
|
||||
P.node = null
|
||||
nullifyPipenet(P.parent)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/omni/atmos_init()
|
||||
..()
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(P.node || P.mode == 0)
|
||||
continue
|
||||
for(var/obj/machinery/atmospherics/target in get_step(src, P.dir))
|
||||
if(target.initialize_directions & get_dir(target,src))
|
||||
P.node = target
|
||||
break
|
||||
|
||||
for(var/datum/omni_port/P in ports)
|
||||
P.update = 1
|
||||
|
||||
update_ports()
|
||||
|
||||
/obj/machinery/atmospherics/omni/update_icon()
|
||||
..()
|
||||
|
||||
if(stat & NOPOWER)
|
||||
overlays = overlays_off
|
||||
on = 0
|
||||
else if(error_check())
|
||||
overlays = overlays_error
|
||||
on = 0
|
||||
else
|
||||
overlays = on ? (overlays_on) : (overlays_off)
|
||||
|
||||
underlays = underlays_current
|
||||
|
||||
/obj/machinery/atmospherics/omni/proc/error_check()
|
||||
return
|
||||
|
||||
/obj/machinery/atmospherics/omni/power_change()
|
||||
var/old_stat = stat
|
||||
..()
|
||||
if(old_stat != stat)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/omni/attackby(var/obj/item/W as obj, var/mob/user as mob, params)
|
||||
if(!istype(W, /obj/item/wrench))
|
||||
return ..()
|
||||
|
||||
if(can_unwrench)
|
||||
var/int_pressure = 0
|
||||
for(var/datum/omni_port/P in ports)
|
||||
int_pressure += P.air.return_pressure()
|
||||
var/datum/gas_mixture/env_air = loc.return_air()
|
||||
if((int_pressure - env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
|
||||
to_chat(user, "<span class='danger'>You cannot unwrench [src], it is too exerted due to internal pressure.</span>")
|
||||
add_fingerprint(user)
|
||||
return 1
|
||||
playsound(loc, W.usesound, 50, 1)
|
||||
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
|
||||
if(do_after(user, 40 * W.toolspeed, target = src))
|
||||
user.visible_message( \
|
||||
"[user] unfastens \the [src].", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
"You hear a ratchet.")
|
||||
new /obj/item/pipe(loc, make_from=src)
|
||||
qdel(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/omni/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
|
||||
add_fingerprint(usr)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/omni/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/omni/proc/build_icons()
|
||||
if(!check_icon_cache())
|
||||
return
|
||||
|
||||
var/core_icon = null
|
||||
if(istype(src, /obj/machinery/atmospherics/omni/mixer))
|
||||
core_icon = "mixer"
|
||||
else if(istype(src, /obj/machinery/atmospherics/omni/filter))
|
||||
core_icon = "filter"
|
||||
else
|
||||
return
|
||||
|
||||
//directional icons are layers 1-4, with the core icon on layer 5
|
||||
if(core_icon)
|
||||
overlays_off[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon)
|
||||
overlays_on[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon + "_glow")
|
||||
|
||||
overlays_error[1] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon)
|
||||
overlays_error[2] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , "error")
|
||||
|
||||
/obj/machinery/atmospherics/omni/proc/update_port_icons()
|
||||
if(!check_icon_cache())
|
||||
return
|
||||
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(P.update)
|
||||
var/ref_layer = 0
|
||||
switch(P.dir)
|
||||
if(NORTH)
|
||||
ref_layer = 1
|
||||
if(SOUTH)
|
||||
ref_layer = 2
|
||||
if(EAST)
|
||||
ref_layer = 3
|
||||
if(WEST)
|
||||
ref_layer = 4
|
||||
|
||||
if(!ref_layer)
|
||||
continue
|
||||
|
||||
var/list/port_icons = select_port_icons(P)
|
||||
if(port_icons)
|
||||
if(P.node)
|
||||
underlays_current[ref_layer] = port_icons["pipe_icon"]
|
||||
else
|
||||
underlays_current[ref_layer] = null
|
||||
overlays_off[ref_layer] = port_icons["off_icon"]
|
||||
overlays_on[ref_layer] = port_icons["on_icon"]
|
||||
else
|
||||
underlays_current[ref_layer] = null
|
||||
overlays_off[ref_layer] = null
|
||||
overlays_on[ref_layer] = null
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/omni/proc/select_port_icons(var/datum/omni_port/P)
|
||||
if(!istype(P))
|
||||
return
|
||||
|
||||
if(P.mode > 0)
|
||||
var/ic_dir = dir_name(P.dir)
|
||||
var/ic_on = ic_dir
|
||||
var/ic_off = ic_dir
|
||||
switch(P.mode)
|
||||
if(ATM_INPUT)
|
||||
ic_on += "_in_glow"
|
||||
ic_off += "_in"
|
||||
if(ATM_OUTPUT)
|
||||
ic_on += "_out_glow"
|
||||
ic_off += "_out"
|
||||
if(ATM_O2 to ATM_N2O)
|
||||
ic_on += "_filter"
|
||||
ic_off += "_out"
|
||||
|
||||
ic_on = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_on)
|
||||
ic_off = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_off)
|
||||
|
||||
var/pipe_state
|
||||
var/turf/T = get_turf(src)
|
||||
if(!istype(T))
|
||||
return
|
||||
if(T.intact && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 )
|
||||
//pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node))
|
||||
pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down")
|
||||
else
|
||||
//pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node))
|
||||
pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact")
|
||||
|
||||
return list("on_icon" = ic_on, "off_icon" = ic_off, "pipe_icon" = pipe_state)
|
||||
|
||||
/obj/machinery/atmospherics/omni/update_underlays()
|
||||
for(var/datum/omni_port/P in ports)
|
||||
P.update = 1
|
||||
update_ports()
|
||||
|
||||
/obj/machinery/atmospherics/omni/hide(var/i)
|
||||
update_underlays()
|
||||
|
||||
/obj/machinery/atmospherics/omni/proc/update_ports()
|
||||
sort_ports()
|
||||
update_port_icons()
|
||||
for(var/datum/omni_port/P in ports)
|
||||
P.update = 0
|
||||
|
||||
/obj/machinery/atmospherics/omni/proc/sort_ports()
|
||||
return
|
||||
|
||||
// Pipenet procs
|
||||
/obj/machinery/atmospherics/omni/build_network(remove_deferral = FALSE)
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(!P.parent)
|
||||
P.parent = new /datum/pipeline()
|
||||
P.parent.build_pipeline(src)
|
||||
..()
|
||||
|
||||
/obj/machinery/atmospherics/omni/disconnect(obj/machinery/atmospherics/reference)
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(reference == P.node)
|
||||
if(istype(P.node, /obj/machinery/atmospherics/pipe))
|
||||
qdel(P.parent)
|
||||
P.node = null
|
||||
update_ports()
|
||||
|
||||
/obj/machinery/atmospherics/omni/nullifyPipenet(datum/pipeline/P)
|
||||
..()
|
||||
if(!P)
|
||||
return
|
||||
for(var/datum/omni_port/PO in ports)
|
||||
if(P == PO.parent)
|
||||
PO.parent.other_airs -= PO.air
|
||||
PO.parent = null
|
||||
|
||||
/obj/machinery/atmospherics/omni/returnPipenetAir(datum/pipeline/P)
|
||||
for(var/datum/omni_port/PO in ports)
|
||||
if(P == PO.parent)
|
||||
return PO.air
|
||||
|
||||
/obj/machinery/atmospherics/omni/pipeline_expansion(datum/pipeline/P)
|
||||
if(P)
|
||||
for(var/datum/omni_port/PO in ports)
|
||||
if(PO.parent == P)
|
||||
return list(PO.node)
|
||||
else
|
||||
var/list/nodes = list()
|
||||
for(var/datum/omni_port/PO in ports)
|
||||
nodes += PO.node
|
||||
|
||||
return nodes
|
||||
|
||||
/obj/machinery/atmospherics/omni/setPipenet(datum/pipeline/P, obj/machinery/atmospherics/A)
|
||||
for(var/datum/omni_port/PO in ports)
|
||||
if(A == PO.node)
|
||||
PO.parent = P
|
||||
|
||||
/obj/machinery/atmospherics/omni/returnPipenet(obj/machinery/atmospherics/A)
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(A == P.node)
|
||||
return P.parent
|
||||
|
||||
/obj/machinery/atmospherics/omni/replacePipenet(datum/pipeline/Old, datum/pipeline/New)
|
||||
for(var/datum/omni_port/P in ports)
|
||||
if(Old == P.parent)
|
||||
P.parent = New
|
||||
|
||||
|
||||
/obj/machinery/atmospherics/omni/process_atmos()
|
||||
..()
|
||||
for(var/datum/omni_port/port in ports)
|
||||
if(!port.parent)
|
||||
return 0
|
||||
return 1
|
||||
@@ -1,26 +1,39 @@
|
||||
|
||||
/// Nothing will be filtered.
|
||||
#define FILTER_NOTHING -1
|
||||
/// Plasma, and Oxygen Agent B.
|
||||
#define FILTER_TOXINS 0
|
||||
/// Oxygen only.
|
||||
#define FILTER_OXYGEN 1
|
||||
/// Nitrogen only.
|
||||
#define FILTER_NITROGEN 2
|
||||
/// Carbon dioxide only.
|
||||
#define FILTER_CO2 3
|
||||
/// Nitrous oxide only.
|
||||
#define FILTER_N2O 4
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter
|
||||
name = "gas filter"
|
||||
icon = 'icons/atmos/filter.dmi'
|
||||
icon_state = "map"
|
||||
|
||||
can_unwrench = 1
|
||||
|
||||
name = "gas filter"
|
||||
|
||||
can_unwrench = TRUE
|
||||
/// The amount of pressure the filter wants to operate at.
|
||||
var/target_pressure = ONE_ATMOSPHERE
|
||||
|
||||
var/filter_type = 0
|
||||
/*
|
||||
Filter types:
|
||||
-1: Nothing
|
||||
0: Toxins: Toxins, Oxygen Agent B
|
||||
1: Oxygen: Oxygen ONLY
|
||||
2: Nitrogen: Nitrogen ONLY
|
||||
3: Carbon Dioxide: Carbon Dioxide ONLY
|
||||
4: Sleeping Agent (N2O)
|
||||
*/
|
||||
|
||||
var/frequency = 0
|
||||
/// The type of gas we want to filter. Valid values that go here are from the `FILTER` defines at the top of the file.
|
||||
var/filter_type = FILTER_NOTHING
|
||||
/// The frequency of the filter. Used with `radio_connection`.
|
||||
var/frequency = NONE
|
||||
/// A reference to the filter's `datum/radio_frequency`.
|
||||
var/datum/radio_frequency/radio_connection
|
||||
/// A list of available filter options. Used with `tgui_data`.
|
||||
var/list/filter_list = list(
|
||||
"Nothing" = FILTER_NOTHING,
|
||||
"Plasma" = FILTER_TOXINS,
|
||||
"O2" = FILTER_OXYGEN,
|
||||
"N2" = FILTER_NITROGEN,
|
||||
"CO2" = FILTER_CO2,
|
||||
"N2O" = FILTER_N2O
|
||||
)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/CtrlClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
@@ -146,26 +159,26 @@ Filter types:
|
||||
filtered_out.temperature = removed.temperature
|
||||
|
||||
switch(filter_type)
|
||||
if(0) //removing hydrocarbons
|
||||
if(FILTER_TOXINS)
|
||||
filtered_out.toxins = removed.toxins
|
||||
removed.toxins = 0
|
||||
|
||||
filtered_out.agent_b = removed.agent_b
|
||||
removed.agent_b = 0
|
||||
|
||||
if(1) //removing O2
|
||||
if(FILTER_OXYGEN)
|
||||
filtered_out.oxygen = removed.oxygen
|
||||
removed.oxygen = 0
|
||||
|
||||
if(2) //removing N2
|
||||
if(FILTER_NITROGEN)
|
||||
filtered_out.nitrogen = removed.nitrogen
|
||||
removed.nitrogen = 0
|
||||
|
||||
if(3) //removing CO2
|
||||
if(FILTER_CO2)
|
||||
filtered_out.carbon_dioxide = removed.carbon_dioxide
|
||||
removed.carbon_dioxide = 0
|
||||
|
||||
if(4)//removing N2O
|
||||
if(FILTER_N2O)
|
||||
filtered_out.sleeping_agent = removed.sleeping_agent
|
||||
removed.sleeping_agent = 0
|
||||
else
|
||||
@@ -188,7 +201,7 @@ Filter types:
|
||||
..()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/attack_hand(mob/user)
|
||||
if(..())
|
||||
@@ -199,53 +212,56 @@ Filter types:
|
||||
return
|
||||
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/atmospherics/trinary/filter/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
user.set_machine(src)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "atmos_filter.tmpl", name, 475, 155, state = state)
|
||||
ui = new(user, src, ui_key, "AtmosFilter", name, 380, 140, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["on"] = on
|
||||
data["pressure"] = round(target_pressure)
|
||||
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
|
||||
data["filter_type"] = filter_type
|
||||
/obj/machinery/atmospherics/trinary/filter/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"on" = on,
|
||||
"pressure" = round(target_pressure),
|
||||
"max_pressure" = round(MAX_OUTPUT_PRESSURE),
|
||||
"filter_type" = filter_type
|
||||
)
|
||||
data["filter_type_list"] = list()
|
||||
for(var/label in filter_list)
|
||||
data["filter_type_list"] += list(list("label" = label, "gas_type" = filter_list[label]))
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
|
||||
/obj/machinery/atmospherics/trinary/filter/tgui_act(action, list/params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
if(href_list["power"])
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
. = TRUE
|
||||
if(href_list["pressure"])
|
||||
var/pressure = href_list["pressure"]
|
||||
if(pressure == "max")
|
||||
pressure = MAX_OUTPUT_PRESSURE
|
||||
. = TRUE
|
||||
else if(pressure == "input")
|
||||
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
|
||||
if(!isnull(pressure) && !..())
|
||||
. = TRUE
|
||||
else if(text2num(pressure) != null)
|
||||
pressure = text2num(pressure)
|
||||
. = TRUE
|
||||
if(.)
|
||||
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
if(href_list["filter"])
|
||||
filter_type = text2num(href_list["filter"])
|
||||
investigate_log("was set to filter [filter_type] by [key_name(usr)]", "atmos")
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("power")
|
||||
toggle()
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
return TRUE
|
||||
|
||||
update_icon()
|
||||
SSnanoui.update_uis(src)
|
||||
if("set_filter")
|
||||
filter_type = text2num(params["filter"])
|
||||
investigate_log("was set to filter [filter_type] by [key_name(usr)]", "atmos")
|
||||
return TRUE
|
||||
|
||||
if("max_pressure")
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
. = TRUE
|
||||
|
||||
if("min_pressure")
|
||||
target_pressure = 0
|
||||
. = TRUE
|
||||
|
||||
if("custom_pressure")
|
||||
target_pressure = clamp(text2num(params["pressure"]), 0, MAX_OUTPUT_PRESSURE)
|
||||
. = TRUE
|
||||
if(.)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
|
||||
/obj/machinery/atmospherics/trinary/filter/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/pen))
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
return 1
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/attack_hand(mob/user)
|
||||
if(..())
|
||||
@@ -163,62 +163,62 @@
|
||||
return
|
||||
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/atmospherics/trinary/mixer/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
user.set_machine(src)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "atmos_mixer.tmpl", name, 370, 165, state = state)
|
||||
ui = new(user, src, ui_key, "AtmosMixer", name, 330, 165, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["on"] = on
|
||||
data["pressure"] = round(target_pressure)
|
||||
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
|
||||
data["node1_concentration"] = round(node1_concentration*100)
|
||||
data["node2_concentration"] = round(node2_concentration*100)
|
||||
/obj/machinery/atmospherics/trinary/mixer/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"on" = on,
|
||||
"pressure" = round(target_pressure, 0.01),
|
||||
"max_pressure" = MAX_OUTPUT_PRESSURE,
|
||||
"node1_concentration" = round(node1_concentration * 100),
|
||||
"node2_concentration" = round(node2_concentration * 100)
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
|
||||
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/tgui_act(action, list/params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
if(href_list["power"])
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
. = TRUE
|
||||
if(href_list["pressure"])
|
||||
var/pressure = href_list["pressure"]
|
||||
if(pressure == "max")
|
||||
pressure = MAX_OUTPUT_PRESSURE
|
||||
. = TRUE
|
||||
else if(pressure == "input")
|
||||
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
|
||||
if(!isnull(pressure) && !..())
|
||||
. = TRUE
|
||||
else if(text2num(pressure) != null)
|
||||
pressure = text2num(pressure)
|
||||
. = TRUE
|
||||
if(.)
|
||||
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
if(href_list["node1"])
|
||||
var/value = text2num(href_list["node1"])
|
||||
node1_concentration = max(0, min(1, node1_concentration + value))
|
||||
node2_concentration = max(0, min(1, node2_concentration - value))
|
||||
investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos")
|
||||
. = TRUE
|
||||
if(href_list["node2"])
|
||||
var/value = text2num(href_list["node2"])
|
||||
node2_concentration = max(0, min(1, node2_concentration + value))
|
||||
node1_concentration = max(0, min(1, node1_concentration - value))
|
||||
investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos")
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("power")
|
||||
toggle()
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
|
||||
return TRUE
|
||||
|
||||
update_icon()
|
||||
SSnanoui.update_uis(src)
|
||||
if("set_node")
|
||||
if(params["node_name"] == "Node 1")
|
||||
node1_concentration = clamp(round(text2num(params["concentration"]), 0.01), 0, 1)
|
||||
node2_concentration = round(1 - node1_concentration, 0.01)
|
||||
investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos")
|
||||
return TRUE
|
||||
else
|
||||
node2_concentration = clamp(round(text2num(params["concentration"]), 0.01), 0, 1)
|
||||
node1_concentration = round(1 - node2_concentration, 0.01)
|
||||
investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos")
|
||||
return TRUE
|
||||
|
||||
if("max_pressure")
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
. = TRUE
|
||||
|
||||
if("min_pressure")
|
||||
target_pressure = 0
|
||||
. = TRUE
|
||||
|
||||
if("custom_pressure")
|
||||
target_pressure = clamp(text2num(params["pressure"]), 0, MAX_OUTPUT_PRESSURE)
|
||||
. = TRUE
|
||||
if(.)
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
|
||||
|
||||
/obj/machinery/atmospherics/trinary/mixer/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/pen))
|
||||
|
||||
@@ -128,66 +128,56 @@
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_pump/process_atmos()
|
||||
..()
|
||||
if((stat & (NOPOWER|BROKEN)))
|
||||
return 0
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return FALSE
|
||||
if(!node)
|
||||
on = 0
|
||||
on = FALSE
|
||||
//broadcast_status() // from now air alarm/control computer should request update purposely --rastaf0
|
||||
if(!on)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(welded)
|
||||
if(air_contents.return_pressure() >= weld_burst_pressure && prob(5)) //the weld is on but the cover is welded shut, can it withstand the internal pressure?
|
||||
visible_message("<span class='danger'>The welded cover of [src] bursts open!</span>")
|
||||
for(var/mob/M in range(1, src))
|
||||
for(var/mob/living/M in range(1))
|
||||
unsafe_pressure_release(M, air_contents.return_pressure()) //let's send everyone flying
|
||||
welded = FALSE
|
||||
update_icon()
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
var/environment_pressure = environment.return_pressure()
|
||||
|
||||
if(pump_direction) //internal -> external
|
||||
var/pressure_delta = 10000
|
||||
|
||||
if(pressure_checks&1)
|
||||
if(pressure_checks & 1)
|
||||
pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
|
||||
if(pressure_checks&2)
|
||||
if(pressure_checks & 2)
|
||||
pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound))
|
||||
|
||||
if(pressure_delta > 0.5)
|
||||
if(air_contents.temperature > 0)
|
||||
var/transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
|
||||
|
||||
loc.assume_air(removed)
|
||||
air_update_turf()
|
||||
|
||||
parent.update = 1
|
||||
if(pressure_delta > 0.5 && air_contents.temperature > 0)
|
||||
var/transfer_moles = pressure_delta * environment.volume / (air_contents.temperature * R_IDEAL_GAS_EQUATION)
|
||||
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
|
||||
loc.assume_air(removed)
|
||||
air_update_turf()
|
||||
parent.update = TRUE
|
||||
|
||||
else //external -> internal
|
||||
var/pressure_delta = 10000
|
||||
if(pressure_checks&1)
|
||||
if(pressure_checks & 1)
|
||||
pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound))
|
||||
if(pressure_checks&2)
|
||||
if(pressure_checks & 2)
|
||||
pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure()))
|
||||
|
||||
if(pressure_delta > 0.5)
|
||||
if(environment.temperature > 0)
|
||||
var/transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION)
|
||||
if(pressure_delta > 0.5 && environment.temperature > 0)
|
||||
var/transfer_moles = pressure_delta * air_contents.volume / (environment.temperature * R_IDEAL_GAS_EQUATION)
|
||||
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
|
||||
if(isnull(removed)) //in space
|
||||
return
|
||||
air_contents.merge(removed)
|
||||
air_update_turf()
|
||||
parent.update = TRUE
|
||||
|
||||
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
|
||||
if(isnull(removed)) //in space
|
||||
return
|
||||
|
||||
air_contents.merge(removed)
|
||||
air_update_turf()
|
||||
|
||||
parent.update = 1
|
||||
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//Radio remote control
|
||||
|
||||
@@ -386,11 +376,11 @@
|
||||
if(I.use_tool(src, user, 20, volume = I.tool_volume))
|
||||
if(!welded)
|
||||
welded = TRUE
|
||||
visible_message("<span class='notice'>[user] welds [src] shut!</span>",\
|
||||
user.visible_message("<span class='notice'>[user] welds [src] shut!</span>",\
|
||||
"<span class='notice'>You weld [src] shut!</span>")
|
||||
else
|
||||
welded = FALSE
|
||||
visible_message("<span class='notice'>[user] unwelds [src]!</span>",\
|
||||
user.visible_message("<span class='notice'>[user] unwelds [src]!</span>",\
|
||||
"<span class='notice'>You unweld [src]!</span>")
|
||||
update_icon()
|
||||
|
||||
|
||||
@@ -404,10 +404,10 @@
|
||||
if(I.use_tool(src, user, 20, volume = I.tool_volume))
|
||||
if(!welded)
|
||||
welded = TRUE
|
||||
visible_message("<span class='notice'>[user] welds [src] shut!</span>",\
|
||||
user.visible_message("<span class='notice'>[user] welds [src] shut!</span>",\
|
||||
"<span class='notice'>You weld [src] shut!</span>")
|
||||
else
|
||||
welded = FALSE
|
||||
visible_message("<span class='notice'>[user] unwelds [src]!</span>",\
|
||||
user.visible_message("<span class='notice'>[user] unwelds [src]!</span>",\
|
||||
"<span class='notice'>You unweld [src]!</span>")
|
||||
update_icon()
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
//var/list/underlays_intact[]
|
||||
//var/list/pipe_underlays_exposed[]
|
||||
//var/list/pipe_underlays_intact[]
|
||||
var/list/omni_icons[]
|
||||
|
||||
/datum/pipe_icon_manager/New()
|
||||
check_icons()
|
||||
@@ -53,8 +52,6 @@
|
||||
return manifold_icons[state + color]
|
||||
if("device")
|
||||
return device_icons[state]
|
||||
if("omni")
|
||||
return omni_icons[state]
|
||||
if("underlay")
|
||||
return underlays[state + dir + color]
|
||||
//if("underlay_intact")
|
||||
@@ -75,8 +72,6 @@
|
||||
gen_manifold_icons()
|
||||
if(!device_icons)
|
||||
gen_device_icons()
|
||||
if(!omni_icons)
|
||||
gen_omni_icons()
|
||||
//if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact)
|
||||
if(!underlays)
|
||||
gen_underlay_icons()
|
||||
@@ -150,18 +145,6 @@
|
||||
continue
|
||||
device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state)
|
||||
|
||||
/datum/pipe_icon_manager/proc/gen_omni_icons()
|
||||
if(!omni_icons)
|
||||
omni_icons = new()
|
||||
|
||||
var/icon/omni = new('icons/atmos/omni_devices.dmi')
|
||||
|
||||
for(var/state in omni.IconStates())
|
||||
if(!state || findtext(state, "map"))
|
||||
continue
|
||||
omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state)
|
||||
|
||||
|
||||
/datum/pipe_icon_manager/proc/gen_underlay_icons()
|
||||
|
||||
if(!underlays)
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
if(!R)
|
||||
return 1
|
||||
|
||||
atom/movable/proc/CanAtmosPass()
|
||||
/atom/movable/proc/CanAtmosPass()
|
||||
return 1
|
||||
|
||||
atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5)
|
||||
/atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5)
|
||||
return (!density || !height)
|
||||
|
||||
turf/CanPass(atom/movable/mover, turf/target, height=1.5)
|
||||
/turf/CanPass(atom/movable/mover, turf/target, height=1.5)
|
||||
if(!target) return 0
|
||||
|
||||
if(istype(mover)) // turf/Enter(...) will perform more advanced checks
|
||||
|
||||
@@ -473,7 +473,7 @@
|
||||
SSair.active_super_conductivity -= src
|
||||
return 0
|
||||
|
||||
turf/simulated/proc/consider_superconductivity(starting)
|
||||
/turf/simulated/proc/consider_superconductivity(starting)
|
||||
if(!thermal_conductivity)
|
||||
return 0
|
||||
|
||||
@@ -489,7 +489,7 @@ turf/simulated/proc/consider_superconductivity(starting)
|
||||
SSair.active_super_conductivity |= src
|
||||
return 1
|
||||
|
||||
turf/simulated/proc/radiate_to_spess() //Radiate excess tile heat to space
|
||||
/turf/simulated/proc/radiate_to_spess() //Radiate excess tile heat to space
|
||||
if(temperature > T0C) //Considering 0 degC as te break even point for radiation in and out
|
||||
var/delta_temperature = (temperature_archived - TCMB) //hardcoded space temperature
|
||||
if((heat_capacity > 0) && (abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER))
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/datum/stack
|
||||
var/list/stack = list()
|
||||
var/max_elements = 0
|
||||
|
||||
/datum/stack/New(list/elements,max)
|
||||
..()
|
||||
if(elements)
|
||||
stack = elements.Copy()
|
||||
if(max)
|
||||
max_elements = max
|
||||
|
||||
/datum/stack/proc/Pop()
|
||||
if(is_empty())
|
||||
return null
|
||||
. = stack[stack.len]
|
||||
stack.Cut(stack.len,0)
|
||||
|
||||
/datum/stack/proc/Push(element)
|
||||
if(max_elements && (stack.len+1 > max_elements))
|
||||
return null
|
||||
stack += element
|
||||
|
||||
/datum/stack/proc/Top()
|
||||
if(is_empty())
|
||||
return null
|
||||
. = stack[stack.len]
|
||||
|
||||
/datum/stack/proc/is_empty()
|
||||
. = stack.len ? 0 : 1
|
||||
|
||||
//Rotate entire stack left with the leftmost looping around to the right
|
||||
/datum/stack/proc/RotateLeft()
|
||||
if(is_empty())
|
||||
return 0
|
||||
. = stack[1]
|
||||
stack.Cut(1,2)
|
||||
Push(.)
|
||||
|
||||
//Rotate entire stack to the right with the rightmost looping around to the left
|
||||
/datum/stack/proc/RotateRight()
|
||||
if(is_empty())
|
||||
return 0
|
||||
. = stack[stack.len]
|
||||
stack.Cut(stack.len,0)
|
||||
stack.Insert(1,.)
|
||||
|
||||
|
||||
/datum/stack/proc/Copy()
|
||||
var/datum/stack/S=new()
|
||||
S.stack = stack.Copy()
|
||||
S.max_elements = max_elements
|
||||
return S
|
||||
|
||||
|
||||
/datum/stack/proc/Clear()
|
||||
stack.Cut()
|
||||
@@ -28,6 +28,12 @@
|
||||
#define AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS 1
|
||||
#define AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER 2
|
||||
|
||||
//used by airlocks and airlock wires.
|
||||
#define AICONTROLDISABLED_OFF 0 // Silicons can control the airlock normally.
|
||||
#define AICONTROLDISABLED_ON 1 // Silicons cannot control the airlock, but can hack the airlock.
|
||||
#define AICONTROLDISABLED_BYPASS 2 // Silicons can control the airlock because they succeeded on the hack
|
||||
#define AICONTROLDISABLED_PERMA 3 // Wire cutting an airlock on AICONTROLDISABLED_BYPASS toggles it between AICONTROLDISABLED_BYPASS and this.
|
||||
|
||||
//plastic flaps construction states
|
||||
#define PLASTIC_FLAPS_NORMAL 0
|
||||
#define PLASTIC_FLAPS_DETACHED 1
|
||||
|
||||
@@ -726,3 +726,7 @@
|
||||
#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt"
|
||||
///from monkey CtrlClickOn(): (/mob)
|
||||
#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl"
|
||||
|
||||
///SSalarm signals
|
||||
#define COMSIG_TRIGGERED_ALARM "ssalarm_triggered"
|
||||
#define COMSIG_CANCELLED_ALARM "ssalarm_cancelled"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#define INSTRUMENT_MIN_OCTAVE 1
|
||||
#define INSTRUMENT_MAX_OCTAVE 9
|
||||
#define INSTRUMENT_MIN_KEY 0
|
||||
#define INSTRUMENT_MAX_KEY 127
|
||||
|
||||
/// Max number of playing notes per instrument.
|
||||
#define CHANNELS_PER_INSTRUMENT 128
|
||||
|
||||
/// Distance multiplier that makes us not be impacted by 3d sound as much. This is a multiplier so lower it is the closer we will pretend to be to people.
|
||||
#define INSTRUMENT_DISTANCE_FALLOFF_BUFF 0.2
|
||||
/// How many tiles instruments have no falloff for
|
||||
#define INSTRUMENT_DISTANCE_NO_FALLOFF 3
|
||||
|
||||
/// Maximum length a note should ever go for
|
||||
#define INSTRUMENT_MAX_TOTAL_SUSTAIN (5 SECONDS)
|
||||
|
||||
/// These are per decisecond.
|
||||
#define INSTRUMENT_EXP_FALLOFF_MIN 1.025 //100/(1.025^50) calculated for [INSTRUMENT_MIN_SUSTAIN_DROPOFF] to be 30.
|
||||
#define INSTRUMENT_EXP_FALLOFF_MAX 10
|
||||
|
||||
/// Minimum volume for when the sound is considered dead.
|
||||
#define INSTRUMENT_MIN_SUSTAIN_DROPOFF 0.1
|
||||
|
||||
#define SUSTAIN_LINEAR 1
|
||||
#define SUSTAIN_EXPONENTIAL 2
|
||||
|
||||
// /datum/instrument instrument_flags
|
||||
#define INSTRUMENT_LEGACY (1<<0) //Legacy instrument. Implies INSTRUMENT_DO_NOT_AUTOSAMPLE
|
||||
#define INSTRUMENT_DO_NOT_AUTOSAMPLE (1<<1) //Do not automatically sample
|
||||
@@ -36,7 +36,7 @@ Be sure to include required js functions in your page, or it'll raise an excepti
|
||||
|
||||
And yes I know this is a proc in a defines file, but its highly relevant so it can be here
|
||||
*/
|
||||
proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null)
|
||||
/proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null)
|
||||
if(receiver && target_element && control_id) // && winexists(receiver, control_id))
|
||||
var/list/argums = list(target_element, new_content)
|
||||
if(callback)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define PLANE_SPACE_PARALLAX -90
|
||||
|
||||
#define FLOOR_PLANE -2
|
||||
#define FLOOR_OVERLAY_PLANE -1.5
|
||||
#define GAME_PLANE -1
|
||||
#define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals
|
||||
|
||||
|
||||
@@ -4,3 +4,8 @@
|
||||
#define SAY_LOG "Say"
|
||||
#define EMOTE_LOG "Emote"
|
||||
#define MISC_LOG "Misc"
|
||||
#define DEADCHAT_LOG "Deadchat"
|
||||
#define OOC_LOG "OOC"
|
||||
#define LOOC_LOG "LOOC"
|
||||
|
||||
#define ALL_LOGS list(ATTACK_LOG, DEFENSE_LOG, CONVERSION_LOG, SAY_LOG, EMOTE_LOG, DEADCHAT_LOG, OOC_LOG, LOOC_LOG, MISC_LOG)
|
||||
|
||||
@@ -92,3 +92,8 @@
|
||||
// Firelock states
|
||||
#define FD_OPEN 1
|
||||
#define FD_CLOSED 2
|
||||
|
||||
// Computer login types
|
||||
#define LOGIN_TYPE_NORMAL 1
|
||||
#define LOGIN_TYPE_AI 2
|
||||
#define LOGIN_TYPE_ROBOT 3
|
||||
|
||||
+60
-16
@@ -69,9 +69,6 @@
|
||||
#define ZONE_ACTIVE 1
|
||||
#define ZONE_SLEEPING 0
|
||||
|
||||
#define shuttle_time_in_station 1800 // 3 minutes in the station
|
||||
#define shuttle_time_to_arrive 6000 // 10 minutes to arrive
|
||||
|
||||
#define EVENT_LEVEL_MUNDANE 1
|
||||
#define EVENT_LEVEL_MODERATE 2
|
||||
#define EVENT_LEVEL_MAJOR 3
|
||||
@@ -245,28 +242,75 @@
|
||||
0.4,0.6,0.0,\
|
||||
0.2,0.2,0.6)
|
||||
|
||||
#define LIST_REPLACE_RENAME list("rebeccapurple" = "dark purple", "darkslategrey" = "dark grey", "darkolivegreen" = "dark green", "darkslateblue" = "dark blue",\
|
||||
"darkkhaki" = "khaki", "darkseagreen" = "light green", "midnightblue" = "blue", "lightgrey" = "light grey", "darkgrey" = "dark grey",\
|
||||
"steelblue" = "blue", "goldenrod" = "gold")
|
||||
/*
|
||||
Used for wire name appearances. Replaces the color name on the left with the one on the right.
|
||||
The color on the left is the one used as the actual color of the wire, but it doesn't look good when written.
|
||||
So, we need to replace the name to something that looks better.
|
||||
*/
|
||||
#define LIST_COLOR_RENAME \
|
||||
list( \
|
||||
"rebeccapurple" = "dark purple",\
|
||||
"darkslategrey" = "dark grey", \
|
||||
"darkolivegreen"= "dark green", \
|
||||
"darkslateblue" = "dark blue", \
|
||||
"darkkhaki" = "khaki", \
|
||||
"darkseagreen" = "light green",\
|
||||
"midnightblue" = "blue", \
|
||||
"lightgrey" = "light grey", \
|
||||
"darkgrey" = "dark grey", \
|
||||
"steelblue" = "blue", \
|
||||
"goldenrod" = "gold" \
|
||||
)
|
||||
|
||||
#define LIST_GREYSCALE_REPLACE list("red" = "lightgrey", "blue" = "grey", "green" = "grey", "orange" = "lightgrey", "brown" = "grey",\
|
||||
"gold" = "lightgrey", "cyan" = "lightgrey", "navy" = "grey", "purple" = "grey", "pink"= "lightgrey")
|
||||
/// Pure Black and white colorblindness. Every species except Vulpkanins and Tajarans will have this.
|
||||
#define GREYSCALE_COLOR_REPLACE \
|
||||
list( \
|
||||
"red" = "grey", \
|
||||
"blue" = "grey", \
|
||||
"green" = "grey", \
|
||||
"orange" = "light grey", \
|
||||
"brown" = "grey", \
|
||||
"gold" = "light grey", \
|
||||
"cyan" = "silver", \
|
||||
"magenta" = "grey", \
|
||||
"purple" = "grey", \
|
||||
"pink" = "light grey" \
|
||||
)
|
||||
|
||||
#define LIST_VULP_REPLACE list("pink" = "beige", "orange" = "goldenrod", "gold" = "goldenrod", "red" = "darkolivegreen", "brown" = "darkolivegreen",\
|
||||
"green" = "darkslategrey", "cyan" = "steelblue", "purple" = "darkslategrey", "navy" = "midnightblue")
|
||||
|
||||
#define LIST_TAJ_REPLACE list("red" = "rebeccapurple", "brown" = "rebeccapurple", "purple" = "darkslateblue", "blue" = "darkslateblue",\
|
||||
"green" = "darkolivegreen", "orange" = "darkkhaki", "gold" = "darkkhaki", "cyan" = "darkseagreen", \
|
||||
"navy" = "midnightblue", "pink" = "lightgrey")
|
||||
/// Red colorblindness. Vulpkanins/Wolpins have this.
|
||||
#define PROTANOPIA_COLOR_REPLACE \
|
||||
list( \
|
||||
"red" = "darkolivegreen", \
|
||||
"green" = "darkslategrey", \
|
||||
"orange" = "goldenrod", \
|
||||
"gold" = "goldenrod", \
|
||||
"brown" = "darkolivegreen", \
|
||||
"cyan" = "steelblue", \
|
||||
"magenta" = "blue", \
|
||||
"purple" = "darkslategrey", \
|
||||
"pink" = "beige" \
|
||||
)
|
||||
|
||||
/// Yellow-Blue colorblindness. Tajarans/Farwas have this.
|
||||
#define TRITANOPIA_COLOR_REPLACE \
|
||||
list( \
|
||||
"red" = "rebeccapurple", \
|
||||
"blue" = "darkslateblue", \
|
||||
"green" = "darkolivegreen", \
|
||||
"orange" = "darkkhaki", \
|
||||
"gold" = "darkkhaki", \
|
||||
"brown" = "rebeccapurple", \
|
||||
"cyan" = "darkseagreen", \
|
||||
"magenta" = "darkslateblue", \
|
||||
"purple" = "darkslateblue", \
|
||||
"pink" = "lightgrey" \
|
||||
)
|
||||
|
||||
//Gun trigger guards
|
||||
#define TRIGGER_GUARD_ALLOW_ALL -1
|
||||
#define TRIGGER_GUARD_NONE 0
|
||||
#define TRIGGER_GUARD_NORMAL 1
|
||||
|
||||
#define CLIENT_FROM_VAR(I) (ismob(I) ? I:client : (istype(I, /client) ? I : (istype(I, /datum/mind) ? I:current?:client : null)))
|
||||
|
||||
// Macro to get the current elapsed round time, rather than total world runtime
|
||||
#define ROUND_TIME (SSticker.round_start_time ? (world.time - SSticker.round_start_time) : 0)
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#define PIPE_TVALVE 18
|
||||
#define PIPE_MANIFOLD4W 19
|
||||
#define PIPE_CAP 20
|
||||
#define PIPE_OMNI_MIXER 21
|
||||
#define PIPE_OMNI_FILTER 22
|
||||
#define PIPE_UNIVERSAL 23
|
||||
#define PIPE_SUPPLY_STRAIGHT 24
|
||||
#define PIPE_SUPPLY_BENT 25
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#define CHANNEL_HIGHEST_AVAILABLE 1017
|
||||
|
||||
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
|
||||
|
||||
#define SOUND_MINIMUM_PRESSURE 10
|
||||
#define FALLOFF_SOUNDS 0.5
|
||||
|
||||
+3
-10
@@ -22,16 +22,9 @@
|
||||
|
||||
// these define the time taken for the shuttle to get to SS13
|
||||
// and the time before it leaves again
|
||||
#define SHUTTLE_PREPTIME 300 // 5 minutes = 300 seconds - after this time, the shuttle departs centcom and cannot be recalled
|
||||
#define SHUTTLE_LEAVETIME 180 // 3 minutes = 180 seconds - the duration for which the shuttle will wait at the station after arriving
|
||||
#define SHUTTLE_TRANSIT_DURATION 300 // 5 minutes = 300 seconds - how long it takes for the shuttle to get to the station
|
||||
#define SHUTTLE_TRANSIT_DURATION_RETURN 120 // 2 minutes = 120 seconds - for some reason it takes less time to come back, go figure.
|
||||
|
||||
//Ferry shuttle processing status
|
||||
#define IDLE_STATE 0
|
||||
#define WAIT_LAUNCH 1
|
||||
#define WAIT_ARRIVE 2
|
||||
#define WAIT_FINISH 3
|
||||
#define SHUTTLE_CALLTIME 6000 //10 minutes = 6000 deciseconds - time taken for emergency shuttle to reach the station when called (in deciseconds)
|
||||
#define SHUTTLE_DOCKTIME 1800 //3 minutes = 1800 deciseconds - time taken for emergency shuttle to leave again once it has docked (in deciseconds)
|
||||
#define SHUTTLE_ESCAPETIME 1200 //2 minutes = 1200 deciseconds - time taken for emergency shuttle to reach a safe distance after leaving station (in deciseconds)
|
||||
|
||||
//shuttle mode defines
|
||||
#define SHUTTLE_IGNITING 0
|
||||
|
||||
@@ -45,11 +45,13 @@
|
||||
// Subsystems shutdown in the reverse of the order they initialize in
|
||||
// The numbers just define the ordering, they are meaningless otherwise.
|
||||
#define INIT_ORDER_TITLE 100 // This **MUST** load first or people will se blank lobby screens
|
||||
#define INIT_ORDER_GARBAGE 19
|
||||
#define INIT_ORDER_DBCORE 18
|
||||
#define INIT_ORDER_BLACKBOX 17
|
||||
#define INIT_ORDER_SERVER_MAINT 16
|
||||
#define INIT_ORDER_INPUT 15
|
||||
#define INIT_ORDER_GARBAGE 21
|
||||
#define INIT_ORDER_DBCORE 20
|
||||
#define INIT_ORDER_BLACKBOX 19
|
||||
#define INIT_ORDER_CLEANUP 18
|
||||
#define INIT_ORDER_INPUT 17
|
||||
#define INIT_ORDER_SOUNDS 16
|
||||
#define INIT_ORDER_INSTRUMENTS 15
|
||||
#define INIT_ORDER_RESEARCH 14
|
||||
#define INIT_ORDER_EVENTS 13
|
||||
#define INIT_ORDER_JOBS 12
|
||||
@@ -80,8 +82,7 @@
|
||||
#define INIT_ORDER_NANOMOB -23
|
||||
#define INIT_ORDER_SQUEAK -40
|
||||
#define INIT_ORDER_PATH -50
|
||||
#define INIT_ORDER_PERSISTENCE -95
|
||||
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
|
||||
#define INIT_ORDER_PERSISTENCE -95
|
||||
|
||||
// Subsystem fire priority, from lowest to highest priority
|
||||
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
|
||||
@@ -89,7 +90,7 @@
|
||||
#define FIRE_PRIORITY_NANOMOB 10
|
||||
#define FIRE_PRIORITY_NIGHTSHIFT 10
|
||||
#define FIRE_PRIORITY_IDLE_NPC 10
|
||||
#define FIRE_PRIORITY_SERVER_MAINT 10
|
||||
#define FIRE_PRIORITY_CLEANUP 10
|
||||
#define FIRE_PRIORITY_TICKETS 10
|
||||
#define FIRE_PRIORITY_RESEARCH 10
|
||||
#define FIRE_PRIORITY_GARBAGE 15
|
||||
@@ -113,7 +114,6 @@
|
||||
#define FIRE_PRIORITY_MOBS 100
|
||||
#define FIRE_PRIORITY_NANOUI 110
|
||||
#define FIRE_PRIORITY_TICKER 200
|
||||
#define FIRE_PRIORITY_CHAT 400
|
||||
#define FIRE_PRIORITY_OVERLAYS 500
|
||||
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// TGUI defines
|
||||
#define TGUI_MODAL_INPUT_MAX_LENGTH 1024
|
||||
#define TGUI_MODAL_INPUT_MAX_LENGTH_NAME 64 // Names for generally anything don't go past 32, let alone 64.
|
||||
|
||||
#define TGUI_MODAL_OPEN 1
|
||||
#define TGUI_MODAL_DELEGATE 2
|
||||
#define TGUI_MODAL_ANSWER 3
|
||||
#define TGUI_MODAL_CLOSE 4
|
||||
@@ -0,0 +1,77 @@
|
||||
// Wire defines for all machines/items.
|
||||
|
||||
// Miscellaneous
|
||||
#define WIRE_DUD_PREFIX "__dud"
|
||||
|
||||
// General
|
||||
#define WIRE_IDSCAN "ID Scan"
|
||||
#define WIRE_MAIN_POWER1 "Primary Power"
|
||||
#define WIRE_MAIN_POWER2 "Secondary Power"
|
||||
#define WIRE_AI_CONTROL "AI Control"
|
||||
#define WIRE_ELECTRIFY "Electrification"
|
||||
#define WIRE_SAFETY "Safety"
|
||||
|
||||
// Vendors and smartfridges
|
||||
#define WIRE_THROW_ITEM "Item Throw"
|
||||
#define WIRE_CONTRABAND "Contraband"
|
||||
|
||||
// Airlock
|
||||
#define WIRE_DOOR_BOLTS "Door Bolts"
|
||||
#define WIRE_BACKUP_POWER1 "Primary Backup Power"
|
||||
#define WIRE_OPEN_DOOR "Door State"
|
||||
#define WIRE_SPEED "Door Timing"
|
||||
#define WIRE_BOLT_LIGHT "Bolt Lights"
|
||||
|
||||
// Air alarm
|
||||
#define WIRE_SYPHON "Siphon"
|
||||
#define WIRE_AALARM "Atmospherics Alarm"
|
||||
|
||||
// Camera
|
||||
#define WIRE_FOCUS "Focus"
|
||||
|
||||
// Mulebot
|
||||
#define WIRE_MOB_AVOIDANCE "Mob Avoidance"
|
||||
#define WIRE_LOADCHECK "Load Checking"
|
||||
#define WIRE_MOTOR1 "Primary Motor"
|
||||
#define WIRE_MOTOR2 "Secondary Motor"
|
||||
#define WIRE_REMOTE_RX "Signal Receiver"
|
||||
#define WIRE_REMOTE_TX "Signal Sender"
|
||||
#define WIRE_BEACON_RX "Beacon Receiver"
|
||||
|
||||
// Explosives, bombs
|
||||
#define WIRE_EXPLODE "Explode" // Explodes if pulsed or cut while active, defuses a bomb that isn't active on cut.
|
||||
#define WIRE_BOMB_UNBOLT "Unbolt" // Unbolts the bomb if cut, hint on pulsed.
|
||||
#define WIRE_BOMB_DELAY "Delay" // Raises the timer on pulse, does nothing on cut.
|
||||
#define WIRE_BOMB_PROCEED "Proceed" // Lowers the timer, explodes if cut while the bomb is active.
|
||||
#define WIRE_BOMB_ACTIVATE "Activate" // Will start a bombs timer if pulsed, will hint if pulsed while already active, will stop a timer a bomb on cut.
|
||||
|
||||
// Nuclear bomb
|
||||
#define WIRE_BOMB_LIGHT "Bomb Light"
|
||||
#define WIRE_BOMB_TIMING "Bomb Timing"
|
||||
#define WIRE_BOMB_SAFETY "Bomb Safety"
|
||||
|
||||
// Particle accelerator
|
||||
#define WIRE_PARTICLE_POWER "Power Toggle" // Toggles whether the PA is on or not.
|
||||
#define WIRE_PARTICLE_STRENGTH "Strength" // Determines the strength of the PA.
|
||||
#define WIRE_PARTICLE_INTERFACE "Interface" // Determines the interface showing up.
|
||||
#define WIRE_PARTICLE_POWER_LIMIT "Maximum Power" // Determines how strong the PA can be.
|
||||
|
||||
// Autolathe
|
||||
#define WIRE_AUTOLATHE_HACK "Hack"
|
||||
#define WIRE_AUTOLATHE_DISABLE "Disable"
|
||||
|
||||
// Radio
|
||||
#define WIRE_RADIO_SIGNAL "Signal"
|
||||
#define WIRE_RADIO_RECEIVER "Receiver"
|
||||
#define WIRE_RADIO_TRANSMIT "Transmitter"
|
||||
|
||||
// Cyborg
|
||||
#define WIRE_BORG_LOCKED "Lockdown"
|
||||
#define WIRE_BORG_CAMERA "Camera"
|
||||
#define WIRE_BORG_LAWCHECK "Law Check"
|
||||
|
||||
// Suit storage unit
|
||||
#define WIRE_SSU_UV "UV wire"
|
||||
|
||||
// Tesla coil
|
||||
#define WIRE_TESLACOIL_ZAP "Zap"
|
||||
+25
-65
@@ -5,11 +5,11 @@
|
||||
var/turf/T = get_turf(A)
|
||||
return T ? T.loc : null
|
||||
|
||||
/proc/get_area_name(N) //get area by its name
|
||||
for(var/area/A in world)
|
||||
if(A.name == N)
|
||||
return A
|
||||
return 0
|
||||
/proc/get_area_name(atom/X, format_text = FALSE)
|
||||
var/area/A = isarea(X) ? X : get_area(X)
|
||||
if(!A)
|
||||
return null
|
||||
return format_text ? format_text(A.name) : A.name
|
||||
|
||||
/proc/get_location_name(atom/X, format_text = FALSE)
|
||||
var/area/A = isarea(X) ? X : get_area(X)
|
||||
@@ -31,6 +31,24 @@
|
||||
areas |= T.loc
|
||||
return areas
|
||||
|
||||
/proc/get_open_turf_in_dir(atom/center, dir)
|
||||
var/turf/T = get_ranged_target_turf(center, dir, 1)
|
||||
if(T && !T.density)
|
||||
return T
|
||||
|
||||
/proc/get_adjacent_open_turfs(atom/center)
|
||||
. = list(get_open_turf_in_dir(center, NORTH),
|
||||
get_open_turf_in_dir(center, SOUTH),
|
||||
get_open_turf_in_dir(center, EAST),
|
||||
get_open_turf_in_dir(center, WEST))
|
||||
listclearnulls(.)
|
||||
|
||||
/proc/get_adjacent_open_areas(atom/center)
|
||||
. = list()
|
||||
var/list/adjacent_turfs = get_adjacent_open_turfs(center)
|
||||
for(var/I in adjacent_turfs)
|
||||
. |= get_area(I)
|
||||
|
||||
// Like view but bypasses luminosity check
|
||||
|
||||
/proc/hear(var/range, var/atom/source)
|
||||
@@ -425,66 +443,8 @@
|
||||
if(pressure <= LAVALAND_EQUIPMENT_EFFECT_PRESSURE)
|
||||
. = TRUE
|
||||
|
||||
proc/pollCandidates(Question, be_special_type, antag_age_check = FALSE, poll_time = 300, ignore_respawnability = FALSE, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
|
||||
var/roletext = be_special_type ? get_roletext(be_special_type) : null
|
||||
var/list/mob/dead/observer/candidates = list()
|
||||
var/time_passed = world.time
|
||||
if(!Question)
|
||||
Question = "Would you like to be a special role?"
|
||||
|
||||
for(var/mob/dead/observer/G in (ignore_respawnability ? GLOB.player_list : GLOB.respawnable_list))
|
||||
if(!G.key || !G.client)
|
||||
continue
|
||||
if(be_special_type)
|
||||
if(!(be_special_type in G.client.prefs.be_special))
|
||||
continue
|
||||
if(antag_age_check)
|
||||
if(!player_old_enough_antag(G.client, be_special_type))
|
||||
continue
|
||||
if(roletext)
|
||||
if(jobban_isbanned(G, roletext) || jobban_isbanned(G, "Syndicate"))
|
||||
continue
|
||||
if(config.use_exp_restrictions && min_hours)
|
||||
if(G.client.get_exp_type_num(EXP_TYPE_LIVING) < min_hours * 60)
|
||||
continue
|
||||
if(check_antaghud && cannotPossess(G))
|
||||
continue
|
||||
spawn(0)
|
||||
G << 'sound/misc/notice2.ogg'//Alerting them to their consideration
|
||||
if(flashwindow)
|
||||
window_flash(G.client)
|
||||
var/ans = alert(G,Question,"Please answer in [poll_time/10] seconds!","No","Yes","Not This Round")
|
||||
if(!G?.client)
|
||||
return
|
||||
switch(ans)
|
||||
if("Yes")
|
||||
to_chat(G, "<span class='notice'>Choice registered: Yes.</span>")
|
||||
if((world.time-time_passed)>poll_time)//If more than 30 game seconds passed.
|
||||
to_chat(G, "<span class='danger'>Sorry, you were too late for the consideration!</span>")
|
||||
G << 'sound/machines/buzz-sigh.ogg'
|
||||
return
|
||||
candidates += G
|
||||
if("No")
|
||||
to_chat(G, "<span class='danger'>Choice registered: No.</span>")
|
||||
return
|
||||
if("Not This Round")
|
||||
to_chat(G, "<span class='danger'>Choice registered: No.</span>")
|
||||
to_chat(G, "<span class='notice'>You will no longer receive notifications for the role '[roletext]' for the rest of the round.</span>")
|
||||
G.client.prefs.be_special -= be_special_type
|
||||
return
|
||||
else
|
||||
return
|
||||
sleep(poll_time)
|
||||
|
||||
//Check all our candidates, to make sure they didn't log off during the 30 second wait period.
|
||||
for(var/mob/dead/observer/G in candidates)
|
||||
if(!G.key || !G.client)
|
||||
candidates.Remove(G)
|
||||
|
||||
return candidates
|
||||
|
||||
/proc/pollCandidatesWithVeto(adminclient, adminusr, max_slots, Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
|
||||
var/list/willing_ghosts = pollCandidates(Question, be_special_type, antag_age_check, poll_time, ignore_respawnability, min_hours, flashwindow, check_antaghud)
|
||||
/proc/pollCandidatesWithVeto(adminclient, adminusr, max_slots, Question, be_special_type, antag_age_check = FALSE, poll_time = 300, ignore_respawnability = FALSE, min_hours = FALSE, flashwindow = TRUE, check_antaghud = TRUE, source)
|
||||
var/list/willing_ghosts = SSghost_spawns.poll_candidates(Question, be_special_type, antag_age_check, poll_time, ignore_respawnability, min_hours, flashwindow, check_antaghud, source)
|
||||
var/list/selected_ghosts = list()
|
||||
if(!willing_ghosts.len)
|
||||
return selected_ghosts
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
|
||||
//////////////////////
|
||||
//Heap object
|
||||
//datum/heap object
|
||||
//////////////////////
|
||||
|
||||
/Heap
|
||||
/datum/heap
|
||||
var/list/L
|
||||
var/cmp
|
||||
|
||||
/Heap/New(compare)
|
||||
/datum/heap/New(compare)
|
||||
L = new()
|
||||
cmp = compare
|
||||
|
||||
/Heap/proc/IsEmpty()
|
||||
/datum/heap/proc/IsEmpty()
|
||||
return !L.len
|
||||
|
||||
//Insert and place at its position a new node in the heap
|
||||
/Heap/proc/Insert(atom/A)
|
||||
/datum/heap/proc/Insert(atom/A)
|
||||
|
||||
L.Add(A)
|
||||
Swim(L.len)
|
||||
|
||||
//removes and returns the first element of the heap
|
||||
//(i.e the max or the min dependant on the comparison function)
|
||||
/Heap/proc/Pop()
|
||||
/datum/heap/proc/Pop()
|
||||
if(!L.len)
|
||||
return 0
|
||||
. = L[1]
|
||||
@@ -33,7 +33,7 @@
|
||||
Sink(1)
|
||||
|
||||
//Get a node up to its right position in the heap
|
||||
/Heap/proc/Swim(var/index)
|
||||
/datum/heap/proc/Swim(var/index)
|
||||
var/parent = round(index * 0.5)
|
||||
|
||||
while(parent > 0 && (call(cmp)(L[index],L[parent]) > 0))
|
||||
@@ -42,7 +42,7 @@
|
||||
parent = round(index * 0.5)
|
||||
|
||||
//Get a node down to its right position in the heap
|
||||
/Heap/proc/Sink(var/index)
|
||||
/datum/heap/proc/Sink(var/index)
|
||||
var/g_child = GetGreaterChild(index)
|
||||
|
||||
while(g_child > 0 && (call(cmp)(L[index],L[g_child]) < 0))
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
//Returns the greater (relative to the comparison proc) of a node children
|
||||
//or 0 if there's no child
|
||||
/Heap/proc/GetGreaterChild(var/index)
|
||||
/datum/heap/proc/GetGreaterChild(var/index)
|
||||
if(index * 2 > L.len)
|
||||
return 0
|
||||
|
||||
@@ -65,11 +65,11 @@
|
||||
return index * 2
|
||||
|
||||
//Replaces a given node so it verify the heap condition
|
||||
/Heap/proc/ReSort(atom/A)
|
||||
/datum/heap/proc/ReSort(atom/A)
|
||||
var/index = L.Find(A)
|
||||
|
||||
Swim(index)
|
||||
Sink(index)
|
||||
|
||||
/Heap/proc/List()
|
||||
/datum/heap/proc/List()
|
||||
. = L.Copy()
|
||||
@@ -672,9 +672,6 @@ proc/dd_sortedObjectList(list/incoming)
|
||||
/obj/machinery/camera/dd_SortValue()
|
||||
return "[c_tag]"
|
||||
|
||||
/datum/alarm/dd_SortValue()
|
||||
return "[sanitize(last_name)]"
|
||||
|
||||
//Picks from the list, with some safeties, and returns the "default" arg if it fails
|
||||
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
|
||||
|
||||
@@ -693,6 +690,9 @@ proc/dd_sortedObjectList(list/incoming)
|
||||
// Lazying Episode 3
|
||||
#define LAZYSET(L, K, V) LAZYINITLIST(L); L[K] = V;
|
||||
|
||||
/// Returns whether a numerical index is within a given list's bounds. Faster than isnull(LAZYACCESS(L, I)).
|
||||
#define ISINDEXSAFE(L, I) (I >= 1 && I <= length(L))
|
||||
|
||||
//same, but returns nothing and acts on list in place
|
||||
/proc/shuffle_inplace(list/L)
|
||||
if(!L)
|
||||
|
||||
+21
-15
@@ -1,4 +1,4 @@
|
||||
proc/GetOppositeDir(var/dir)
|
||||
/proc/GetOppositeDir(var/dir)
|
||||
switch(dir)
|
||||
if(NORTH) return SOUTH
|
||||
if(SOUTH) return NORTH
|
||||
@@ -10,7 +10,7 @@ proc/GetOppositeDir(var/dir)
|
||||
if(SOUTHEAST) return NORTHWEST
|
||||
return 0
|
||||
|
||||
proc/random_underwear(gender, species = "Human")
|
||||
/proc/random_underwear(gender, species = "Human")
|
||||
var/list/pick_list = list()
|
||||
switch(gender)
|
||||
if(MALE) pick_list = GLOB.underwear_m
|
||||
@@ -18,7 +18,7 @@ proc/random_underwear(gender, species = "Human")
|
||||
else pick_list = GLOB.underwear_list
|
||||
return pick_species_allowed_underwear(pick_list, species)
|
||||
|
||||
proc/random_undershirt(gender, species = "Human")
|
||||
/proc/random_undershirt(gender, species = "Human")
|
||||
var/list/pick_list = list()
|
||||
switch(gender)
|
||||
if(MALE) pick_list = GLOB.undershirt_m
|
||||
@@ -26,7 +26,7 @@ proc/random_undershirt(gender, species = "Human")
|
||||
else pick_list = GLOB.undershirt_list
|
||||
return pick_species_allowed_underwear(pick_list, species)
|
||||
|
||||
proc/random_socks(gender, species = "Human")
|
||||
/proc/random_socks(gender, species = "Human")
|
||||
var/list/pick_list = list()
|
||||
switch(gender)
|
||||
if(MALE) pick_list = GLOB.socks_m
|
||||
@@ -34,7 +34,7 @@ proc/random_socks(gender, species = "Human")
|
||||
else pick_list = GLOB.socks_list
|
||||
return pick_species_allowed_underwear(pick_list, species)
|
||||
|
||||
proc/pick_species_allowed_underwear(list/all_picks, species)
|
||||
/proc/pick_species_allowed_underwear(list/all_picks, species)
|
||||
var/list/valid_picks = list()
|
||||
for(var/test in all_picks)
|
||||
var/datum/sprite_accessory/S = all_picks[test]
|
||||
@@ -46,7 +46,7 @@ proc/pick_species_allowed_underwear(list/all_picks, species)
|
||||
|
||||
return pick(valid_picks)
|
||||
|
||||
proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead)
|
||||
/proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead)
|
||||
var/h_style = "Bald"
|
||||
var/list/valid_hairstyles = list()
|
||||
for(var/hairstyle in GLOB.hair_styles_public_list)
|
||||
@@ -75,7 +75,7 @@ proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohea
|
||||
|
||||
return h_style
|
||||
|
||||
proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead)
|
||||
/proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead)
|
||||
var/f_style = "Shaved"
|
||||
var/list/valid_facial_hairstyles = list()
|
||||
for(var/facialhairstyle in GLOB.facial_hair_styles_list)
|
||||
@@ -104,7 +104,7 @@ proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/
|
||||
|
||||
return f_style
|
||||
|
||||
proc/random_head_accessory(species = "Human")
|
||||
/proc/random_head_accessory(species = "Human")
|
||||
var/ha_style = "None"
|
||||
var/list/valid_head_accessories = list()
|
||||
for(var/head_accessory in GLOB.head_accessory_styles_list)
|
||||
@@ -119,7 +119,7 @@ proc/random_head_accessory(species = "Human")
|
||||
|
||||
return ha_style
|
||||
|
||||
proc/random_marking_style(var/location = "body", species = "Human", var/datum/robolimb/robohead, var/body_accessory, var/alt_head)
|
||||
/proc/random_marking_style(var/location = "body", species = "Human", var/datum/robolimb/robohead, var/body_accessory, var/alt_head)
|
||||
var/m_style = "None"
|
||||
var/list/valid_markings = list()
|
||||
for(var/marking in GLOB.marking_styles_list)
|
||||
@@ -158,7 +158,7 @@ proc/random_marking_style(var/location = "body", species = "Human", var/datum/ro
|
||||
|
||||
return m_style
|
||||
|
||||
proc/random_body_accessory(species = "Vulpkanin")
|
||||
/proc/random_body_accessory(species = "Vulpkanin")
|
||||
var/body_accessory = null
|
||||
var/list/valid_body_accessories = list()
|
||||
for(var/B in GLOB.body_accessory_by_name)
|
||||
@@ -174,7 +174,7 @@ proc/random_body_accessory(species = "Vulpkanin")
|
||||
|
||||
return body_accessory
|
||||
|
||||
proc/random_name(gender, species = "Human")
|
||||
/proc/random_name(gender, species = "Human")
|
||||
|
||||
var/datum/species/current_species
|
||||
if(species)
|
||||
@@ -188,7 +188,7 @@ proc/random_name(gender, species = "Human")
|
||||
else
|
||||
return current_species.get_random_name(gender)
|
||||
|
||||
proc/random_skin_tone(species = "Human")
|
||||
/proc/random_skin_tone(species = "Human")
|
||||
if(species == "Human" || species == "Drask")
|
||||
switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino"))
|
||||
if("caucasian") . = -10
|
||||
@@ -202,7 +202,7 @@ proc/random_skin_tone(species = "Human")
|
||||
. = rand(1, 6)
|
||||
return .
|
||||
|
||||
proc/skintone2racedescription(tone, species = "Human")
|
||||
/proc/skintone2racedescription(tone, species = "Human")
|
||||
if(species == "Human")
|
||||
switch(tone)
|
||||
if(30 to INFINITY) return "albino"
|
||||
@@ -225,7 +225,7 @@ proc/skintone2racedescription(tone, species = "Human")
|
||||
else
|
||||
return "unknown"
|
||||
|
||||
proc/age2agedescription(age)
|
||||
/proc/age2agedescription(age)
|
||||
switch(age)
|
||||
if(0 to 1) return "infant"
|
||||
if(1 to 3) return "toddler"
|
||||
@@ -289,11 +289,14 @@ This is always put in the attack log.
|
||||
|
||||
var/user_str = key_name_log(user) + COORD(user)
|
||||
var/target_str
|
||||
var/target_info
|
||||
if(isatom(target))
|
||||
var/atom/AT = target
|
||||
target_str = key_name_log(AT) + COORD(AT)
|
||||
target_info = key_name_admin(target)
|
||||
else
|
||||
target_str = target
|
||||
target_info = target
|
||||
var/mob/MU = user
|
||||
var/mob/MT = target
|
||||
if(istype(MU))
|
||||
@@ -317,10 +320,13 @@ This is always put in the attack log.
|
||||
var/area/A = get_area(MT)
|
||||
if(A && A.hide_attacklogs)
|
||||
loglevel = ATKLOG_ALMOSTALL
|
||||
else
|
||||
loglevel = ATKLOG_ALL // Hitting an object. Not a mob
|
||||
if(isLivingSSD(target)) // Attacks on SSDs are shown to admins with any log level except ATKLOG_NONE. Overrides custom level
|
||||
loglevel = ATKLOG_FEW
|
||||
|
||||
msg_admin_attack("[key_name_admin(user)] vs [key_name_admin(target)]: [what_done]", loglevel)
|
||||
|
||||
msg_admin_attack("[key_name_admin(user)] vs [target_info]: [what_done]", loglevel)
|
||||
|
||||
/proc/do_mob(mob/user, mob/target, time = 30, uninterruptible = 0, progress = 1, list/extra_checks = list())
|
||||
if(!user || !target)
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
//checks text for html tags
|
||||
//if tag is not in whitelist (var/list/paper_tag_whitelist in global.dm)
|
||||
//relpaces < with <
|
||||
proc/checkhtml(var/t)
|
||||
/proc/checkhtml(var/t)
|
||||
t = sanitize_simple(t, list("&#"="."))
|
||||
var/p = findtext(t,"<",1)
|
||||
while(p) //going through all the tags
|
||||
@@ -615,5 +615,3 @@ proc/checkhtml(var/t)
|
||||
text = replacetext(text, "<td>", "\[cell\]")
|
||||
text = replacetext(text, "<img src = ntlogo.png>", "\[logo\]")
|
||||
return text
|
||||
|
||||
#define string2charlist(string) (splittext(string, regex("(\\x0A|.)")) - splittext(string, ""))
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
return time2text(station_time(time, TRUE), format)
|
||||
|
||||
/* Returns 1 if it is the selected month and day */
|
||||
proc/isDay(var/month, var/day)
|
||||
/proc/isDay(var/month, var/day)
|
||||
if(isnum(month) && isnum(day))
|
||||
var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
|
||||
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
|
||||
@@ -95,7 +95,7 @@ proc/isDay(var/month, var/day)
|
||||
/proc/seconds_to_time(var/seconds as num)
|
||||
var/numSeconds = seconds % 60
|
||||
var/numMinutes = (seconds - numSeconds) / 60
|
||||
return "[numMinutes] [numMinutes > 1 ? "minutes" : "minute"] and [numSeconds] seconds."
|
||||
return "[numMinutes] [numMinutes > 1 ? "minutes" : "minute"] and [numSeconds] seconds"
|
||||
|
||||
//Take a value in seconds and makes it display like a clock
|
||||
/proc/seconds_to_clock(var/seconds as num)
|
||||
|
||||
+16
-11
@@ -529,7 +529,7 @@ Returns 1 if the chain up to the area contains the given typepath
|
||||
return max(min(middle, high), low)
|
||||
|
||||
//returns random gauss number
|
||||
proc/GaussRand(var/sigma)
|
||||
/proc/GaussRand(var/sigma)
|
||||
var/x,y,rsq
|
||||
do
|
||||
x=2*rand()-1
|
||||
@@ -539,7 +539,7 @@ proc/GaussRand(var/sigma)
|
||||
return sigma*y*sqrt(-2*log(rsq)/rsq)
|
||||
|
||||
//returns random gauss number, rounded to 'roundto'
|
||||
proc/GaussRandRound(var/sigma,var/roundto)
|
||||
/proc/GaussRandRound(var/sigma,var/roundto)
|
||||
return round(GaussRand(sigma),roundto)
|
||||
|
||||
//Will return the contents of an atom recursivly to a depth of 'searchDepth'
|
||||
@@ -583,7 +583,7 @@ proc/GaussRandRound(var/sigma,var/roundto)
|
||||
|
||||
return 1
|
||||
|
||||
proc/is_blocked_turf(turf/T, exclude_mobs)
|
||||
/proc/is_blocked_turf(turf/T, exclude_mobs)
|
||||
if(T.density)
|
||||
return 1
|
||||
for(var/i in T)
|
||||
@@ -984,16 +984,16 @@ proc/is_blocked_turf(turf/T, exclude_mobs)
|
||||
|
||||
|
||||
|
||||
proc/get_cardinal_dir(atom/A, atom/B)
|
||||
/proc/get_cardinal_dir(atom/A, atom/B)
|
||||
var/dx = abs(B.x - A.x)
|
||||
var/dy = abs(B.y - A.y)
|
||||
return get_dir(A, B) & (rand() * (dx+dy) < dy ? 3 : 12)
|
||||
|
||||
//chances are 1:value. anyprob(1) will always return true
|
||||
proc/anyprob(value)
|
||||
/proc/anyprob(value)
|
||||
return (rand(1,value)==value)
|
||||
|
||||
proc/view_or_range(distance = world.view , center = usr , type)
|
||||
/proc/view_or_range(distance = world.view , center = usr , type)
|
||||
switch(type)
|
||||
if("view")
|
||||
. = view(distance,center)
|
||||
@@ -1001,7 +1001,7 @@ proc/view_or_range(distance = world.view , center = usr , type)
|
||||
. = range(distance,center)
|
||||
return
|
||||
|
||||
proc/oview_or_orange(distance = world.view , center = usr , type)
|
||||
/proc/oview_or_orange(distance = world.view , center = usr , type)
|
||||
switch(type)
|
||||
if("view")
|
||||
. = oview(distance,center)
|
||||
@@ -1009,7 +1009,7 @@ proc/oview_or_orange(distance = world.view , center = usr , type)
|
||||
. = orange(distance,center)
|
||||
return
|
||||
|
||||
proc/get_mob_with_client_list()
|
||||
/proc/get_mob_with_client_list()
|
||||
var/list/mobs = list()
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(M.client)
|
||||
@@ -1233,10 +1233,10 @@ GLOBAL_LIST_INIT(wall_items, typecacheof(list(/obj/machinery/power/apc, /obj/mac
|
||||
return 0
|
||||
|
||||
|
||||
proc/get_angle(atom/a, atom/b)
|
||||
/proc/get_angle(atom/a, atom/b)
|
||||
return atan2(b.y - a.y, b.x - a.x)
|
||||
|
||||
proc/atan2(x, y)
|
||||
/proc/atan2(x, y)
|
||||
if(!x && !y) return 0
|
||||
return y >= 0 ? arccos(x / sqrt(x * x + y * y)) : -arccos(x / sqrt(x * x + y * y))
|
||||
|
||||
@@ -1329,7 +1329,7 @@ Standard way to write links -Sayu
|
||||
return FACING_INIT_FACING_TARGET_TARGET_FACING_PERPENDICULAR
|
||||
|
||||
|
||||
atom/proc/GetTypeInAllContents(typepath)
|
||||
/atom/proc/GetTypeInAllContents(typepath)
|
||||
var/list/processing_list = list(src)
|
||||
var/list/processed = list()
|
||||
|
||||
@@ -2017,5 +2017,10 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
set waitfor = FALSE
|
||||
return call(source, proctype)(arglist(arguments))
|
||||
|
||||
/proc/IsFrozen(atom/A)
|
||||
if(A in GLOB.frozen_atom_list)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/// Waits at a line of code until X is true
|
||||
#define UNTIL(X) while(!(X)) stoplag()
|
||||
|
||||
@@ -47,7 +47,10 @@ GLOBAL_LIST_EMPTY(ladders)
|
||||
GLOBAL_LIST_INIT(active_diseases, list()) //List of Active disease in all mobs; purely for quick referencing.
|
||||
|
||||
GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
|
||||
|
||||
GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert
|
||||
GLOBAL_LIST_EMPTY(explosive_walls)
|
||||
|
||||
GLOBAL_LIST_EMPTY(engine_beacon_list)
|
||||
|
||||
/// List of wire colors for each object type of that round. One for airlocks, one for vendors, etc.
|
||||
GLOBAL_LIST_EMPTY(wire_color_directory) // This is an associative list with the `holder_type` as the key, and a list of colors as the value.
|
||||
|
||||
@@ -34,4 +34,6 @@ GLOBAL_PROTECT(IClog)
|
||||
GLOBAL_LIST_EMPTY(OOClog)
|
||||
GLOBAL_PROTECT(OOClog)
|
||||
|
||||
GLOBAL_DATUM_INIT(logging, /datum/logging, new /datum/logging())
|
||||
|
||||
GLOBAL_LIST_INIT(investigate_log_subjects, list("notes", "watchlist", "hrefs"))
|
||||
|
||||
@@ -10,12 +10,12 @@ GLOBAL_DATUM_INIT(command_announcer, /obj/item/radio/intercom/command, create_co
|
||||
|
||||
// Load order issues means this can't be new'd until other code runs
|
||||
// This is probably not the way I should be doing this, but I don't know how to do it right!
|
||||
proc/create_global_announcer()
|
||||
/proc/create_global_announcer()
|
||||
spawn(0)
|
||||
GLOB.global_announcer = new(null)
|
||||
return
|
||||
|
||||
proc/create_command_announcer()
|
||||
/proc/create_command_announcer()
|
||||
spawn(0)
|
||||
GLOB.command_announcer = new(null)
|
||||
return
|
||||
@@ -92,6 +92,7 @@ GLOBAL_VAR(map_name) // Self explanatory
|
||||
GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) // Station datacore, manifest, etc
|
||||
|
||||
GLOBAL_VAR_INIT(panic_bunker_enabled, FALSE) // Is the panic bunker enabled
|
||||
GLOBAL_VAR_INIT(pending_server_update, FALSE)
|
||||
|
||||
//Database connections
|
||||
//A connection is established on world creation. Ideally, the connection dies when the server restarts (After feedback logging.).
|
||||
|
||||
+74
-57
@@ -145,12 +145,10 @@
|
||||
/mob/living/silicon/ai/MiddleClickOn(var/atom/A)
|
||||
A.AIMiddleClick(src)
|
||||
|
||||
/*
|
||||
The following criminally helpful code is just the previous code cleaned up;
|
||||
I have no idea why it was in atoms.dm instead of respective files.
|
||||
*/
|
||||
|
||||
/atom/proc/AICtrlShiftClick(var/mob/user) // Examines
|
||||
// DEFAULT PROCS TO OVERRIDE
|
||||
|
||||
/atom/proc/AICtrlShiftClick(mob/user) // Examines
|
||||
if(user.client)
|
||||
user.examinate(src)
|
||||
return
|
||||
@@ -158,74 +156,93 @@
|
||||
/atom/proc/AIAltShiftClick()
|
||||
return
|
||||
|
||||
/obj/machinery/door/airlock/AIAltShiftClick() // Sets/Unsets Emergency Access Override
|
||||
if(density)
|
||||
Topic(src, list("src" = UID(), "command"="emergency", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
||||
else
|
||||
Topic(src, list("src" = UID(), "command"="emergency", "activate" = "0"), 1)
|
||||
return
|
||||
|
||||
/atom/proc/AIShiftClick(var/mob/user)
|
||||
/atom/proc/AIShiftClick(mob/living/user) // borgs use this too
|
||||
if(user.client)
|
||||
user.examinate(src)
|
||||
return
|
||||
|
||||
/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors!
|
||||
if(density)
|
||||
Topic(src, list("src" = UID(), "command"="open", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
||||
else
|
||||
Topic(src, list("src" = UID(), "command"="open", "activate" = "0"), 1)
|
||||
/atom/proc/AICtrlClick(mob/living/silicon/ai/user)
|
||||
return
|
||||
|
||||
/atom/proc/AICtrlClick(var/mob/living/silicon/ai/user)
|
||||
return
|
||||
|
||||
/obj/machinery/door/airlock/AICtrlClick() // Bolts doors
|
||||
if(locked)
|
||||
Topic(src, list("src" = UID(), "command"="bolts", "activate" = "0"), 1)// 1 meaning no window (consistency!)
|
||||
else
|
||||
Topic(src, list("src" = UID(), "command"="bolts", "activate" = "1"), 1)
|
||||
|
||||
/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs.
|
||||
Topic("breaker=1", list("breaker"="1"), 0) // 0 meaning no window (consistency! wait...)
|
||||
|
||||
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
|
||||
Topic(src, list("src" = UID(), "command"="enable", "value"="[!enabled]"), 1) // 1 meaning no window (consistency!)
|
||||
|
||||
/atom/proc/AIAltClick(var/atom/A)
|
||||
/atom/proc/AIAltClick(atom/A)
|
||||
AltClick(A)
|
||||
|
||||
/obj/machinery/door/airlock/AIAltClick() // Electrifies doors.
|
||||
if(!electrified_until)
|
||||
// permanent shock
|
||||
Topic(src, list("src" = UID(), "command"="electrify_permanently", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
||||
else
|
||||
// disable/6 is not in Topic; disable/5 disables both temporary and permanent shock
|
||||
Topic(src, list("src" = UID(), "command"="electrify_permanently", "activate" = "0"), 1)
|
||||
/atom/proc/AIMiddleClick(mob/living/user)
|
||||
return
|
||||
|
||||
/mob/living/silicon/ai/TurfAdjacent(turf/T)
|
||||
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
|
||||
|
||||
|
||||
// APC
|
||||
|
||||
/obj/machinery/power/apc/AICtrlClick(mob/living/user) // turns off/on APCs.
|
||||
toggle_breaker(user)
|
||||
|
||||
|
||||
// TURRETCONTROL
|
||||
|
||||
/obj/machinery/turretid/AICtrlClick(mob/living/silicon/ai/user) //turns off/on Turrets
|
||||
enabled = !enabled
|
||||
updateTurrets()
|
||||
|
||||
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
|
||||
Topic(src, list("src" = UID(), "command"="lethal", "value"="[!lethal]"), 1) // 1 meaning no window (consistency!)
|
||||
if(lethal_is_configurable)
|
||||
lethal = !lethal
|
||||
updateTurrets()
|
||||
|
||||
/atom/proc/AIMiddleClick()
|
||||
return
|
||||
// AIRLOCKS
|
||||
|
||||
/obj/machinery/door/airlock/AIMiddleClick() // Toggles door bolt lights.
|
||||
if(!src.lights)
|
||||
Topic(src, list("src" = UID(), "command"="lights", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
||||
/obj/machinery/door/airlock/AIAltShiftClick(mob/user) // Sets/Unsets Emergency Access Override
|
||||
emergency = !emergency
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/door/airlock/AIShiftClick(mob/user) // Opens and closes doors!
|
||||
if(welded)
|
||||
to_chat(user, "<span class='warning'>The airlock has been welded shut!</span>")
|
||||
if(locked)
|
||||
locked = !locked
|
||||
if(density)
|
||||
open()
|
||||
else
|
||||
Topic(src, list("src" = UID(), "command"="lights", "activate" = "0"), 1)
|
||||
return
|
||||
close()
|
||||
|
||||
/obj/machinery/ai_slipper/AICtrlClick() //Turns liquid dispenser on or off
|
||||
/obj/machinery/door/airlock/AICtrlClick(mob/living/silicon/ai/user) // Bolts doors
|
||||
locked = !locked
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/door/airlock/AIAltClick(mob/living/silicon/ai/user) // Electrifies doors.
|
||||
if(wires.is_cut(WIRE_ELECTRIFY))
|
||||
to_chat(user, "<span class='warning'>The electrification wire is cut - Cannot electrify the door.</span>")
|
||||
if(isElectrified())
|
||||
electrify(0) // un-shock
|
||||
else
|
||||
electrify(-1) // permanent shock
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/AIMiddleClick(mob/living/user) // Toggles door bolt lights.
|
||||
if(wires.is_cut(WIRE_BOLT_LIGHT))
|
||||
to_chat(user, "<span class='warning'>The bolt lights wire has been cut - The door bolt lights are permanently disabled.</span>")
|
||||
else if(lights)
|
||||
lights = FALSE
|
||||
to_chat(user, "<span class='notice'>The door bolt lights have been disabled.</span>")
|
||||
else if(!lights)
|
||||
lights = TRUE
|
||||
to_chat(user, "<span class='notice'>The door bolt lights have been enabled.</span>")
|
||||
update_icon()
|
||||
|
||||
// FIRE ALARMS
|
||||
|
||||
/obj/machinery/firealarm/AICtrlClick()
|
||||
if(enabled)
|
||||
reset()
|
||||
else
|
||||
alarm()
|
||||
|
||||
// AI-CONTROLLED SLIP GENERATOR IN AI CORE
|
||||
|
||||
/obj/machinery/ai_slipper/AICtrlClick(mob/living/silicon/ai/user) //Turns liquid dispenser on or off
|
||||
ToggleOn()
|
||||
|
||||
/obj/machinery/ai_slipper/AIAltClick() //Dispenses liquid if on
|
||||
Activate()
|
||||
|
||||
//
|
||||
// Override AdjacentQuick for AltClicking
|
||||
//
|
||||
|
||||
/mob/living/silicon/ai/TurfAdjacent(var/turf/T)
|
||||
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
|
||||
|
||||
@@ -73,7 +73,9 @@
|
||||
var/dragged = modifiers["drag"]
|
||||
if(dragged && !modifiers[dragged])
|
||||
return
|
||||
|
||||
if(IsFrozen(A) && !is_admin(usr))
|
||||
to_chat(usr, "<span class='boldannounce'>Interacting with admin-frozen players is not permitted.</span>")
|
||||
return
|
||||
if(modifiers["middle"] && modifiers["shift"] && modifiers["ctrl"])
|
||||
MiddleShiftControlClickOn(A)
|
||||
return
|
||||
|
||||
@@ -170,6 +170,9 @@
|
||||
/obj/machinery/ai_slipper/BorgAltClick() //Dispenses liquid if on
|
||||
Activate()
|
||||
|
||||
/obj/machinery/firealarm/BorgCtrlClick()
|
||||
AICtrlClick()
|
||||
|
||||
/*
|
||||
As with AI, these are not used in click code,
|
||||
because the code for robots is specific, not generic.
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
/obj/screen/ai/alerts/Click()
|
||||
if(isAI(usr))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
AI.subsystem_alarm_monitor()
|
||||
AI.ai_alerts()
|
||||
|
||||
/obj/screen/ai/announcement
|
||||
name = "Make Announcement"
|
||||
|
||||
+90
-20
@@ -3,7 +3,7 @@
|
||||
//PUBLIC - call these wherever you want
|
||||
|
||||
|
||||
/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE)
|
||||
/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE, timeout_override, no_anim)
|
||||
|
||||
/*
|
||||
Proc to create or update an alert. Returns the alert if the alert is new or updated, 0 if it was thrown already
|
||||
@@ -59,14 +59,16 @@
|
||||
LAZYSET(alerts, category, alert) // This also creates the list if it doesn't exist
|
||||
if(client && hud_used)
|
||||
hud_used.reorganize_alerts()
|
||||
alert.transform = matrix(32, 6, MATRIX_TRANSLATE)
|
||||
animate(alert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
|
||||
|
||||
if(alert.timeout)
|
||||
spawn(alert.timeout)
|
||||
if(alert.timeout && alerts[category] == alert && world.time >= alert.timeout)
|
||||
clear_alert(category)
|
||||
alert.timeout = world.time + alert.timeout - world.tick_lag
|
||||
if(!no_anim)
|
||||
alert.transform = matrix(32, 6, MATRIX_TRANSLATE)
|
||||
animate(alert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
|
||||
|
||||
var/timeout = timeout_override || alert.timeout
|
||||
if(timeout)
|
||||
addtimer(CALLBACK(alert, /obj/screen/alert/.proc/do_timeout, src, category), timeout)
|
||||
alert.timeout = world.time + timeout - world.tick_lag
|
||||
|
||||
return alert
|
||||
|
||||
// Proc to clear an existing alert.
|
||||
@@ -94,7 +96,6 @@
|
||||
var/alerttooltipstyle = ""
|
||||
var/override_alerts = FALSE //If it is overriding other alerts of the same type
|
||||
|
||||
|
||||
/obj/screen/alert/MouseEntered(location,control,params)
|
||||
openToolTip(usr, src, params, title = name, content = desc, theme = alerttooltipstyle)
|
||||
|
||||
@@ -102,6 +103,12 @@
|
||||
/obj/screen/alert/MouseExited()
|
||||
closeToolTip(usr)
|
||||
|
||||
/obj/screen/alert/proc/do_timeout(mob/M, category)
|
||||
if(!M || !M.alerts)
|
||||
return
|
||||
|
||||
if(timeout && M.alerts[category] == src && world.time >= timeout)
|
||||
M.clear_alert(category)
|
||||
|
||||
//Gas alerts
|
||||
/obj/screen/alert/not_enough_oxy
|
||||
@@ -507,6 +514,34 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
timeout = 300
|
||||
var/atom/target = null
|
||||
var/action = NOTIFY_JUMP
|
||||
var/show_time_left = FALSE // If true you need to call START_PROCESSING manually
|
||||
var/image/time_left_overlay // The last image showing the time left
|
||||
var/datum/candidate_poll/poll // If set, on Click() it'll register the player as a candidate
|
||||
|
||||
/obj/screen/alert/notify_action/process()
|
||||
if(show_time_left)
|
||||
var/timeleft = timeout - world.time
|
||||
if(timeleft <= 0)
|
||||
return PROCESS_KILL
|
||||
|
||||
if(time_left_overlay)
|
||||
overlays -= time_left_overlay
|
||||
|
||||
var/obj/O = new
|
||||
O.maptext = "<span style='font-family: \"Small Fonts\"; font-weight: bold; font-size: 32px; color: [(timeleft <= 10 SECONDS) ? "red" : "white"];'>[CEILING(timeleft / 10, 1)]</span>"
|
||||
O.maptext_width = O.maptext_height = 128
|
||||
var/matrix/M = new
|
||||
M.Translate(4, 16)
|
||||
O.transform = M
|
||||
|
||||
var/image/I = image(O)
|
||||
I.layer = FLOAT_LAYER
|
||||
I.plane = FLOAT_PLANE + 1
|
||||
overlays += I
|
||||
|
||||
time_left_overlay = I
|
||||
qdel(O)
|
||||
..()
|
||||
|
||||
/obj/screen/alert/notify_action/Destroy()
|
||||
target = null
|
||||
@@ -515,20 +550,55 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
/obj/screen/alert/notify_action/Click()
|
||||
if(!usr || !usr.client)
|
||||
return
|
||||
if(!target)
|
||||
return
|
||||
var/mob/dead/observer/G = usr
|
||||
if(!istype(G))
|
||||
return
|
||||
switch(action)
|
||||
if(NOTIFY_ATTACK)
|
||||
target.attack_ghost(G)
|
||||
if(NOTIFY_JUMP)
|
||||
var/turf/T = get_turf(target)
|
||||
if(T && isturf(T))
|
||||
G.loc = T
|
||||
if(NOTIFY_FOLLOW)
|
||||
G.ManualFollow(target)
|
||||
|
||||
if(poll)
|
||||
if(poll.sign_up(G))
|
||||
// Add a small overlay to indicate we've signed up
|
||||
display_signed_up()
|
||||
else if(target)
|
||||
switch(action)
|
||||
if(NOTIFY_ATTACK)
|
||||
target.attack_ghost(G)
|
||||
if(NOTIFY_JUMP)
|
||||
var/turf/T = get_turf(target)
|
||||
if(T && isturf(T))
|
||||
G.loc = T
|
||||
if(NOTIFY_FOLLOW)
|
||||
G.ManualFollow(target)
|
||||
|
||||
/obj/screen/alert/notify_action/Topic(href, href_list)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if(href_list["signup"] && isobserver(usr) && poll?.sign_up(usr))
|
||||
display_signed_up()
|
||||
|
||||
/obj/screen/alert/notify_action/proc/display_signed_up()
|
||||
var/image/I = image('icons/mob/screen_gen.dmi', icon_state = "selector")
|
||||
I.layer = FLOAT_LAYER
|
||||
I.plane = FLOAT_PLANE + 2
|
||||
overlays += I
|
||||
|
||||
/obj/screen/alert/notify_action/proc/display_stacks(stacks = 1)
|
||||
if(stacks <= 1)
|
||||
return
|
||||
|
||||
var/obj/O = new
|
||||
O.maptext = "<span style='font-family: \"Small Fonts\"; font-size: 32px; color: yellow;'>[stacks]x</span>"
|
||||
O.maptext_width = O.maptext_height = 128
|
||||
var/matrix/M = new
|
||||
M.Translate(4, 2)
|
||||
O.transform = M
|
||||
|
||||
var/image/I = image(O)
|
||||
I.layer = FLOAT_LAYER
|
||||
I.plane = FLOAT_PLANE + 1
|
||||
overlays += I
|
||||
|
||||
qdel(O)
|
||||
|
||||
/obj/screen/alert/notify_soulstone
|
||||
name = "Soul Stone"
|
||||
|
||||
@@ -81,6 +81,9 @@
|
||||
|
||||
/obj/screen/ghost/respawn_pai/Click()
|
||||
var/mob/dead/observer/G = usr
|
||||
if(!GLOB.paiController.check_recruit(G))
|
||||
to_chat(G, "<span class='warning'>You are not eligible to become a pAI.</span>")
|
||||
return
|
||||
GLOB.paiController.recruitWindow(G)
|
||||
|
||||
/datum/hud/ghost
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
using.icon_state = mymob.a_intent
|
||||
static_inventory += using
|
||||
action_intent = using
|
||||
|
||||
|
||||
using = new /obj/screen/guardian/Manifest()
|
||||
using.screen_loc = ui_rhand
|
||||
static_inventory += using
|
||||
@@ -49,8 +49,8 @@
|
||||
/obj/screen/guardian/Manifest/Click()
|
||||
if(isguardian(usr))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = usr
|
||||
G.Manifest()
|
||||
|
||||
if(G.loc == G.summoner)
|
||||
G.Manifest()
|
||||
|
||||
/obj/screen/guardian/Recall
|
||||
icon_state = "recall"
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
user.do_attack_animation(M)
|
||||
. = M.attacked_by(src, user, def_zone)
|
||||
|
||||
add_attack_logs(user, M, "Attacked with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])", (M.ckey && force > 0 && damtype != STAMINA) ? null : ATKLOG_ALMOSTALL)
|
||||
add_attack_logs(user, M, "Attacked with [name] ([uppertext(user.a_intent)]) ([uppertext(damtype)])", (M.ckey && force > 0 && damtype != STAMINA) ? null : ATKLOG_ALMOSTALL)
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
|
||||
#define MIDDLE_CLICK 0
|
||||
#define ALT_CLICK 1
|
||||
#define CTRL_CLICK 2
|
||||
#define MAX_HARDSUIT_CLICK_MODE 2
|
||||
|
||||
/client
|
||||
var/hardsuit_click_mode = MIDDLE_CLICK
|
||||
|
||||
/client/verb/toggle_hardsuit_mode()
|
||||
set name = "Toggle Hardsuit Activation Mode"
|
||||
set desc = "Switch between hardsuit activation modes."
|
||||
set category = "OOC"
|
||||
|
||||
hardsuit_click_mode++
|
||||
if(hardsuit_click_mode > MAX_HARDSUIT_CLICK_MODE)
|
||||
hardsuit_click_mode = 0
|
||||
|
||||
switch(hardsuit_click_mode)
|
||||
if(MIDDLE_CLICK)
|
||||
to_chat(src, "Hardsuit activation mode set to middle-click.")
|
||||
if(ALT_CLICK)
|
||||
to_chat(src, "Hardsuit activation mode set to alt-click.")
|
||||
if(CTRL_CLICK)
|
||||
to_chat(src, "Hardsuit activation mode set to control-click.")
|
||||
else
|
||||
// should never get here, but just in case:
|
||||
log_runtime(EXCEPTION("Bad hardsuit click mode: [hardsuit_click_mode] - expected 0 to [MAX_HARDSUIT_CLICK_MODE]"), src)
|
||||
to_chat(src, "Somehow you bugged the system. Setting your hardsuit mode to middle-click.")
|
||||
hardsuit_click_mode = MIDDLE_CLICK
|
||||
|
||||
/mob/living/MiddleClickOn(atom/A)
|
||||
if(client && client.hardsuit_click_mode == MIDDLE_CLICK)
|
||||
if(HardsuitClickOn(A))
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/AltClickOn(atom/A)
|
||||
if(client && client.hardsuit_click_mode == ALT_CLICK)
|
||||
if(HardsuitClickOn(A))
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/CtrlClickOn(atom/A)
|
||||
if(client && client.hardsuit_click_mode == CTRL_CLICK)
|
||||
if(HardsuitClickOn(A))
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/proc/can_use_rig()
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/can_use_rig()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/brain/can_use_rig()
|
||||
return istype(loc, /obj/item/mmi)
|
||||
|
||||
/mob/living/silicon/ai/can_use_rig()
|
||||
return istype(loc, /obj/item/aicard)
|
||||
|
||||
/mob/living/silicon/pai/can_use_rig()
|
||||
return loc == card
|
||||
|
||||
/mob/living/proc/HardsuitClickOn(var/atom/A, var/alert_ai = 0)
|
||||
if(!can_use_rig() || (next_move > world.time))
|
||||
return 0
|
||||
var/obj/item/rig/rig = get_rig()
|
||||
if(istype(rig) && !rig.offline && rig.selected_module)
|
||||
if(src != rig.wearer)
|
||||
if(rig.ai_can_move_suit(src, check_user_module = 1))
|
||||
message_admins("[key_name_admin(src)] is trying to force \the [key_name_admin(rig.wearer)] to use a hardsuit module.")
|
||||
else
|
||||
return 0
|
||||
rig.selected_module.engage(A, alert_ai)
|
||||
if(ismob(A)) // No instant mob attacking - though modules have their own cooldowns
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
#undef MIDDLE_CLICK
|
||||
#undef ALT_CLICK
|
||||
#undef CTRL_CLICK
|
||||
#undef MAX_HARDSUIT_CLICK_MODE
|
||||
@@ -61,7 +61,6 @@
|
||||
var/usewhitelist = 0
|
||||
var/mods_are_mentors = 0
|
||||
var/load_jobs_from_txt = 0
|
||||
var/ToRban = 0
|
||||
var/automute_on = 0 //enables automuting/spam prevention
|
||||
var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access.
|
||||
var/round_abandon_penalty_period = 30 MINUTES // Time from round start during which ghosting out is penalized
|
||||
@@ -578,9 +577,6 @@
|
||||
if("humans_need_surnames")
|
||||
humans_need_surnames = 1
|
||||
|
||||
if("tor_ban")
|
||||
ToRban = 1
|
||||
|
||||
if("automute_on")
|
||||
automute_on = 1
|
||||
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
SUBSYSTEM_DEF(alarms)
|
||||
name = "Alarms"
|
||||
init_order = INIT_ORDER_ALARMS // 2
|
||||
offline_implications = "Alarms (Power, camera, fire, etc) will no longer be checked. No immediate action is needed."
|
||||
var/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
|
||||
var/datum/alarm_handler/burglar/burglar_alarm = new()
|
||||
var/datum/alarm_handler/camera/camera_alarm = new()
|
||||
var/datum/alarm_handler/fire/fire_alarm = new()
|
||||
var/datum/alarm_handler/motion/motion_alarm = new()
|
||||
var/datum/alarm_handler/power/power_alarm = new()
|
||||
var/list/datum/alarm/all_handlers
|
||||
SUBSYSTEM_DEF(alarm)
|
||||
name = "Alarm"
|
||||
flags = SS_NO_INIT | SS_NO_FIRE
|
||||
var/list/alarms = list("Motion" = list(), "Fire" = list(), "Atmosphere" = list(), "Power" = list(), "Camera" = list(), "Burglar" = list())
|
||||
|
||||
/datum/controller/subsystem/alarms/Initialize(start_timeofday)
|
||||
all_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
|
||||
return ..()
|
||||
/datum/controller/subsystem/alarm/proc/triggerAlarm(class, area/A, list/O, obj/alarmsource)
|
||||
var/list/L = alarms[class]
|
||||
for(var/I in L)
|
||||
if(I == A.name)
|
||||
var/list/alarm = L[I]
|
||||
var/list/sources = alarm[3]
|
||||
if(!(alarmsource.UID() in sources))
|
||||
sources += alarmsource.UID()
|
||||
return TRUE
|
||||
L[A.name] = list(get_area_name(A, TRUE), O, list(alarmsource.UID()))
|
||||
SEND_SIGNAL(SSalarm, COMSIG_TRIGGERED_ALARM, class, A, O, alarmsource)
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/alarms/fire()
|
||||
for(var/datum/alarm_handler/AH in all_handlers)
|
||||
AH.process()
|
||||
/datum/controller/subsystem/alarm/proc/cancelAlarm(class, area/A, obj/origin)
|
||||
var/list/L = alarms[class]
|
||||
var/cleared = FALSE
|
||||
for(var/I in L)
|
||||
if(I == A.name)
|
||||
var/list/alarm = L[I]
|
||||
var/list/srcs = alarm[3]
|
||||
srcs -= origin.UID()
|
||||
if(!length(srcs))
|
||||
cleared = TRUE
|
||||
L -= I
|
||||
|
||||
/datum/controller/subsystem/alarms/proc/active_alarms()
|
||||
var/list/all_alarms = new ()
|
||||
for(var/datum/alarm_handler/AH in all_handlers)
|
||||
var/list/alarms = AH.alarms
|
||||
all_alarms += alarms
|
||||
|
||||
return all_alarms
|
||||
|
||||
/datum/controller/subsystem/alarms/proc/number_of_active_alarms()
|
||||
var/list/alarms = active_alarms()
|
||||
return alarms.len
|
||||
SEND_SIGNAL(SSalarm, COMSIG_CANCELLED_ALARM, class, A, origin, cleared)
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
SUBSYSTEM_DEF(chat)
|
||||
name = "Chat"
|
||||
flags = SS_TICKER|SS_NO_INIT
|
||||
wait = 1
|
||||
priority = FIRE_PRIORITY_CHAT
|
||||
init_order = INIT_ORDER_CHAT
|
||||
offline_implications = "Chat messages will no longer be cleanly queued. No immediate action is needed."
|
||||
|
||||
var/list/payload = list()
|
||||
|
||||
|
||||
/datum/controller/subsystem/chat/fire()
|
||||
for(var/i in payload)
|
||||
var/client/C = i
|
||||
if(C)
|
||||
C << output(payload[C], "browseroutput:output")
|
||||
payload -= C
|
||||
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
|
||||
/datum/controller/subsystem/chat/proc/queue(target, message, flag)
|
||||
if(!target || !message)
|
||||
return
|
||||
|
||||
if(!istext(message))
|
||||
stack_trace("to_chat called with invalid input type")
|
||||
return
|
||||
|
||||
if(target == world)
|
||||
target = GLOB.clients
|
||||
|
||||
//Some macros remain in the string even after parsing and fuck up the eventual output
|
||||
message = replacetext(message, "\improper", "")
|
||||
message = replacetext(message, "\proper", "")
|
||||
message += "<br>"
|
||||
|
||||
|
||||
//url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
|
||||
//Do the double-encoding here to save nanoseconds
|
||||
var/twiceEncoded = url_encode(url_encode(message))
|
||||
|
||||
if(islist(target))
|
||||
for(var/I in target)
|
||||
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
|
||||
|
||||
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
|
||||
continue
|
||||
|
||||
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
|
||||
C.chatOutput.messageQueue += message
|
||||
continue
|
||||
|
||||
payload[C] += twiceEncoded
|
||||
|
||||
else
|
||||
var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
|
||||
|
||||
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
|
||||
return
|
||||
|
||||
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
|
||||
C.chatOutput.messageQueue += message
|
||||
return
|
||||
|
||||
payload[C] += twiceEncoded
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* # Cleanup Subsystem
|
||||
*
|
||||
* For now, all it does is periodically clean the supplied global lists of any null values they may contain.
|
||||
*
|
||||
* Why is this important?
|
||||
*
|
||||
* Sometimes, these lists can gain nulls due to errors.
|
||||
* For example, when a dead player trasitions from the `dead_mob_list` to the `alive_mob_list`, a null value may get stuck in the dead mob list.
|
||||
* This can cause issues when other code tries to do things with the values in the list, but are instead met with null values.
|
||||
* These problems are incredibly hard to track down and fix, so this subsystem is a solution to that.
|
||||
*/
|
||||
SUBSYSTEM_DEF(cleanup)
|
||||
name = "Null cleanup"
|
||||
wait = 30 SECONDS
|
||||
flags = SS_POST_FIRE_TIMING
|
||||
priority = FIRE_PRIORITY_CLEANUP
|
||||
init_order = INIT_ORDER_CLEANUP
|
||||
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
|
||||
offline_implications = "Certain global lists will no longer be cleared of nulls, which may result in runtimes. No immediate action is needed."
|
||||
/// A list of global lists we want the subsystem to clean.
|
||||
var/list/lists_to_clean
|
||||
|
||||
/datum/controller/subsystem/cleanup/Initialize(start_timeofday)
|
||||
// If you want this subsystem to clean out nulls from a specific list, add it here.
|
||||
lists_to_clean = list(
|
||||
GLOB.clients = "clients",
|
||||
GLOB.player_list = "player_list",
|
||||
GLOB.mob_list = "mob_list",
|
||||
GLOB.alive_mob_list = "alive_mob_list",
|
||||
GLOB.dead_mob_list = "dead_mob_list",
|
||||
GLOB.human_list = "human_list",
|
||||
GLOB.carbon_list = "carbon_list"
|
||||
)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/cleanup/fire(resumed)
|
||||
for(var/L in lists_to_clean)
|
||||
var/list/_list = L
|
||||
var/prev_length = length(_list)
|
||||
listclearnulls(_list)
|
||||
|
||||
if(length(_list) < prev_length)
|
||||
stack_trace("Found a null value in GLOB.[lists_to_clean[_list]]!")
|
||||
@@ -0,0 +1,275 @@
|
||||
SUBSYSTEM_DEF(ghost_spawns)
|
||||
name = "Ghost Spawns"
|
||||
init_order = INIT_ORDER_EVENTS
|
||||
flags = SS_BACKGROUND
|
||||
wait = 1 SECONDS
|
||||
runlevels = RUNLEVEL_GAME
|
||||
offline_implications = "Ghosts will no longer be able to respawn as event mobs (Blob, etc..). Shuttle call recommended."
|
||||
|
||||
/// List of polls currently ongoing, to be checked on next fire()
|
||||
var/list/datum/candidate_poll/currently_polling
|
||||
/// Whether there are active polls or not
|
||||
var/polls_active = FALSE
|
||||
/// Number of polls performed since the start
|
||||
var/total_polls = 0
|
||||
/// The poll that's closest to finishing
|
||||
var/datum/candidate_poll/next_poll_to_finish
|
||||
|
||||
/datum/controller/subsystem/ghost_spawns/fire()
|
||||
if(!polls_active)
|
||||
return
|
||||
if(!currently_polling) // if polls_active is TRUE then this shouldn't happen, but still..
|
||||
currently_polling = list()
|
||||
|
||||
for(var/poll in currently_polling)
|
||||
var/datum/candidate_poll/P = poll
|
||||
if(P.time_left() <= 0)
|
||||
polling_finished(P)
|
||||
|
||||
/**
|
||||
* Polls for candidates with a question and a preview of the role
|
||||
*
|
||||
* This proc replaces /proc/pollCandidates.
|
||||
* Should NEVER be used in a proc that has waitfor set to FALSE/0 (due to #define UNTIL)
|
||||
* Arguments:
|
||||
* * question - The question to ask to potential candidates
|
||||
* * role - The role to poll for. Should be a ROLE_x enum. If set, potential candidates who aren't eligible will be ignored
|
||||
* * antag_age_check - Whether to filter out potential candidates who don't have an old enough account
|
||||
* * poll_time - How long to poll for in deciseconds
|
||||
* * ignore_respawnability - Whether to ignore the player's respawnability
|
||||
* * min_hours - The amount of hours needed for a potential candidate to be eligible
|
||||
* * flash_window - Whether the poll should flash a potential candidate's game window
|
||||
* * check_antaghud - Whether to filter out potential candidates who enabled AntagHUD
|
||||
* * source - The atom, atom prototype, icon or mutable appearance to display as an icon in the alert
|
||||
*/
|
||||
/datum/controller/subsystem/ghost_spawns/proc/poll_candidates(question = "Would you like to play a special role?", role, antag_age_check = FALSE, poll_time = 30 SECONDS, ignore_respawnability = FALSE, min_hours = 0, flash_window = TRUE, check_antaghud = TRUE, source)
|
||||
log_debug("Polling candidates [role ? "for [get_roletext(role)]" : "\"[question]\""] for [poll_time / 10] seconds")
|
||||
|
||||
// Start firing
|
||||
polls_active = TRUE
|
||||
total_polls++
|
||||
|
||||
var/datum/candidate_poll/P = new(role, question, poll_time)
|
||||
LAZYADD(currently_polling, P)
|
||||
|
||||
// We're the poll closest to completion
|
||||
if(!next_poll_to_finish || poll_time < next_poll_to_finish.time_left())
|
||||
next_poll_to_finish = P
|
||||
|
||||
var/category = "[P.hash]_notify_action"
|
||||
|
||||
for(var/mob/dead/observer/M in (ignore_respawnability ? GLOB.player_list : GLOB.respawnable_list))
|
||||
if(!is_eligible(M, role, antag_age_check, role, min_hours, check_antaghud))
|
||||
continue
|
||||
|
||||
SEND_SOUND(M, 'sound/misc/notice2.ogg')
|
||||
if(flash_window)
|
||||
window_flash(M.client)
|
||||
|
||||
// If we somehow send two polls for the same mob type, but with a duration on the second one shorter than the time left on the first one,
|
||||
// we need to keep the first one's timeout rather than use the shorter one
|
||||
var/obj/screen/alert/notify_action/current_alert = LAZYACCESS(M.alerts, category)
|
||||
var/alert_time = poll_time
|
||||
var/alert_poll = P
|
||||
if(current_alert && current_alert.timeout > (world.time + poll_time - world.tick_lag))
|
||||
alert_time = current_alert.timeout - world.time + world.tick_lag
|
||||
alert_poll = current_alert.poll
|
||||
|
||||
// Send them an on-screen alert
|
||||
var/obj/screen/alert/notify_action/A = M.throw_alert(category, /obj/screen/alert/notify_action, timeout_override = alert_time, no_anim = TRUE)
|
||||
if(!A)
|
||||
continue
|
||||
|
||||
A.icon = ui_style2icon(M.client?.prefs.UI_style)
|
||||
A.name = "Looking for candidates"
|
||||
A.desc = "[question]\n\n(expires in [poll_time / 10] seconds)"
|
||||
A.show_time_left = TRUE
|
||||
A.poll = alert_poll
|
||||
|
||||
// Sign up inheritance and stacking
|
||||
var/inherited_sign_up = FALSE
|
||||
var/num_stack = 1
|
||||
for(var/existing_poll in currently_polling)
|
||||
var/datum/candidate_poll/P2 = existing_poll
|
||||
if(P != P2 && P.hash == P2.hash)
|
||||
// If there's already a poll for an identical mob type ongoing and the client is signed up for it, sign them up for this one
|
||||
if(!inherited_sign_up && (M in P2.signed_up) && P.sign_up(M, TRUE))
|
||||
A.display_signed_up()
|
||||
inherited_sign_up = TRUE
|
||||
// This number is used to display the number of polls the alert regroups
|
||||
num_stack++
|
||||
if(num_stack > 1)
|
||||
A.display_stacks(num_stack)
|
||||
|
||||
// Image to display
|
||||
var/image/I
|
||||
if(source)
|
||||
if(!ispath(source))
|
||||
var/atom/S = source
|
||||
var/old_layer = S.layer
|
||||
var/old_plane = S.plane
|
||||
|
||||
S.layer = FLOAT_LAYER
|
||||
S.plane = FLOAT_PLANE
|
||||
A.overlays += S
|
||||
S.layer = old_layer
|
||||
S.plane = old_plane
|
||||
else
|
||||
I = image(source, layer = FLOAT_LAYER, dir = SOUTH)
|
||||
else
|
||||
// Just use a generic image
|
||||
I = image('icons/effects/effects.dmi', icon_state = "static", layer = FLOAT_LAYER, dir = SOUTH)
|
||||
|
||||
if(I)
|
||||
I.layer = FLOAT_LAYER
|
||||
I.plane = FLOAT_PLANE
|
||||
A.overlays += I
|
||||
|
||||
// Chat message
|
||||
var/act_jump = ""
|
||||
if(isatom(source))
|
||||
act_jump = "<a href='?src=[M.UID()];jump=\ref[source]'>\[Teleport]</a>"
|
||||
var/act_signup = "<a href='?src=[A.UID()];signup=1'>\[Sign Up]</a>"
|
||||
to_chat(M, "<big><span class='boldnotice'>Now looking for candidates [role ? "to play as \an [get_roletext(role)]" : "\"[question]\""]. [act_jump] [act_signup]</span></big>")
|
||||
|
||||
// Start processing it so it updates visually the timer
|
||||
START_PROCESSING(SSprocessing, A)
|
||||
A.process()
|
||||
|
||||
// Sleep until the time is up
|
||||
UNTIL(P.finished)
|
||||
return P.signed_up
|
||||
|
||||
/**
|
||||
* Returns whether an observer is eligible to be an event mob
|
||||
*
|
||||
* Arguments:
|
||||
* * M - The mob to check eligibility
|
||||
* * role - The role to check eligibility for. Checks 1. the client has enabled the role 2. the account's age for this role if antag_age_check is TRUE
|
||||
* * antag_age_check - Whether to check the account's age or not for the given role.
|
||||
* * role_text - The role's clean text. Used for checking job bans to determine eligibility
|
||||
* * min_hours - The amount of minimum hours the client needs before being eligible
|
||||
* * check_antaghud - Whether to consider a client who enabled AntagHUD ineligible or not
|
||||
*/
|
||||
/datum/controller/subsystem/ghost_spawns/proc/is_eligible(mob/M, role, antag_age_check, role_text, min_hours, check_antaghud)
|
||||
. = FALSE
|
||||
if(!M.key || !M.client)
|
||||
return
|
||||
if(role)
|
||||
if(!(role in M.client.prefs.be_special))
|
||||
return
|
||||
if(antag_age_check)
|
||||
if(!player_old_enough_antag(M.client, role))
|
||||
return
|
||||
if(role_text)
|
||||
if(jobban_isbanned(M, role_text) || jobban_isbanned(M, "Syndicate"))
|
||||
return
|
||||
if(config.use_exp_restrictions && min_hours)
|
||||
if(M.client.get_exp_type_num(EXP_TYPE_LIVING) < min_hours * 60)
|
||||
return
|
||||
if(check_antaghud && cannotPossess(M))
|
||||
return
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Called by the subsystem when a poll's timer runs out
|
||||
*
|
||||
* Can be called manually to finish a poll prematurely
|
||||
* Arguments:
|
||||
* * P - The poll to finish
|
||||
*/
|
||||
/datum/controller/subsystem/ghost_spawns/proc/polling_finished(datum/candidate_poll/P)
|
||||
// Trim players who aren't eligible anymore
|
||||
var/len_pre_trim = length(P.signed_up)
|
||||
P.trim_candidates()
|
||||
log_debug("Candidate poll [P.role ? "for [get_roletext(P.role)]" : "\"[P.question]\""] finished. [len_pre_trim] players signed up, [length(P.signed_up)] after trimming")
|
||||
|
||||
P.finished = TRUE
|
||||
currently_polling -= P
|
||||
|
||||
// Determine which is the next poll closest the completion or "disable" firing if there's none
|
||||
if(!length(currently_polling))
|
||||
polls_active = FALSE
|
||||
next_poll_to_finish = null
|
||||
else if(P == next_poll_to_finish)
|
||||
next_poll_to_finish = null
|
||||
for(var/poll in currently_polling)
|
||||
var/datum/candidate_poll/P2 = poll
|
||||
if(!next_poll_to_finish || P2.time_left() < next_poll_to_finish.time_left())
|
||||
next_poll_to_finish = P2
|
||||
|
||||
/datum/controller/subsystem/ghost_spawns/stat_entry(msg)
|
||||
msg += "Active: [length(currently_polling)] | Total: [total_polls]"
|
||||
if(next_poll_to_finish)
|
||||
msg += " | Next: [DisplayTimeText(next_poll_to_finish.time_left())] ([length(next_poll_to_finish.signed_up)] candidates)"
|
||||
..(msg)
|
||||
|
||||
// The datum that describes one instance of candidate polling
|
||||
/datum/candidate_poll
|
||||
var/role // The role the poll is for
|
||||
var/question // The question asked to observers
|
||||
var/duration // The duration of the poll
|
||||
var/list/mob/dead/observer/signed_up // The players who signed up to this poll
|
||||
var/time_started // The world.time at which the poll was created
|
||||
var/finished = FALSE // Whether the polling is finished
|
||||
var/hash // Used to categorize in the alerts system
|
||||
|
||||
/datum/candidate_poll/New(polled_role, polled_question, poll_duration)
|
||||
role = polled_role
|
||||
question = polled_question
|
||||
duration = poll_duration
|
||||
signed_up = list()
|
||||
time_started = world.time
|
||||
hash = copytext(md5("[question]_[role ? role : "0"]"), 1, 7)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Attempts to sign a (controlled) mob up
|
||||
*
|
||||
* Will fail if the mob is already signed up or the poll's timer ran out.
|
||||
* Does not check for eligibility
|
||||
* Arguments:
|
||||
* * M - The (controlled) mob to sign up
|
||||
* * silent - Whether no messages should appear or not. If not TRUE, signing up to this poll will also sign the mob up for identical polls
|
||||
*/
|
||||
/datum/candidate_poll/proc/sign_up(mob/dead/observer/M, silent = FALSE)
|
||||
. = FALSE
|
||||
if(!istype(M) || !M.key || !M.client)
|
||||
return
|
||||
if(M in signed_up)
|
||||
if(!silent)
|
||||
to_chat(M, "<span class='warning'>You have already signed up for this!</span>")
|
||||
return
|
||||
if(time_left() <= 0)
|
||||
if(!silent)
|
||||
to_chat(M, "<span class='danger'>Sorry, you were too late for the consideration!</span>")
|
||||
SEND_SOUND(M, 'sound/machines/buzz-sigh.ogg')
|
||||
return
|
||||
|
||||
signed_up += M
|
||||
if(!silent)
|
||||
to_chat(M, "<span class='notice'>You have signed up for this role! A candidate will be picked randomly soon..</span>")
|
||||
// Sign them up for any other polls with the same mob type
|
||||
for(var/existing_poll in SSghost_spawns.currently_polling)
|
||||
var/datum/candidate_poll/P = existing_poll
|
||||
if(src != P && hash == P.hash && !(M in P.signed_up))
|
||||
P.sign_up(M, TRUE)
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Deletes any candidates who may have disconnected from the list
|
||||
*/
|
||||
/datum/candidate_poll/proc/trim_candidates()
|
||||
listclearnulls(signed_up)
|
||||
for(var/mob in signed_up)
|
||||
var/mob/M = mob
|
||||
if(!M.key || !M.client)
|
||||
signed_up -= M
|
||||
|
||||
/**
|
||||
* Returns the time left for a poll
|
||||
*/
|
||||
/datum/candidate_poll/proc/time_left()
|
||||
return duration - (world.time - time_started)
|
||||
@@ -27,7 +27,7 @@ SUBSYSTEM_DEF(jobs)
|
||||
/datum/controller/subsystem/jobs/fire()
|
||||
if(!config.sql_enabled || !config.use_exp_tracking)
|
||||
return
|
||||
update_exp(5,0)
|
||||
INVOKE_ASYNC(GLOBAL_PROC, /.proc/update_exp, 5, 0)
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/SetupOccupations(var/list/faction = list("Station"))
|
||||
occupations = list()
|
||||
@@ -620,20 +620,32 @@ SUBSYSTEM_DEF(jobs)
|
||||
var/mob/M = tgtcard.getPlayer()
|
||||
for(var/datum/job/job in occupations)
|
||||
if(tgtcard.assignment && tgtcard.assignment == job.title)
|
||||
jobs_to_formats[job.title] = "disabled" // the job they already have is pre-selected
|
||||
jobs_to_formats[job.title] = "green" // the job they already have is pre-selected
|
||||
else if(tgtcard.assignment == "Demoted" || tgtcard.assignment == "Terminated")
|
||||
jobs_to_formats[job.title] = "grey"
|
||||
else if(!job.would_accept_job_transfer_from_player(M))
|
||||
jobs_to_formats[job.title] = "linkDiscourage" // jobs which are karma-locked and not unlocked for this player are discouraged
|
||||
jobs_to_formats[job.title] = "grey" // jobs which are karma-locked and not unlocked for this player are discouraged
|
||||
else if((job.title in GLOB.command_positions) && istype(M) && M.client && job.available_in_playtime(M.client))
|
||||
jobs_to_formats[job.title] = "linkDiscourage" // command jobs which are playtime-locked and not unlocked for this player are discouraged
|
||||
jobs_to_formats[job.title] = "grey" // command jobs which are playtime-locked and not unlocked for this player are discouraged
|
||||
else if(job.total_positions && !job.current_positions && job.title != "Civilian")
|
||||
jobs_to_formats[job.title] = "linkEncourage" // jobs with nobody doing them at all are encouraged
|
||||
jobs_to_formats[job.title] = "teal" // jobs with nobody doing them at all are encouraged
|
||||
else if(job.total_positions >= 0 && job.current_positions >= job.total_positions)
|
||||
jobs_to_formats[job.title] = "linkDiscourage" // jobs that are full (no free positions) are discouraged
|
||||
jobs_to_formats[job.title] = "grey" // jobs that are full (no free positions) are discouraged
|
||||
if(tgtcard.assignment == "Demoted" || tgtcard.assignment == "Terminated")
|
||||
jobs_to_formats["Custom"] = "grey"
|
||||
return jobs_to_formats
|
||||
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/log_job_transfer(transferee, oldvalue, newvalue, whodidit)
|
||||
id_change_records["[id_change_counter]"] = list("transferee" = transferee, "oldvalue" = oldvalue, "newvalue" = newvalue, "whodidit" = whodidit, "timestamp" = station_time_timestamp())
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/log_job_transfer(transferee, oldvalue, newvalue, whodidit, reason)
|
||||
id_change_records["[id_change_counter]"] = list(
|
||||
"transferee" = transferee,
|
||||
"oldvalue" = oldvalue,
|
||||
"newvalue" = newvalue,
|
||||
"whodidit" = whodidit,
|
||||
"timestamp" = station_time_timestamp(),
|
||||
"reason" = reason
|
||||
)
|
||||
id_change_counter++
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/slot_job_transfer(oldtitle, newtitle)
|
||||
@@ -644,43 +656,54 @@ SUBSYSTEM_DEF(jobs)
|
||||
oldjobdatum.current_positions--
|
||||
newjobdatum.current_positions++
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/notify_dept_head(jobtitle, antext)
|
||||
// Used to notify the department head of jobtitle X that their employee was brigged, demoted or terminated
|
||||
if(!jobtitle || !antext)
|
||||
return
|
||||
var/datum/job/tgt_job = GetJob(jobtitle)
|
||||
if(!tgt_job)
|
||||
return
|
||||
if(!tgt_job.department_head[1])
|
||||
return
|
||||
var/boss_title = tgt_job.department_head[1]
|
||||
var/obj/item/pda/target_pda
|
||||
for(var/obj/item/pda/check_pda in GLOB.PDAs)
|
||||
if(check_pda.ownrank == boss_title)
|
||||
target_pda = check_pda
|
||||
break
|
||||
if(!target_pda)
|
||||
return
|
||||
var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger)
|
||||
if(PM && PM.can_receive())
|
||||
PM.notify("<b>Automated Notification: </b>\"[antext]\" (Unable to Reply)", 0) // the 0 means don't make the PDA flash
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/fetch_transfer_record_html(var/centcom)
|
||||
var/record_html = "<TABLE border=\"1\">"
|
||||
/datum/controller/subsystem/jobs/proc/notify_by_name(target_name, antext)
|
||||
// Used to notify a specific crew member based on their real_name
|
||||
if(!target_name || !antext)
|
||||
return
|
||||
var/obj/item/pda/target_pda
|
||||
for(var/obj/item/pda/check_pda in GLOB.PDAs)
|
||||
if(check_pda.owner == target_name)
|
||||
target_pda = check_pda
|
||||
break
|
||||
if(!target_pda)
|
||||
return
|
||||
var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger)
|
||||
if(PM && PM.can_receive())
|
||||
PM.notify("<b>Automated Notification: </b>\"[antext]\" (Unable to Reply)", 0) // the 0 means don't make the PDA flash
|
||||
|
||||
var/table_headers = list("Crewman", "Old Rank", "New Rank", "Authorized By", "Time")
|
||||
var/hidden_fields = list("deletedby")
|
||||
if(centcom)
|
||||
table_headers += "<span class='bad'>Deleted By</span>"
|
||||
record_html += "<TR>"
|
||||
for(var/thisheader in table_headers)
|
||||
record_html += "<TD><B>[thisheader]</B></TD>"
|
||||
record_html += "</TR>"
|
||||
|
||||
var/visible_record_count = 0
|
||||
/datum/controller/subsystem/jobs/proc/format_job_change_records(centcom)
|
||||
var/list/formatted = list()
|
||||
for(var/thisid in id_change_records)
|
||||
var/thisrecord = id_change_records[thisid]
|
||||
|
||||
if(thisrecord["deletedby"] && !centcom)
|
||||
continue
|
||||
|
||||
record_html += "<TR>"
|
||||
var/list/newlist = list()
|
||||
for(var/lkey in thisrecord)
|
||||
if(lkey in hidden_fields)
|
||||
if(centcom)
|
||||
record_html += "<TD><span class='bad'>[thisrecord[lkey]]<span></TD>"
|
||||
else
|
||||
continue
|
||||
else
|
||||
record_html += "<TD>[thisrecord[lkey]]</TD>"
|
||||
record_html += "</TR>"
|
||||
visible_record_count++
|
||||
newlist[lkey] = thisrecord[lkey]
|
||||
formatted.Add(list(newlist))
|
||||
return formatted
|
||||
|
||||
record_html += "</TABLE>"
|
||||
|
||||
if(!visible_record_count)
|
||||
return "No records on file yet."
|
||||
return record_html
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/delete_log_records(sourceuser, delete_all)
|
||||
. = 0
|
||||
|
||||
@@ -34,7 +34,7 @@ SUBSYSTEM_DEF(parallax)
|
||||
for (A; isloc(A.loc) && !isturf(A.loc); A = A.loc);
|
||||
|
||||
if(A != C.movingmob)
|
||||
if(C.movingmob != null)
|
||||
if(C.movingmob != null && C.movingmob.client_mobs_in_contents)
|
||||
C.movingmob.client_mobs_in_contents -= C.mob
|
||||
UNSETEMPTY(C.movingmob.client_mobs_in_contents)
|
||||
LAZYINITLIST(A.client_mobs_in_contents)
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(instruments)
|
||||
name = "Instruments"
|
||||
init_order = INIT_ORDER_INSTRUMENTS
|
||||
wait = 1
|
||||
flags = SS_TICKER|SS_BACKGROUND|SS_KEEP_TIMING
|
||||
offline_implications = "Instruments will no longer play. No immediate action is needed."
|
||||
|
||||
/// List of all instrument data, associative id = datum
|
||||
var/list/datum/instrument/instrument_data
|
||||
/// List of all song datums.
|
||||
var/list/datum/song/songs
|
||||
/// Max lines in songs
|
||||
var/musician_maxlines = 600
|
||||
/// Max characters per line in songs
|
||||
var/musician_maxlinechars = 300
|
||||
/// Deciseconds between hearchecks. Too high and instruments seem to lag when people are moving around in terms of who can hear it. Too low and the server lags from this.
|
||||
var/musician_hearcheck_mindelay = 5
|
||||
/// Maximum instrument channels total instruments are allowed to use. This is so you don't have instruments deadlocking all sound channels.
|
||||
var/max_instrument_channels = MAX_INSTRUMENT_CHANNELS
|
||||
/// Current number of channels allocated for instruments
|
||||
var/current_instrument_channels = 0
|
||||
/// Single cached list for synthesizer instrument ids, so you don't have to have a new list with every synthesizer.
|
||||
var/list/synthesizer_instrument_ids
|
||||
|
||||
/datum/controller/subsystem/processing/instruments/Initialize()
|
||||
initialize_instrument_data()
|
||||
synthesizer_instrument_ids = get_allowed_instrument_ids()
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Initializes all instrument datums
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/initialize_instrument_data()
|
||||
instrument_data = list()
|
||||
for(var/path in subtypesof(/datum/instrument))
|
||||
var/datum/instrument/I = path
|
||||
if(initial(I.abstract_type) == path)
|
||||
continue
|
||||
I = new path
|
||||
I.Initialize()
|
||||
if(!I.id)
|
||||
qdel(I)
|
||||
continue
|
||||
else
|
||||
instrument_data[I.id] = I
|
||||
CHECK_TICK
|
||||
|
||||
/**
|
||||
* Reserves a sound channel for a given instrument datum
|
||||
*
|
||||
* Arguments:
|
||||
* * I - The instrument datum
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/reserve_instrument_channel(datum/instrument/I)
|
||||
if(current_instrument_channels > max_instrument_channels)
|
||||
return
|
||||
. = SSsounds.reserve_sound_channel(I)
|
||||
if(!isnull(.))
|
||||
current_instrument_channels++
|
||||
|
||||
/**
|
||||
* Called when a datum/song is created
|
||||
*
|
||||
* Arguments:
|
||||
* * S - The created datum/song
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/on_song_new(datum/song/S)
|
||||
LAZYADD(songs, S)
|
||||
|
||||
/**
|
||||
* Called when a datum/song is deleted
|
||||
*
|
||||
* Arguments:
|
||||
* * S - The deleted datum/song
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/on_song_del(datum/song/S)
|
||||
LAZYREMOVE(songs, S)
|
||||
|
||||
/**
|
||||
* Returns the instrument datum at the given ID or path
|
||||
*
|
||||
* Arguments:
|
||||
* * id_or_path - The ID or path of the instrument
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/get_instrument(id_or_path)
|
||||
return instrument_data["[id_or_path]"]
|
||||
@@ -14,9 +14,9 @@ SUBSYSTEM_DEF(shuttle)
|
||||
//emergency shuttle stuff
|
||||
var/obj/docking_port/mobile/emergency/emergency
|
||||
var/obj/docking_port/mobile/emergency/backup/backup_shuttle
|
||||
var/emergencyCallTime = 6000 //time taken for emergency shuttle to reach the station when called (in deciseconds)
|
||||
var/emergencyDockTime = 1800 //time taken for emergency shuttle to leave again once it has docked (in deciseconds)
|
||||
var/emergencyEscapeTime = 1200 //time taken for emergency shuttle to reach a safe distance after leaving station (in deciseconds)
|
||||
var/emergencyCallTime = SHUTTLE_CALLTIME //time taken for emergency shuttle to reach the station when called (in deciseconds)
|
||||
var/emergencyDockTime = SHUTTLE_DOCKTIME //time taken for emergency shuttle to leave again once it has docked (in deciseconds)
|
||||
var/emergencyEscapeTime = SHUTTLE_ESCAPETIME //time taken for emergency shuttle to reach a safe distance after leaving station (in deciseconds)
|
||||
var/emergency_sec_level_time = 0 // time sec level was last raised to red or higher
|
||||
var/area/emergencyLastCallLoc
|
||||
var/emergencyNoEscape
|
||||
@@ -93,6 +93,11 @@ SUBSYSTEM_DEF(shuttle)
|
||||
return S
|
||||
WARNING("couldn't find dock with id: [id]")
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/secondsToRefuel()
|
||||
var/elapsed = world.time - SSticker.round_start_time
|
||||
var/remaining = round((config.shuttle_refuel_delay - elapsed) / 10)
|
||||
return remaining > 0 ? remaining : 0
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason)
|
||||
if(!emergency)
|
||||
WARNING("requestEvac(): There is no emergency shuttle, but the shuttle was called. Using the backup shuttle instead.")
|
||||
@@ -107,7 +112,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
return
|
||||
emergency = backup_shuttle
|
||||
|
||||
if(world.time - SSticker.round_start_time < config.shuttle_refuel_delay)
|
||||
if(secondsToRefuel())
|
||||
to_chat(user, "The emergency shuttle is refueling. Please wait another [abs(round(((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)/600))] minutes before trying again.")
|
||||
return
|
||||
|
||||
@@ -131,7 +136,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
call_reason = trim(html_encode(call_reason))
|
||||
|
||||
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH)
|
||||
to_chat(user, "You must provide a reason.")
|
||||
to_chat(user, "Reason is too short. [CALL_SHUTTLE_REASON_LENGTH] character minimum.")
|
||||
return
|
||||
|
||||
var/area/signal_origin = get_area(user)
|
||||
@@ -192,7 +197,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
var/obj/machinery/computer/communications/C = thing
|
||||
if(C.stat & BROKEN)
|
||||
continue
|
||||
else if(istype(thing, /datum/computer_file/program/comm) || istype(thing, /obj/item/circuitboard/communications))
|
||||
else if(istype(thing, /obj/item/circuitboard/communications))
|
||||
continue
|
||||
|
||||
var/turf/T = get_turf(thing)
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#define DATUMLESS "NO_DATUM"
|
||||
|
||||
SUBSYSTEM_DEF(sounds)
|
||||
name = "Sounds"
|
||||
init_order = INIT_ORDER_SOUNDS
|
||||
flags = SS_NO_FIRE
|
||||
offline_implications = "Sounds may not play correctly. Shuttle call recommended."
|
||||
|
||||
var/using_channels_max = CHANNEL_HIGHEST_AVAILABLE // BYOND max channels
|
||||
/// Amount of channels to reserve for random usage rather than reservations being allowed to reserve all channels. Also a nice safeguard for when someone screws up.
|
||||
var/random_channels_min = 50
|
||||
// Hey uh these two needs to be initialized fast because the whole "things get deleted before init" thing.
|
||||
/// Assoc list, "[channel]" = either the datum using it or TRUE for an unsafe-reserved (datumless reservation) channel
|
||||
var/list/using_channels
|
||||
/// Assoc list datum = list(channel1, channel2, ...) for what channels something reserved.
|
||||
var/list/using_channels_by_datum
|
||||
// Special datastructure for fast channel management
|
||||
/// List of all channels as numbers
|
||||
var/list/channel_list
|
||||
/// Associative list of all reserved channels associated to their position. "[channel_number]" = index as number
|
||||
var/list/reserved_channels
|
||||
/// lower iteration position - Incremented and looped to get "random" sound channels for normal sounds. The channel at this index is returned when asking for a random channel.
|
||||
var/channel_random_low
|
||||
/// higher reserve position - decremented and incremented to reserve sound channels, anything above this is reserved. The channel at this index is the highest unreserved channel.
|
||||
var/channel_reserve_high
|
||||
|
||||
/datum/controller/subsystem/sounds/Initialize()
|
||||
setup_available_channels()
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Sets up all available sound channels
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/setup_available_channels()
|
||||
channel_list = list()
|
||||
reserved_channels = list()
|
||||
using_channels = list()
|
||||
using_channels_by_datum = list()
|
||||
for(var/i in 1 to using_channels_max)
|
||||
channel_list += i
|
||||
channel_random_low = 1
|
||||
channel_reserve_high = length(channel_list)
|
||||
|
||||
/**
|
||||
* Removes a channel from using list
|
||||
*
|
||||
* Arguments:
|
||||
* * channel - The channel number
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/free_sound_channel(channel)
|
||||
var/text_channel = num2text(channel)
|
||||
var/using = using_channels[text_channel]
|
||||
using_channels -= text_channel
|
||||
if(!using) // datum channel
|
||||
using_channels_by_datum[using] -= channel
|
||||
if(!length(using_channels_by_datum[using]))
|
||||
using_channels_by_datum -= using
|
||||
free_channel(channel)
|
||||
|
||||
/**
|
||||
* Frees all the channels a datum is using
|
||||
*
|
||||
* Arguments:
|
||||
* * D - The datum
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/free_datum_channels(datum/D)
|
||||
var/list/L = using_channels_by_datum[D]
|
||||
if(!L)
|
||||
return
|
||||
for(var/channel in L)
|
||||
using_channels -= num2text(channel)
|
||||
free_channel(channel)
|
||||
using_channels_by_datum -= D
|
||||
|
||||
/**
|
||||
* Frees all datumless channels
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/free_datumless_channels()
|
||||
free_datum_channels(DATUMLESS)
|
||||
|
||||
/**
|
||||
* NO AUTOMATIC CLEANUP - If you use this, you better manually free it later!
|
||||
*
|
||||
* Returns an integer for channel
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/reserve_sound_channel_datumless()
|
||||
. = reserve_channel()
|
||||
if(!.) // oh no..
|
||||
return FALSE
|
||||
var/text_channel = num2text(.)
|
||||
using_channels[text_channel] = DATUMLESS
|
||||
LAZYADD(using_channels_by_datum[DATUMLESS], .)
|
||||
|
||||
/**
|
||||
* Reserves a channel for a datum. Automatic cleanup only when the datum is deleted.
|
||||
*
|
||||
* Returns an integer for channel
|
||||
* Arguments:
|
||||
* * D - The datum
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/reserve_sound_channel(datum/D)
|
||||
if(!D) // i don't like typechecks but someone will fuck it up
|
||||
CRASH("Attempted to reserve sound channel without datum using the managed proc.")
|
||||
. = reserve_channel()
|
||||
if(!.)
|
||||
return FALSE
|
||||
var/text_channel = num2text(.)
|
||||
using_channels[text_channel] = D
|
||||
LAZYADD(using_channels_by_datum[D], .)
|
||||
|
||||
/**
|
||||
* Reserves a channel and updates the datastructure. Private proc.
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/reserve_channel()
|
||||
PRIVATE_PROC(TRUE)
|
||||
if(channel_reserve_high <= random_channels_min) // out of channels
|
||||
return
|
||||
var/channel = channel_list[channel_reserve_high]
|
||||
reserved_channels[num2text(channel)] = channel_reserve_high--
|
||||
return channel
|
||||
|
||||
/**
|
||||
* Frees a channel and updates the datastructure. Private proc.
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/free_channel(number)
|
||||
PRIVATE_PROC(TRUE)
|
||||
var/text_channel = num2text(number)
|
||||
var/index = reserved_channels[text_channel]
|
||||
if(!index)
|
||||
CRASH("Attempted to (internally) free a channel that wasn't reserved.")
|
||||
reserved_channels -= text_channel
|
||||
// push reserve index up, which makes it now on a channel that is reserved
|
||||
channel_reserve_high++
|
||||
// swap the reserved channel with the unreserved channel so the reserve index is now on an unoccupied channel and the freed channel is next to be used.
|
||||
channel_list.Swap(channel_reserve_high, index)
|
||||
// now, an existing reserved channel will likely (exception: unreserving last reserved channel) be at index
|
||||
// get it, and update position.
|
||||
var/text_reserved = num2text(channel_list[index])
|
||||
if(!reserved_channels[text_reserved]) // if it isn't already reserved make sure we don't accidently mistakenly put it on reserved list!
|
||||
return
|
||||
reserved_channels[text_reserved] = index
|
||||
|
||||
/**
|
||||
* Random available channel, returns text
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/random_available_channel_text()
|
||||
if(channel_random_low > channel_reserve_high)
|
||||
channel_random_low = 1
|
||||
. = "[channel_list[channel_random_low++]]"
|
||||
|
||||
/**
|
||||
* Random available channel, returns number
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/random_available_channel()
|
||||
if(channel_random_low > channel_reserve_high)
|
||||
channel_random_low = 1
|
||||
. = channel_list[channel_random_low++]
|
||||
|
||||
/**
|
||||
* How many channels we have left
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/available_channels_left()
|
||||
return length(channel_list) - random_channels_min
|
||||
|
||||
#undef DATUMLESS
|
||||
@@ -61,7 +61,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(GAME_STATE_STARTUP)
|
||||
// This is ran as soon as the MC starts firing, and should only run ONCE, unless startup fails
|
||||
round_start_time = world.time + (config.pregame_timestart * 10)
|
||||
to_chat(world, "<B><FONT color='blue'>Welcome to the pre-game lobby!</FONT></B>")
|
||||
to_chat(world, "<B><span class='darkmblue'>Welcome to the pre-game lobby!</span></B>")
|
||||
to_chat(world, "Please, setup your character and select ready. Game will start in [config.pregame_timestart] seconds")
|
||||
current_state = GAME_STATE_PREGAME
|
||||
fire() // TG says this is a good idea
|
||||
@@ -217,11 +217,11 @@ SUBSYSTEM_DEF(ticker)
|
||||
for(var/obj/effect/landmark/spacepod/random/R in L)
|
||||
qdel(R)
|
||||
|
||||
to_chat(world, "<FONT color='blue'><B>Enjoy the game!</B></FONT>")
|
||||
to_chat(world, "<span class='darkmblue'><B>Enjoy the game!</B></span>")
|
||||
world << sound('sound/AI/welcome.ogg')// Skie
|
||||
|
||||
if(SSholiday.holidays)
|
||||
to_chat(world, "<font color='blue'>and...</font>")
|
||||
to_chat(world, "<span class='darkmblue'>and...</span>")
|
||||
for(var/holidayname in SSholiday.holidays)
|
||||
var/datum/holiday/holiday = SSholiday.holidays[holidayname]
|
||||
to_chat(world, "<h4>[holiday.greet()]</h4>")
|
||||
|
||||
@@ -6,17 +6,23 @@ GLOBAL_REAL(SSmentor_tickets, /datum/controller/subsystem/tickets/mentor_tickets
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets
|
||||
name = "Mentor Tickets"
|
||||
offline_implications = "Mentor tickets will no longer be marked as stale. No immediate action is needed."
|
||||
ticket_system_name = "Mentor Tickets"
|
||||
ticket_name = "Mentor Ticket"
|
||||
span_class = "mentorhelp"
|
||||
other_ticket_name = "Admin"
|
||||
other_ticket_permission = R_ADMIN
|
||||
close_rights = R_MENTOR | R_ADMIN
|
||||
offline_implications = "Mentor tickets will no longer be marked as stale. No immediate action is needed."
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/message_staff(var/msg)
|
||||
message_mentorTicket(msg)
|
||||
rights_needed = R_MENTOR | R_ADMIN | R_MOD
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/Initialize()
|
||||
close_messages = list("<font color='red' size='3'><b>- [ticket_name] Closed -</b></font>",
|
||||
"<span class='boldmessage'>Please try to be as descriptive as possible in mentor helps. Mentors do not know the full situation you're in and need more information to give you a helpful response.</span>",
|
||||
"<span class='[span_class]'>Your [ticket_name] has now been closed.</span>")
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/message_staff(msg)
|
||||
message_mentorTicket(msg)
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/create_other_system_ticket(datum/ticket/T)
|
||||
SStickets.newTicket(T.clientName, T.content, T.title)
|
||||
|
||||
@@ -12,18 +12,23 @@
|
||||
|
||||
SUBSYSTEM_DEF(tickets)
|
||||
name = "Admin Tickets"
|
||||
var/span_class = "adminticket"
|
||||
var/ticket_system_name = "Admin Tickets"
|
||||
var/ticket_name = "Admin Ticket"
|
||||
var/close_rights = R_ADMIN
|
||||
var/list/close_messages
|
||||
init_order = INIT_ORDER_TICKETS
|
||||
wait = 300
|
||||
priority = FIRE_PRIORITY_TICKETS
|
||||
offline_implications = "Admin tickets will no longer be marked as stale. No immediate action is needed."
|
||||
|
||||
flags = SS_BACKGROUND
|
||||
|
||||
var/span_class = "adminticket"
|
||||
var/ticket_system_name = "Admin Tickets"
|
||||
var/ticket_name = "Admin Ticket"
|
||||
var/close_rights = R_ADMIN
|
||||
var/rights_needed = R_ADMIN | R_MOD
|
||||
|
||||
/// The name of the other ticket type to convert to
|
||||
var/other_ticket_name = "Mentor"
|
||||
/// Which permission to look for when seeing if there is staff available for the other ticket type
|
||||
var/other_ticket_permission = R_MENTOR
|
||||
var/list/close_messages
|
||||
var/list/allTickets = list() //make it here because someone might ahelp before the system has initialized
|
||||
|
||||
var/ticketCounter = 1
|
||||
@@ -114,9 +119,37 @@ SUBSYSTEM_DEF(tickets)
|
||||
to_chat_safe(returnClient(N), "<span class='[span_class]'>Your [ticket_name] has now been resolved.</span>")
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/convert_to_other_ticket(ticketId)
|
||||
if(!check_rights(rights_needed))
|
||||
return
|
||||
if(alert("Are you sure to convert this ticket to an '[other_ticket_name]' ticket?",,"Yes","No") != "Yes")
|
||||
return
|
||||
if(!other_ticket_system_staff_check())
|
||||
return
|
||||
var/datum/ticket/T = allTickets[ticketId]
|
||||
convert_ticket(T)
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/other_ticket_system_staff_check()
|
||||
var/list/staff = staff_countup(other_ticket_permission)
|
||||
if(!staff[1])
|
||||
if(alert("No active staff online to answer the ticket. Are you sure you want to convert the ticket?",, "No", "Yes") != "Yes")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/convert_ticket(datum/ticket/T)
|
||||
T.ticketState = TICKET_CLOSED
|
||||
var/client/C = usr.client
|
||||
to_chat_safe(T.clientName, list("<span class='[span_class]'>[key_name_hidden(C)] has converted your ticket to a [other_ticket_name] ticket.</span>",\
|
||||
"<span class='[span_class]'>Be sure to use the correct type of help next time!</span>"))
|
||||
message_staff("<span class='[span_class]'>[C] has converted ticket number [T.ticketNum] to a [other_ticket_name] ticket.</span>")
|
||||
log_game("[C] has converted ticket number [T.ticketNum] to a [other_ticket_name] ticket.")
|
||||
create_other_system_ticket(T)
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/create_other_system_ticket(datum/ticket/T)
|
||||
SSmentor_tickets.newTicket(T.clientName, T.content, T.title)
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/autoRespond(N)
|
||||
if(!check_rights(R_ADMIN|R_MOD))
|
||||
if(!check_rights(rights_needed))
|
||||
return
|
||||
|
||||
var/datum/ticket/T = allTickets[N]
|
||||
@@ -131,6 +164,7 @@ SUBSYSTEM_DEF(tickets)
|
||||
"Already Resolved" = "The problem has been resolved already.",
|
||||
"Mentorhelp" = "Please redirect your question to Mentorhelp, as they are better experienced with these types of questions.",
|
||||
"Happens Again" = "Thanks, let us know if it continues to happen.",
|
||||
"Github Issue Report" = "To report a bug, please go to our <a href='[config.githuburl]'>Github page</a>. Then go to 'Issues'. Then 'New Issue'. Then fill out the report form. If the report would reveal current-round information, file it after the round ends.",
|
||||
"Clear Cache" = "To fix a blank screen, go to the 'Special Verbs' tab and press 'Reload UI Resources'. If that fails, clear your BYOND cache (instructions provided with 'Reload UI Resources'). If that still fails, please adminhelp again, stating you have already done the following." ,
|
||||
"IC Issue" = "This is an In Character (IC) issue and will not be handled by admins. You could speak to Security, Internal Affairs, a Departmental Head, Nanotrasen Representetive, or any other relevant authority currently on station.",
|
||||
"Reject" = "Reject",
|
||||
@@ -157,14 +191,17 @@ SUBSYSTEM_DEF(tickets)
|
||||
resolveTicket(N)
|
||||
message_staff("[C] has auto responded to [T.clientName]\'s adminhelp with:<span class='adminticketalt'> [message_key] </span>")
|
||||
log_game("[C] has auto responded to [T.clientName]\'s adminhelp with: [response_phrases[message_key]]")
|
||||
if("Mentorhelp")
|
||||
convert_ticket(T)
|
||||
else
|
||||
var/msg_sound = sound('sound/effects/adminhelp.ogg')
|
||||
SEND_SOUND(returnClient(N), msg_sound)
|
||||
to_chat(returnClient(N), "<span class='[span_class]'>[key_name_hidden(C)] is autoresponding with: <span/> <span class='adminticketalt'>[response_phrases[message_key]]</span>")//for this we want the full value of whatever key this is to tell the player so we do response_phrases[message_key]
|
||||
to_chat_safe(returnClient(N), "<span class='[span_class]'>[key_name_hidden(C)] is autoresponding with: <span/> <span class='adminticketalt'>[response_phrases[message_key]]</span>")//for this we want the full value of whatever key this is to tell the player so we do response_phrases[message_key]
|
||||
message_staff("[C] has auto responded to [T.clientName]\'s adminhelp with:<span class='adminticketalt'> [message_key] </span>") //we want to use the short named keys for this instead of the full sentence which is why we just do message_key
|
||||
T.lastStaffResponse = "Autoresponse: [message_key]"
|
||||
resolveTicket(N)
|
||||
log_game("[C] has auto responded to [T.clientName]\'s adminhelp with: [response_phrases[message_key]]")
|
||||
|
||||
//Set ticket state with key N to closed
|
||||
/datum/controller/subsystem/tickets/proc/closeTicket(N)
|
||||
var/datum/ticket/T = allTickets[N]
|
||||
@@ -352,7 +389,7 @@ UI STUFF
|
||||
dat += "<tr><td>[T.content[i]]</td></tr>"
|
||||
|
||||
dat += "</table><br /><br />"
|
||||
dat += "<a href='?src=[UID()];detailreopen=[T.ticketNum]'>Re-Open</a>[check_rights(R_ADMIN|R_MOD, 0) ? "<a href='?src=[UID()];autorespond=[T.ticketNum]'>Auto</a>": ""]<a href='?src=[UID()];detailresolve=[T.ticketNum]'>Resolve</a><br /><br />"
|
||||
dat += "<a href='?src=[UID()];detailreopen=[T.ticketNum]'>Re-Open</a>[check_rights(rights_needed, 0) ? "<a href='?src=[UID()];autorespond=[T.ticketNum]'>Auto</a>": ""]<a href='?src=[UID()];detailresolve=[T.ticketNum]'>Resolve</a><br /><br />"
|
||||
|
||||
if(!T.staffAssigned)
|
||||
dat += "No staff member assigned to this [ticket_name] - <a href='?src=[UID()];assignstaff=[T.ticketNum]'>Take Ticket</a><br />"
|
||||
@@ -367,6 +404,7 @@ UI STUFF
|
||||
dat += "<br /><br />"
|
||||
|
||||
dat += "<a href='?src=[UID()];detailclose=[T.ticketNum]'>Close Ticket</a>"
|
||||
dat += "<a href='?src=[UID()];convert_ticket=[T.ticketNum]'>Convert Ticket</a>"
|
||||
|
||||
var/datum/browser/popup = new(user, "[ticket_system_name]detail", "[ticket_system_name] #[T.ticketNum]", 1000, 600)
|
||||
popup.set_content(dat)
|
||||
@@ -449,7 +487,6 @@ UI STUFF
|
||||
if(closeTicket(indexNum))
|
||||
showDetailUI(usr, indexNum)
|
||||
|
||||
|
||||
if(href_list["detailreopen"])
|
||||
var/indexNum = text2num(href_list["detailreopen"])
|
||||
if(openTicket(indexNum))
|
||||
@@ -469,6 +506,10 @@ UI STUFF
|
||||
var/indexNum = text2num(href_list["autorespond"])
|
||||
autoRespond(indexNum)
|
||||
|
||||
if(href_list["convert_ticket"])
|
||||
var/indexNum = text2num(href_list["convert_ticket"])
|
||||
convert_to_other_ticket(indexNum)
|
||||
|
||||
if(href_list["resolveall"])
|
||||
if(ticket_system_name == "Mentor Tickets")
|
||||
usr.client.resolveAllMentorTickets()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
set name = "Restart Controller"
|
||||
set desc = "Restart one of the various periodic loop controllers for the game (be careful!)"
|
||||
|
||||
if(!holder)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
switch(controller)
|
||||
if("Master")
|
||||
@@ -20,13 +20,14 @@
|
||||
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
|
||||
|
||||
/client/proc/debug_controller(controller in list("failsafe", "Master", "Ticker", "Air", "Jobs", "Sun", "Radio", "Configuration", "pAI",
|
||||
"Cameras", "Garbage", "Event", "Alarm", "Nano", "Vote", "Fires",
|
||||
"Cameras", "Garbage", "Event", "Nano", "Vote", "Fires",
|
||||
"Mob", "NPC Pool", "Shuttle", "Timer", "Weather", "Space", "Mob Hunt Server","Input"))
|
||||
set category = "Debug"
|
||||
set name = "Debug Controller"
|
||||
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
|
||||
|
||||
if(!holder) return
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
switch(controller)
|
||||
if("failsafe")
|
||||
debug_variables(Failsafe)
|
||||
@@ -64,9 +65,6 @@
|
||||
if("Event")
|
||||
debug_variables(SSevents)
|
||||
feedback_add_details("admin_verb","DEvent")
|
||||
if("Alarm")
|
||||
debug_variables(SSalarms)
|
||||
feedback_add_details("admin_verb", "DAlarm")
|
||||
if("Nano")
|
||||
debug_variables(SSnanoui)
|
||||
feedback_add_details("admin_verb","DNano")
|
||||
|
||||
+16
-16
@@ -190,9 +190,6 @@
|
||||
/datum/action/item_action/toggle_mister
|
||||
name = "Toggle Mister"
|
||||
|
||||
/datum/action/item_action/toggle_headphones
|
||||
name = "Toggle Headphones"
|
||||
|
||||
/datum/action/item_action/toggle_helmet_light
|
||||
name = "Toggle Helmet Light"
|
||||
|
||||
@@ -232,19 +229,6 @@
|
||||
button.name = name
|
||||
..()
|
||||
|
||||
/datum/action/item_action/synthswitch
|
||||
name = "Change Synthesizer Instrument"
|
||||
desc = "Change the type of instrument your synthesizer is playing as."
|
||||
|
||||
/datum/action/item_action/synthswitch/Trigger()
|
||||
if(istype(target, /obj/item/instrument/piano_synth))
|
||||
var/obj/item/instrument/piano_synth/synth = target
|
||||
var/chosen = input("Choose the type of instrument you want to use", "Instrument Selection", "piano") as null|anything in synth.insTypes
|
||||
if(!synth.insTypes[chosen])
|
||||
return
|
||||
return synth.changeInstrument(chosen)
|
||||
return ..()
|
||||
|
||||
/datum/action/item_action/vortex_recall
|
||||
name = "Vortex Recall"
|
||||
desc = "Recall yourself, and anyone nearby, to an attuned hierophant beacon at any time.<br>If the beacon is still attached, will detach it."
|
||||
@@ -257,6 +241,9 @@
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/datum/action/item_action/change_headphones_song
|
||||
name = "Change Headphones Song"
|
||||
|
||||
/datum/action/item_action/toggle
|
||||
|
||||
/datum/action/item_action/toggle/New(Target)
|
||||
@@ -463,6 +450,7 @@
|
||||
/datum/action/spell_action
|
||||
check_flags = 0
|
||||
background_icon_state = "bg_spell"
|
||||
var/recharge_text_color = "#FFFFFF"
|
||||
|
||||
/datum/action/spell_action/New(Target)
|
||||
..()
|
||||
@@ -500,6 +488,18 @@
|
||||
return spell.can_cast(owner)
|
||||
return 0
|
||||
|
||||
/datum/action/spell_action/UpdateButtonIcon()
|
||||
if(button && !(. = ..()))
|
||||
var/obj/effect/proc_holder/spell/S = target
|
||||
if(!istype(S))
|
||||
return
|
||||
var/progress = S.get_availability_percentage()
|
||||
var/col_val_high = 72 * progress + 128
|
||||
var/col_val_low = 200 * progress
|
||||
button.maptext = "<div style=\"font-size:6pt;color:[recharge_text_color];font:'Small Fonts';text-align:center;\" valign=\"bottom\">[round_down(progress * 100)]%</div>"
|
||||
button.color = rgb(col_val_high, col_val_low, col_val_low, col_val_high)
|
||||
else
|
||||
button.maptext = null
|
||||
/*
|
||||
/datum/action/spell_action/alien
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
if(!(flags & CALTROP_BYPASS_SHOES) && (H.shoes || feetCover))
|
||||
return
|
||||
|
||||
if((H.flying) || H.buckled)
|
||||
if(H.flying || H.floating || H.buckled)
|
||||
return
|
||||
|
||||
var/damage = rand(min_damage, max_damage)
|
||||
|
||||
@@ -47,23 +47,30 @@
|
||||
return
|
||||
if(!isturf(target))
|
||||
return
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
var/turf/source_turf = get_turf(I)
|
||||
var/turf/target_turf = target
|
||||
var/list/clickparams = params2list(params)
|
||||
var/x_offset = text2num(clickparams["icon-x"]) - 16
|
||||
var/y_offset = text2num(clickparams["icon-y"]) - 16
|
||||
var/x_offset
|
||||
var/y_offset
|
||||
if(target_turf != get_turf(I)) //Trying to stick it on a wall, don't move it to the actual wall or you can move the item through it. Instead set the pixels as appropriate
|
||||
var/target_direction = get_dir(source_turf, target_turf)//The direction we clicked
|
||||
// Snowflake diagonal handling
|
||||
if(target_direction in GLOB.diagonals)
|
||||
to_chat(user, "<span class='warning'>You cant reach [target_turf].</span>")
|
||||
return
|
||||
if(target_direction & EAST)
|
||||
x_offset += 32
|
||||
x_offset = 16
|
||||
y_offset = rand(-12, 12)
|
||||
else if(target_direction & WEST)
|
||||
x_offset -= 32
|
||||
if(target_direction & NORTH)
|
||||
y_offset += 32
|
||||
x_offset = -16
|
||||
y_offset = rand(-12, 12)
|
||||
else if(target_direction & NORTH)
|
||||
x_offset = rand(-12, 12)
|
||||
y_offset = 16
|
||||
else if(target_direction & SOUTH)
|
||||
y_offset -= 32
|
||||
x_offset = rand(-12, 12)
|
||||
y_offset = -16
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You stick [I] to [target_turf].</span>")
|
||||
I.pixel_x = x_offset
|
||||
I.pixel_y = y_offset
|
||||
|
||||
@@ -51,6 +51,6 @@
|
||||
Additionally calls the parent's `after_slip()` proc on the `victim`.
|
||||
*/
|
||||
/datum/component/slippery/proc/Slip(datum/source, mob/living/carbon/human/victim)
|
||||
if(istype(victim) && prob(slip_chance) && victim.slip(description, stun, weaken, slip_tiles, walking_is_safe, slip_always, slip_verb))
|
||||
if(istype(victim) && !victim.flying && prob(slip_chance) && victim.slip(description, stun, weaken, slip_tiles, walking_is_safe, slip_always, slip_verb))
|
||||
var/atom/movable/owner = parent
|
||||
owner.after_slip(victim)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/datum/component/spooky
|
||||
var/too_spooky = TRUE //will it spawn a new instrument?
|
||||
|
||||
/datum/component/spooky/Initialize()
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/spectral_attack)
|
||||
|
||||
/datum/component/spooky/proc/spectral_attack(datum/source, mob/living/carbon/C, mob/user)
|
||||
if(ishuman(user)) //this weapon wasn't meant for mortals.
|
||||
var/mob/living/carbon/human/U = user
|
||||
if(!istype(U.dna.species, /datum/species/skeleton))
|
||||
U.adjustStaminaLoss(35) //Extra Damage
|
||||
U.Jitter(35)
|
||||
U.stuttering = 20
|
||||
if(U.getStaminaLoss() > 95)
|
||||
to_chat(U, "<font color='red' size='4'><b>Your ears weren't meant for this spectral sound.</b></font>")
|
||||
spectral_change(U)
|
||||
return
|
||||
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(istype(H.dna.species, /datum/species/skeleton))
|
||||
return //undeads are unaffected by the spook-pocalypse.
|
||||
C.Jitter(35)
|
||||
C.stuttering = 20
|
||||
if(!istype(H.dna.species, /datum/species/diona) && !istype(H.dna.species, /datum/species/machine) && !istype(H.dna.species, /datum/species/slime) && !istype(H.dna.species, /datum/species/golem) && !istype(H.dna.species, /datum/species/plasmaman))
|
||||
C.adjustStaminaLoss(25) //boneless humanoids don't lose the will to live
|
||||
to_chat(C, "<font color='red' size='4'><B>DOOT</B></font>")
|
||||
spectral_change(H)
|
||||
|
||||
else //the sound will spook monkeys.
|
||||
C.Jitter(15)
|
||||
C.stuttering = 20
|
||||
|
||||
/datum/component/spooky/proc/spectral_change(mob/living/carbon/human/H, mob/user)
|
||||
if((H.getStaminaLoss() > 95) && (!istype(H.dna.species, /datum/species/diona) && !istype(H.dna.species, /datum/species/machine) && !istype(H.dna.species, /datum/species/slime) && !istype(H.dna.species, /datum/species/golem) && !istype(H.dna.species, /datum/species/plasmaman) && !istype(H.dna.species, /datum/species/skeleton)))
|
||||
H.Stun(20)
|
||||
H.set_species(/datum/species/skeleton)
|
||||
H.visible_message("<span class='warning'>[H] has given up on life as a mortal.</span>")
|
||||
var/T = get_turf(H)
|
||||
if(too_spooky)
|
||||
if(prob(30))
|
||||
new/obj/item/instrument/saxophone/spectral(T)
|
||||
else if(prob(30))
|
||||
new/obj/item/instrument/trumpet/spectral(T)
|
||||
else if(prob(30))
|
||||
new/obj/item/instrument/trombone/spectral(T)
|
||||
else
|
||||
to_chat(H, "<span class='boldwarning'>The spooky gods forgot to ship your instrument. Better luck next unlife.</span>")
|
||||
to_chat(H, "<span class='boldnotice'>You are the spooky skeleton!</span>")
|
||||
to_chat(H, "<span class='boldnotice'>A new life and identity has begun. Help your fellow skeletons into bringing out the spooky-pocalypse. You haven't forgotten your past life, and are still beholden to past loyalties.</span>")
|
||||
change_name(H) //time for a new name!
|
||||
|
||||
/datum/component/spooky/proc/change_name(mob/living/carbon/human/H)
|
||||
var/t = stripped_input(H, "Enter your new skeleton name", H.real_name, null, MAX_NAME_LEN)
|
||||
if(!t)
|
||||
t = "spooky skeleton"
|
||||
H.real_name = t
|
||||
H.name = t
|
||||
@@ -67,6 +67,14 @@
|
||||
var/obj/item/projectile/P = AM
|
||||
if(P.original != parent)
|
||||
return
|
||||
if(ismob(AM))
|
||||
var/mob/M = AM
|
||||
if(M.flying)
|
||||
return
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = M
|
||||
if(L.floating)
|
||||
return
|
||||
var/atom/current_parent = parent
|
||||
if(isturf(current_parent.loc))
|
||||
play_squeak()
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
W.plane = initial(W.plane)
|
||||
W.loc = affected_mob.loc
|
||||
W.dropped(affected_mob)
|
||||
if(isobj(affected_mob.loc))
|
||||
var/obj/O = affected_mob.loc
|
||||
O.force_eject_occupant()
|
||||
var/mob/living/new_mob = new new_form(affected_mob.loc)
|
||||
if(istype(new_mob))
|
||||
new_mob.a_intent = "harm"
|
||||
|
||||
@@ -191,6 +191,10 @@
|
||||
..()
|
||||
desc = "That's Definitely Not [M.real_name]."
|
||||
|
||||
/datum/dog_fashion/head/cone
|
||||
name = "REAL_NAME"
|
||||
desc = "Omnicone's Chosen Champion"
|
||||
|
||||
/datum/dog_fashion/back/hardsuit
|
||||
name = "Space Explorer REAL_NAME"
|
||||
desc = "That's one small step for a corgi. One giant yap for corgikind."
|
||||
@@ -200,3 +204,7 @@
|
||||
D.mutations.Add(BREATHLESS)
|
||||
D.atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
D.minbodytemp = 0
|
||||
|
||||
/datum/dog_fashion/head/fried_vox_empty
|
||||
name = "Colonel REAL_NAME"
|
||||
desc = "Keep away from live vox."
|
||||
|
||||
@@ -152,13 +152,11 @@
|
||||
return doTeleport()
|
||||
return 0
|
||||
|
||||
/datum/teleport/instant //teleports when datum is created
|
||||
|
||||
start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
|
||||
if(..())
|
||||
if(teleport())
|
||||
return 1
|
||||
return 0
|
||||
/datum/teleport/instant/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
|
||||
if(..())
|
||||
if(teleport())
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/datum/teleport/instant/science
|
||||
|
||||
+32
-13
@@ -3,32 +3,51 @@
|
||||
var/raw_time // When did this happen?
|
||||
var/what // What happened
|
||||
var/who // Who did it
|
||||
var/target // Who/what was targeted (can be a string)
|
||||
var/turf/where // Where did it happen
|
||||
var/target // Who/what was targeted
|
||||
var/where // Where did it happen
|
||||
|
||||
/datum/log_record/New(_log_type, _who, _what, _target, _where, _raw_time)
|
||||
log_type = _log_type
|
||||
|
||||
who = get_subject_text(_who)
|
||||
|
||||
who = get_subject_text(_who, _log_type)
|
||||
what = _what
|
||||
target = get_subject_text(_target)
|
||||
if(!_where)
|
||||
target = get_subject_text(_target, _log_type)
|
||||
if(!istext(_where) && !isturf(_where))
|
||||
_where = get_turf(_who)
|
||||
where = _where
|
||||
if(isturf(_where))
|
||||
var/turf/T = _where
|
||||
where = ADMIN_COORDJMP(T)
|
||||
else
|
||||
where = _where
|
||||
if(!_raw_time)
|
||||
_raw_time = world.time
|
||||
raw_time = _raw_time
|
||||
|
||||
/datum/log_record/proc/get_subject_text(subject)
|
||||
/datum/log_record/proc/get_subject_text(subject, log_type)
|
||||
if(ismob(subject) || isclient(subject) || istype(subject, /datum/mind))
|
||||
return key_name_admin(subject)
|
||||
if(isatom(subject))
|
||||
. = key_name_admin(subject)
|
||||
if(should_log_health(log_type) && isliving(subject))
|
||||
. += get_health_string(subject)
|
||||
else if(isatom(subject))
|
||||
var/atom/A = subject
|
||||
return A.name
|
||||
if(istype(subject, /datum))
|
||||
. = A.name
|
||||
else if(istype(subject, /datum))
|
||||
var/datum/D = subject
|
||||
return D.type
|
||||
return subject
|
||||
else
|
||||
. = subject
|
||||
|
||||
/datum/log_record/proc/get_health_string(var/mob/living/L)
|
||||
var/OX = L.getOxyLoss() > 50 ? "<b>[L.getOxyLoss()]</b>" : L.getOxyLoss()
|
||||
var/TX = L.getToxLoss() > 50 ? "<b>[L.getToxLoss()]</b>" : L.getToxLoss()
|
||||
var/BU = L.getFireLoss() > 50 ? "<b>[L.getFireLoss()]</b>" : L.getFireLoss()
|
||||
var/BR = L.getBruteLoss() > 50 ? "<b>[L.getBruteLoss()]</b>" : L.getBruteLoss()
|
||||
return " ([L.health]: <font color='deepskyblue'>[OX]</font> - <font color='green'>[TX]</font> - <font color='#FFA500'>[BU]</font> - <font color='red'>[BR]</font>)"
|
||||
|
||||
/datum/log_record/proc/should_log_health(log_type)
|
||||
if(log_type == ATTACK_LOG || log_type == DEFENSE_LOG)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/proc/compare_log_record(datum/log_record/A, datum/log_record/B)
|
||||
var/time_diff = A.raw_time - B.raw_time
|
||||
|
||||
+108
-24
@@ -1,31 +1,45 @@
|
||||
#define ALL_LOGS list(ATTACK_LOG, DEFENSE_LOG, CONVERSION_LOG, SAY_LOG, EMOTE_LOG, MISC_LOG)
|
||||
#define UPDATE_CKEY_MOB(__ckey) var/mob/result = selected_ckeys_mobs[__ckey];\
|
||||
if(!result || result.ckey != __ckey){\
|
||||
result = get_mob_by_ckey(__ckey);\
|
||||
selected_ckeys_mobs[__ckey] = result;\
|
||||
}
|
||||
|
||||
#define RECORD_WARN_LIMIT 1000
|
||||
#define RECORD_HARD_LIMIT 2500
|
||||
|
||||
/datum/log_viewer
|
||||
var/time_from = 0
|
||||
var/time_to = 4 HOURS // 4 Hours should be enough. INFINITY would screw the UI up
|
||||
var/list/selected_mobs = list() // The mobs in question
|
||||
var/list/selected_log_types = list() // The log types being searched for
|
||||
|
||||
var/list/selected_mobs = list() // The mobs in question.
|
||||
var/list/selected_ckeys = list() // The ckeys selected to search for. Will show all mobs the ckey is attached to
|
||||
var/list/mob/selected_ckeys_mobs = list()
|
||||
var/list/selected_log_types = ALL_LOGS // The log types being searched for
|
||||
var/list/log_records = list() // Found and sorted records
|
||||
|
||||
/datum/log_viewer/proc/clear_all()
|
||||
selected_mobs.Cut()
|
||||
selected_log_types.Cut()
|
||||
selected_log_types = ALL_LOGS
|
||||
selected_ckeys.Cut()
|
||||
selected_ckeys_mobs.Cut()
|
||||
time_from = initial(time_from)
|
||||
time_to = initial(time_to)
|
||||
log_records.Cut()
|
||||
return
|
||||
|
||||
/datum/log_viewer/proc/search()
|
||||
/datum/log_viewer/proc/search(user)
|
||||
log_records.Cut() // Empty the old results
|
||||
var/list/invalid_mobs = list()
|
||||
var/list/ckeys = selected_ckeys.Copy()
|
||||
for(var/i in selected_mobs)
|
||||
var/mob/M = i
|
||||
if(!M || QDELETED(M))
|
||||
if(!M || QDELETED(M) || !M.last_known_ckey)
|
||||
invalid_mobs |= M
|
||||
continue
|
||||
ckeys |= M.last_known_ckey
|
||||
|
||||
for(var/ckey in ckeys)
|
||||
for(var/log_type in selected_log_types)
|
||||
var/list/logs = M.logs[log_type]
|
||||
var/list/logs = GLOB.logging.get_logs_by_type(ckey, log_type)
|
||||
var/len_logs = length(logs)
|
||||
if(len_logs)
|
||||
var/start_index = get_earliest_log_index(logs)
|
||||
@@ -36,8 +50,8 @@
|
||||
continue
|
||||
log_records.Add(logs.Copy(start_index, end_index + 1))
|
||||
|
||||
if(invalid_mobs.len)
|
||||
to_chat(usr, "<span class='warning'>The search criteria contained invalid mobs. They have been removed from the criteria.</span>")
|
||||
if(length(invalid_mobs))
|
||||
to_chat(user, "<span class='warning'>The search criteria contained invalid mobs. They have been removed from the criteria.</span>")
|
||||
for(var/i in invalid_mobs)
|
||||
selected_mobs -= i // Cleanup
|
||||
|
||||
@@ -91,9 +105,23 @@
|
||||
return start
|
||||
return 0
|
||||
|
||||
/datum/log_viewer/proc/add_mob(mob/user, mob/M)
|
||||
/datum/log_viewer/proc/add_mobs(list/mob/mobs)
|
||||
if(!length(mobs))
|
||||
return
|
||||
for(var/i in mobs)
|
||||
add_mob(usr, i, FALSE)
|
||||
|
||||
/datum/log_viewer/proc/add_ckey(mob/user, ckey)
|
||||
if(!user || !ckey)
|
||||
return
|
||||
selected_ckeys |= ckey
|
||||
UPDATE_CKEY_MOB(ckey)
|
||||
show_ui(user)
|
||||
|
||||
/datum/log_viewer/proc/add_mob(mob/user, mob/M, show_the_ui = TRUE)
|
||||
if(!M || !user)
|
||||
return
|
||||
|
||||
selected_mobs |= M
|
||||
|
||||
show_ui(user)
|
||||
@@ -102,9 +130,9 @@
|
||||
var/all_log_types = ALL_LOGS
|
||||
var/trStyleTop = "border-top:2px solid; border-bottom:2px solid; padding-top: 5px; padding-bottom: 5px;"
|
||||
var/trStyle = "border-top:1px solid; border-bottom:1px solid; padding-top: 5px; padding-bottom: 5px;"
|
||||
var/dat
|
||||
dat += "<head><style>.adminticket{border:2px solid} td{border:1px solid grey;} th{border:1px solid grey;} span{float:left;width:150px;}</style></head>"
|
||||
dat += "<div style='height:15vh'>"
|
||||
var/list/dat = list()
|
||||
dat += "<head><meta http-equiv='X-UA-Compatible' content='IE=edge'><style>.adminticket{border:2px solid} td{border:1px solid grey;} th{border:1px solid grey;} span{float:left;width:150px;}</style></head>"
|
||||
dat += "<div style='min-height:100px'>"
|
||||
dat += "<span>Time Search Range:</span> <a href='?src=[UID()];start_time=1'>[gameTimestamp(wtime = time_from)]</a>"
|
||||
dat += " To: <a href='?src=[UID()];end_time=1'>[gameTimestamp(wtime = time_to)]</a>"
|
||||
dat += "<BR>"
|
||||
@@ -115,20 +143,26 @@
|
||||
if(QDELETED(M))
|
||||
selected_mobs -= i
|
||||
continue
|
||||
dat += "<a href='?src=[UID()];remove_mob=\ref[M]'>[M.name]</a>"
|
||||
dat += "<a href='?src=[UID()];remove_mob=\ref[M]'>[get_display_name(M)]</a>"
|
||||
dat += "<a href='?src=[UID()];add_mob=1'>Add Mob</a>"
|
||||
dat += "<a href='?src=[UID()];clear_mobs=1'>Clear All Mobs</a>"
|
||||
dat += "<BR>"
|
||||
|
||||
dat += "<span>Ckeys being used:</span>"
|
||||
for(var/ckey in selected_ckeys)
|
||||
dat += "<a href='?src=[UID()];remove_ckey=[ckey]'>[get_ckey_name(ckey)]</a>"
|
||||
dat += "<a href='?src=[UID()];add_ckey=1'>Add ckey</a>"
|
||||
dat += "<a href='?src=[UID()];clear_ckeys=1'>Clear All ckeys</a>"
|
||||
dat += "<BR>"
|
||||
|
||||
dat += "<span>Log Types:</span>"
|
||||
for(var/i in all_log_types)
|
||||
var/log_type = i
|
||||
for(var/log_type in all_log_types)
|
||||
var/enabled = (log_type in selected_log_types)
|
||||
var/text
|
||||
var/style
|
||||
if(enabled)
|
||||
text = "<b>[log_type]</b>"
|
||||
style = "background: [get_logtype_color(i)]"
|
||||
style = "background: [get_logtype_color(log_type)]"
|
||||
else
|
||||
text = log_type
|
||||
|
||||
@@ -142,9 +176,9 @@
|
||||
// Search results
|
||||
var/tdStyleTime = "width:80px; text-align:center;"
|
||||
var/tdStyleType = "width:80px; text-align:center;"
|
||||
var/tdStyleWho = "width:300px; text-align:center;"
|
||||
var/tdStyleWho = "width:400px; text-align:center;"
|
||||
var/tdStyleWhere = "width:150px; text-align:center;"
|
||||
dat += "<div style='overflow-y: auto; max-height:76vh;'>"
|
||||
dat += "<div style='overflow-y: auto; max-height:calc(100vh - 150px);'>"
|
||||
dat += "<table style='width:100%; border: 1px solid;'>"
|
||||
dat += "<tr style='[trStyleTop]'><th style='[tdStyleTime]'>When</th><th style='[tdStyleType]'>Type</th><th style='[tdStyleWho]'>Who</th><th>What</th><th>Target</th><th style='[tdStyleWhere]'>Where</th></tr>"
|
||||
for(var/i in log_records)
|
||||
@@ -153,13 +187,12 @@
|
||||
|
||||
dat +="<tr style='[trStyle]'><td style='[tdStyleTime]'>[time]</td><td style='[tdStyleType]background: [get_logtype_color(L.log_type)]'>[L.log_type]</td>\
|
||||
<td style='[tdStyleWho]'>[L.who]</td><td style='background: [get_logtype_color(L.log_type)];'>[L.what]</td>\
|
||||
<td style='[tdStyleWho]'>[L.target]</td><td style='[tdStyleWhere]'>[ADMIN_COORDJMP(L.where)]</td></tr>"
|
||||
|
||||
<td style='[tdStyleWho]'>[L.target]</td><td style='[tdStyleWhere]'>[L.where]</td></tr>"
|
||||
dat += "</table>"
|
||||
dat += "</div>"
|
||||
|
||||
var/datum/browser/popup = new(user, "Log viewer", "Log viewer", 1400, 600)
|
||||
popup.set_content(dat)
|
||||
var/datum/browser/popup = new(user, "Log Viewer", "Log Viewer", 1500, 600)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open()
|
||||
|
||||
/datum/log_viewer/Topic(href, href_list)
|
||||
@@ -188,6 +221,19 @@
|
||||
return
|
||||
if(href_list["search"])
|
||||
search(usr)
|
||||
var/records_len = length(log_records)
|
||||
if(records_len > RECORD_WARN_LIMIT)
|
||||
var/datum/log_record/last_record = log_records[RECORD_WARN_LIMIT]
|
||||
var/last_time = gameTimestamp(wtime = last_record.raw_time - 9.99)
|
||||
var/answer = alert(usr, "More than [RECORD_WARN_LIMIT] records were found. continuing will take a long time. This won't cause much lag for the server. Time at the [RECORD_WARN_LIMIT]th record '[last_time]'", "Warning", "Continue", "Limit to [RECORD_WARN_LIMIT]", "Cancel")
|
||||
if(answer == "Limit to [RECORD_WARN_LIMIT]")
|
||||
log_records.Cut(RECORD_WARN_LIMIT)
|
||||
else if(answer == "Cancel")
|
||||
log_records.Cut()
|
||||
else
|
||||
if(records_len > RECORD_HARD_LIMIT)
|
||||
to_chat(usr, "<span class='warning'>Record limit reached. Limiting to [RECORD_HARD_LIMIT].</span>")
|
||||
log_records.Cut(RECORD_HARD_LIMIT)
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["clear_all"])
|
||||
@@ -198,17 +244,31 @@
|
||||
selected_mobs.Cut()
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["clear_ckeys"])
|
||||
selected_ckeys.Cut()
|
||||
selected_ckeys_mobs.Cut()
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["add_mob"])
|
||||
var/list/mobs = getpois(TRUE, TRUE)
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a mob: ", mobs)
|
||||
A.on_close(CALLBACK(src, .proc/add_mob, usr))
|
||||
return
|
||||
if(href_list["add_ckey"])
|
||||
var/list/ckeys = GLOB.logging.get_ckeys_logged()
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a ckey: ", ckeys)
|
||||
A.on_close(CALLBACK(src, .proc/add_ckey, usr))
|
||||
return
|
||||
if(href_list["remove_mob"])
|
||||
var/mob/M = locate(href_list["remove_mob"])
|
||||
if(M)
|
||||
selected_mobs -= M
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["remove_ckey"])
|
||||
selected_ckeys -= href_list["remove_ckey"]
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["toggle_log_type"])
|
||||
var/log_type = href_list["toggle_log_type"]
|
||||
if(log_type in selected_log_types)
|
||||
@@ -232,4 +292,28 @@
|
||||
return "deepskyblue"
|
||||
if(MISC_LOG)
|
||||
return "gray"
|
||||
if(DEADCHAT_LOG)
|
||||
return "#cc00c6"
|
||||
if(OOC_LOG)
|
||||
return "#002eb8"
|
||||
if(LOOC_LOG)
|
||||
return "#6699CC"
|
||||
return "slategray"
|
||||
|
||||
/datum/log_viewer/proc/get_display_name(mob/M)
|
||||
var/name = M.name
|
||||
if(M.name != M.real_name)
|
||||
name = "[name] ([M.real_name])"
|
||||
if(isobserver(M))
|
||||
name = "[name] (DEAD)"
|
||||
return "\[[M.last_known_ckey]\] [name]"
|
||||
|
||||
/datum/log_viewer/proc/get_ckey_name(ckey)
|
||||
UPDATE_CKEY_MOB(ckey)
|
||||
var/mob/M = selected_ckeys_mobs[ckey]
|
||||
|
||||
return get_display_name(M)
|
||||
|
||||
#undef UPDATE_CKEY_MOB
|
||||
#undef RECORD_WARN_LIMIT
|
||||
#undef RECORD_HARD_LIMIT
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/datum/logging
|
||||
var/list/datum/log_record/logs = list() // Assoc list of assoc lists (ckey, (log_type, list/logs))
|
||||
|
||||
/datum/logging/proc/add_log(ckey, datum/log_record/log)
|
||||
if(!ckey)
|
||||
log_debug("GLOB.logging.add_log called with an invalid ckey")
|
||||
return
|
||||
|
||||
if(!logs[ckey])
|
||||
logs[ckey] = list()
|
||||
|
||||
var/list/log_types_list = logs[ckey]
|
||||
|
||||
if(!log_types_list[log.log_type])
|
||||
log_types_list[log.log_type] = list()
|
||||
|
||||
var/list/datum/log_record/log_records = log_types_list[log.log_type]
|
||||
log_records.Add(log)
|
||||
|
||||
/datum/logging/proc/get_ckeys_logged()
|
||||
var/list/ckeys = list()
|
||||
for(var/ckey in logs)
|
||||
ckeys.Add(ckey)
|
||||
return ckeys
|
||||
|
||||
/* Returns the logs of a given ckey and log_type
|
||||
* If no logs exist it will return an empty list
|
||||
*/
|
||||
/datum/logging/proc/get_logs_by_type(ckey, log_type)
|
||||
if(!ckey)
|
||||
log_debug("GLOB.logging.get_logs_by_type called with an invalid ckey")
|
||||
return
|
||||
if(!log_type || !(log_type in ALL_LOGS))
|
||||
log_debug("GLOB.logging.get_logs_by_type called with an invalid log_type '[log_type]'")
|
||||
return
|
||||
|
||||
var/list/log_types_list = logs[ckey]
|
||||
// Check if logs exist for the ckey
|
||||
if(!length(log_types_list))
|
||||
return list()
|
||||
|
||||
var/list/datum/log_record/log_records = log_types_list[log_type]
|
||||
|
||||
// Check if logs exist for this type
|
||||
if(!log_records)
|
||||
return list()
|
||||
return log_records
|
||||
@@ -71,7 +71,7 @@
|
||||
var/list/atoms_cache = output_atoms
|
||||
var/sound/S = sound(soundfile)
|
||||
if(direct)
|
||||
S.channel = open_sound_channel()
|
||||
S.channel = SSsounds.random_available_channel()
|
||||
S.volume = volume
|
||||
for(var/i in 1 to atoms_cache.len)
|
||||
var/atom/thing = atoms_cache[i]
|
||||
|
||||
+6
-13
@@ -100,14 +100,6 @@
|
||||
current.mind = null
|
||||
leave_all_huds() //leave all the huds in the old body, so it won't get huds if somebody else enters it
|
||||
|
||||
for(var/log_type in current.logs) // Copy the old logs
|
||||
var/list/logs = current.logs[log_type]
|
||||
if(new_character.logs[log_type])
|
||||
new_character.logs[log_type] += logs.Copy() // Append the old ones
|
||||
new_character.logs[log_type] = sortTim(new_character.logs[log_type], /proc/compare_log_record) // Sort them on time
|
||||
else
|
||||
new_character.logs[log_type] = logs.Copy() // Just copy them
|
||||
|
||||
SSnanoui.user_transferred(current, new_character)
|
||||
|
||||
if(new_character.mind) //remove any mind currently in our new body's mind variable
|
||||
@@ -922,7 +914,7 @@
|
||||
log_admin("[key_name(usr)] has equipped [key_name(current)] as a wizard")
|
||||
message_admins("[key_name_admin(usr)] has equipped [key_name_admin(current)] as a wizard")
|
||||
if("name")
|
||||
SSticker.mode.name_wizard(current)
|
||||
INVOKE_ASYNC(SSticker.mode, /datum/game_mode/wizard.proc/name_wizard, current)
|
||||
log_admin("[key_name(usr)] has allowed wizard [key_name(current)] to name themselves")
|
||||
message_admins("[key_name_admin(usr)] has allowed wizard [key_name_admin(current)] to name themselves")
|
||||
if("autoobjectives")
|
||||
@@ -1419,9 +1411,10 @@
|
||||
return A
|
||||
|
||||
/datum/mind/proc/announce_objectives()
|
||||
to_chat(current, "<span class='notice'>Your current objectives:</span>")
|
||||
for(var/line in splittext(gen_objective_text(), "<br>"))
|
||||
to_chat(current, line)
|
||||
if(current)
|
||||
to_chat(current, "<span class='notice'>Your current objectives:</span>")
|
||||
for(var/line in splittext(gen_objective_text(), "<br>"))
|
||||
to_chat(current, line)
|
||||
|
||||
/datum/mind/proc/find_syndicate_uplink()
|
||||
var/list/L = current.get_contents()
|
||||
@@ -1508,7 +1501,7 @@
|
||||
SSticker.mode.equip_wizard(current)
|
||||
for(var/obj/item/spellbook/S in current.contents)
|
||||
S.op = 0
|
||||
SSticker.mode.name_wizard(current)
|
||||
INVOKE_ASYNC(SSticker.mode, /datum/game_mode/wizard.proc/name_wizard, current)
|
||||
SSticker.mode.forge_wizard_objectives(src)
|
||||
SSticker.mode.greet_wizard(src)
|
||||
SSticker.mode.update_wiz_icons_added(src)
|
||||
|
||||
@@ -222,10 +222,10 @@
|
||||
name = "NT Undercover Operative"
|
||||
// Disguised NT special forces, sent to quietly eliminate or keep tabs on people in high positions (e.g: captain)
|
||||
|
||||
uniform = /obj/item/clothing/under/color/black
|
||||
uniform = /obj/item/clothing/under/color/random
|
||||
back = /obj/item/storage/backpack
|
||||
belt = /obj/item/storage/belt/utility/full/multitool
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
gloves = /obj/item/clothing/gloves/color/yellow
|
||||
shoes = /obj/item/clothing/shoes/chameleon/noslip
|
||||
l_ear = /obj/item/radio/headset/centcom
|
||||
id = /obj/item/card/id
|
||||
|
||||
@@ -351,16 +351,6 @@ GLOBAL_LIST_EMPTY(rpd_pipe_list) //Some pipes we don't want to be dispensable
|
||||
pipe_id = PIPE_CIRCULATOR
|
||||
pipe_icon = "circ"
|
||||
|
||||
/datum/pipes/atmospheric/omni_filter
|
||||
pipe_name = "omni filter"
|
||||
pipe_id = PIPE_OMNI_FILTER
|
||||
pipe_icon = "omni_filter"
|
||||
|
||||
/datum/pipes/atmospheric/omni_mixer
|
||||
pipe_name = "omni mixer"
|
||||
pipe_id = PIPE_OMNI_MIXER
|
||||
pipe_icon = "omni_mixer"
|
||||
|
||||
/datum/pipes/atmospheric/insulated
|
||||
pipe_name = "insulated pipe"
|
||||
pipe_id = PIPE_INSULATED_STRAIGHT
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
name = "Biodome Winter"
|
||||
id = "biodome-winter"
|
||||
description = "For those getaways where you want to get back to nature, but you don't want to leave the fortified military compound where you spend your days. \
|
||||
Includes a unique(*) laser pistol display case, and the recently introduced I.C.E(tm)."
|
||||
Includes the recently introduced I.C.E(tm)."
|
||||
suffix = "lavaland_biodome_winter.dmm"
|
||||
|
||||
/datum/map_template/ruin/lavaland/biodome/clown
|
||||
@@ -42,7 +42,7 @@
|
||||
cost = 10
|
||||
allow_duplicates = FALSE
|
||||
|
||||
datum/map_template/ruin/lavaland/ash_walker
|
||||
/datum/map_template/ruin/lavaland/ash_walker
|
||||
name = "Ash Walker Nest"
|
||||
id = "ash-walker"
|
||||
description = "A race of unbreathing lizards live here, that run faster than a human can, worship a broken dead city, and are capable of reproducing by something involving tentacles? \
|
||||
|
||||
@@ -248,3 +248,29 @@
|
||||
allow_duplicates = FALSE // I dont even want to think about what happens if you have 2 shuttles with the same ID. Likely scary stuff.
|
||||
always_place = TRUE // Its designed to make exploring other space ruins more accessible
|
||||
cost = 0 // Force spawned so shouldnt have a cost
|
||||
|
||||
/datum/map_template/ruin/space/syndiecakesfactory
|
||||
id = "Syndiecakes Factory"
|
||||
suffix = "syndiecakesfactory.dmm"
|
||||
name = "Syndicakes Factory"
|
||||
description = "Syndicate used to get funds selling corgi cakes produced here. Was it hit by meteors or by a Nanotrasen comando?"
|
||||
allow_duplicates = FALSE
|
||||
cost = 2 //telecomms + multiple mobs
|
||||
|
||||
/datum/map_template/ruin/space/debris1
|
||||
id = "debris1"
|
||||
suffix = "debris1.dmm"
|
||||
name = "Debris field 1"
|
||||
description = "A bunch of metal chunks, wires and space waste"
|
||||
|
||||
/datum/map_template/ruin/space/debris2
|
||||
id = "debris2"
|
||||
suffix = "debris2.dmm"
|
||||
name = "Debris field 2"
|
||||
description = "A bunch of metal chunks, wires and space waste that used to be some kind of secure storage facility"
|
||||
|
||||
/datum/map_template/ruin/space/debris3
|
||||
id = "debris3"
|
||||
suffix = "debris3.dmm"
|
||||
name = "Debris field 3"
|
||||
description = "A bunch of metal chunks, wires and space waste. It used to be an arcade."
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
var/admin_notes
|
||||
|
||||
/datum/map_template/shuttle/New()
|
||||
shuttle_id = "[port_id]_[suffix]"
|
||||
mappath = "[prefix][shuttle_id].dmm"
|
||||
if(port_id && suffix)
|
||||
shuttle_id = "[port_id]_[suffix]"
|
||||
mappath = "[prefix][shuttle_id].dmm"
|
||||
. = ..()
|
||||
|
||||
/datum/map_template/shuttle/emergency
|
||||
@@ -132,3 +133,8 @@
|
||||
suffix = "admin"
|
||||
name = "NTV Argos"
|
||||
description = "Default Admin ship. An older ship used for special operations."
|
||||
|
||||
/datum/map_template/shuttle/admin/armory
|
||||
suffix = "armory"
|
||||
name = "NRV Sparta"
|
||||
description = "Armory Shuttle, with plenty of guns to hand out and some general supplies."
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user