Merge remote-tracking branch 'ParadiseSS13/master' into pr/TDSSS/14074

This commit is contained in:
AffectedArc07
2020-09-15 18:40:32 +01:00
797 changed files with 23924 additions and 10603 deletions
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
},
@@ -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
"}
@@ -99,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,
@@ -922,7 +928,7 @@ b
f
f
f
c
f
f
D
m
@@ -964,7 +970,7 @@ f
f
p
Y
f
u
f
j
i
File diff suppressed because it is too large Load Diff
@@ -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" = (
+7 -3
View File
@@ -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"
},
File diff suppressed because it is too large Load Diff
@@ -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()
+6
View File
@@ -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
+4
View File
@@ -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"
+29
View File
@@ -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
+1
View File
@@ -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
+5
View File
@@ -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)
+5
View File
@@ -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
View File
@@ -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)
+1
View File
@@ -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
View File
@@ -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
+8 -8
View File
@@ -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_SERVER_MAINT 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)
@@ -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.
+8
View File
@@ -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
+77
View File
@@ -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
View File
@@ -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
+3 -3
View File
@@ -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)
-2
View File
@@ -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, ""))
-10
View File
@@ -1919,16 +1919,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return pois
/*
* Returns all player mobs in an assoc list with ckey as key and the mob as value
*/
/proc/get_assoc_mob_list_by_ckey()
var/list/mob/mobs = list()
for(var/i in GLOB.player_list)
var/mob/M = i
mobs[M.ckey] = M
return mobs
/proc/flash_color(mob_or_client, flash_color="#960000", flash_time=20)
var/client/C
if(istype(mob_or_client, /mob))
+4 -1
View File
@@ -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.
+2
View File
@@ -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"))
+67 -57
View File
@@ -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,86 @@
/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()
// 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))
+1 -1
View File
@@ -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
View File
@@ -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"
+3
View File
@@ -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
+3 -3
View File
@@ -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"
+28 -28
View File
@@ -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)
-67
View File
@@ -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
+275
View File
@@ -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)
+22 -1
View File
@@ -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()
@@ -644,6 +644,27 @@ 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)")
/datum/controller/subsystem/jobs/proc/fetch_transfer_record_html(var/centcom)
var/record_html = "<TABLE border=\"1\">"
@@ -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]"]
+3 -3
View File
@@ -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
+165
View File
@@ -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
+3 -3
View File
@@ -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)
+50 -10
View File
@@ -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]
@@ -158,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]
@@ -353,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 />"
@@ -368,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)
@@ -450,7 +487,6 @@ UI STUFF
if(closeTicket(indexNum))
showDetailUI(usr, indexNum)
if(href_list["detailreopen"])
var/indexNum = text2num(href_list["detailreopen"])
if(openTicket(indexNum))
@@ -470,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()
+4 -6
View File
@@ -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")
+3 -16
View File
@@ -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)
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+58
View File
@@ -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
+8
View File
@@ -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()
+8 -4
View File
@@ -3,8 +3,8 @@
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
@@ -12,9 +12,13 @@
who = get_subject_text(_who, _log_type)
what = _what
target = get_subject_text(_target, _log_type)
if(!_where)
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
+90 -28
View File
@@ -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_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 = 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
@@ -92,16 +106,22 @@
return 0
/datum/log_viewer/proc/add_mobs(list/mob/mobs)
if(!mobs?.len)
if(!length(mobs))
return
for(var/i in mobs)
var/mob/M = i
if(istype(M))
selected_mobs |= M
add_mob(usr, i, FALSE)
/datum/log_viewer/proc/add_mob(mob/user, mob/M)
/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)
@@ -110,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
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:95px'>"
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>"
@@ -125,19 +145,24 @@
continue
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()];add_mob_ckey=1'>Add Mob (by ckey)</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
@@ -153,7 +178,7 @@
var/tdStyleType = "width:80px; 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:calc(100vh - 145px);'>"
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)
@@ -162,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", 1500, 600)
popup.set_content(dat)
popup.set_content(dat.Join())
popup.open()
/datum/log_viewer/Topic(href, href_list)
@@ -197,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"])
@@ -207,15 +244,20 @@
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_mob_ckey"])
var/list/mobs = get_assoc_mob_list_by_ckey()
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a ckey: ", mobs)
A.on_close(CALLBACK(src, .proc/add_mob, usr))
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"])
@@ -223,6 +265,10 @@
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)
@@ -246,6 +292,12 @@
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)
@@ -254,4 +306,14 @@
name = "[name] ([M.real_name])"
if(isobserver(M))
name = "[name] (DEAD)"
return name
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
+47
View File
@@ -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
+1 -1
View File
@@ -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]
-8
View File
@@ -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
+2 -2
View File
@@ -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
+26
View File
@@ -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."
+5
View File
@@ -133,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."
+5
View File
@@ -444,6 +444,11 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
return
// Normally, AoE spells will generate an attack log for every turf they loop over, while searching for targets.
// With this override, all /aoe_turf type spells will only generate 1 log, saying that the user has cast the spell.
/obj/effect/proc_holder/spell/aoe_turf/perform(list/targets, recharge, mob/user, make_attack_logs)
add_attack_logs(user, null, "Cast the AoE spell [name]", ATKLOG_ALL)
return ..(targets, recharge, user, FALSE)
/obj/effect/proc_holder/spell/targeted/proc/los_check(mob/A,mob/B)
//Checks for obstacles from A to B
-5
View File
@@ -13,11 +13,6 @@
action_icon_state = "knock"
sound = 'sound/magic/knock.ogg'
// Knock doesn't need to generate an attack log for every turf, set `make_attack_logs` to FALSE and just create a custom one.
/obj/effect/proc_holder/spell/aoe_turf/knock/perform(list/targets, recharge, mob/user)
add_attack_logs(user, user, "cast the spell [name]", ATKLOG_ALL)
return ..(targets, recharge, user, make_attack_logs = FALSE)
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
+2 -3
View File
@@ -1173,11 +1173,10 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
containername = "fox crate"
/datum/supply_packs/organic/butterfly
name = "Butterflies Crate"
name = "Butterfly Crate"
cost = 50
containertype = /obj/structure/closet/critter/butterfly
containername = "butterflies crate"
contraband = 1
containername = "butterfly crate"
/datum/supply_packs/organic/deer
name = "Deer Crate"
+10 -2
View File
@@ -736,6 +736,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 12 // normally 18
gamemodes = list(/datum/game_mode/nuclear)
/datum/uplink_item/ammo/bulldog_XLmagsbag
name = "Bulldog - 12g XL Magazine Duffel Bag"
desc = "A duffel bag containing three 16 round drum magazines(Slug, Buckshot, Dragon's Breath)."
reference = "12XLDB"
item = /obj/item/storage/backpack/duffel/syndie/ammo/shotgunXLmags
cost = 12 // normally 18
gamemodes = list(/datum/game_mode/nuclear)
/datum/uplink_item/ammo/smg
name = "C-20r - .45 Magazine"
desc = "An additional 20-round .45 magazine for use in the C-20r submachine gun. These bullets pack a lot of punch that can knock most targets down, but do limited overall damage."
@@ -1725,8 +1733,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
U.purchase_log += "<BIG>[bicon(C)]</BIG>"
for(var/item in bought_items)
new item(C)
U.purchase_log += "<BIG>[bicon(item)]</BIG>"
var/obj/purchased = new item(C)
U.purchase_log += "<BIG>[bicon(purchased)]</BIG>"
log_game("[key_name(usr)] purchased a surplus crate with [jointext(itemlog, ", ")]")
/datum/uplink_item/bundles_TC/telecrystal
@@ -35,6 +35,8 @@
return
if(!L.client) //Only sentient people are going along with it!
return
if(L.flying)
return
L.adjustFireLoss(3)
/datum/weather/floor_is_lava/fake
+76 -119
View File
@@ -1,67 +1,29 @@
// Wires for airlocks
/datum/wires/airlock/secure
random = 1
randomize = TRUE
/datum/wires/airlock
holder_type = /obj/machinery/door/airlock
wire_count = 12
window_x = 410
window_y = 570
wire_count = 12 // 10 actual, 2 duds.
proper_name = "Airlock"
window_x = 400
window_y = 101
#define AIRLOCK_WIRE_IDSCAN 1
#define AIRLOCK_WIRE_MAIN_POWER1 2
#define AIRLOCK_WIRE_DOOR_BOLTS 4
#define AIRLOCK_WIRE_BACKUP_POWER1 8
#define AIRLOCK_WIRE_OPEN_DOOR 16
#define AIRLOCK_WIRE_AI_CONTROL 32
#define AIRLOCK_WIRE_ELECTRIFY 64
#define AIRLOCK_WIRE_SAFETY 128
#define AIRLOCK_WIRE_SPEED 256
#define AIRLOCK_WIRE_LIGHT 512
/datum/wires/airlock/New(atom/_holder)
wires = list(
WIRE_IDSCAN, WIRE_MAIN_POWER1, WIRE_DOOR_BOLTS, WIRE_BACKUP_POWER1, WIRE_OPEN_DOOR,
WIRE_AI_CONTROL, WIRE_ELECTRIFY, WIRE_SAFETY, WIRE_SPEED, WIRE_BOLT_LIGHT
)
return ..()
/datum/wires/airlock/GetWireName(index)
switch(index)
if(AIRLOCK_WIRE_IDSCAN)
return "ID Scan"
if(AIRLOCK_WIRE_MAIN_POWER1)
return "Primary Power"
if(AIRLOCK_WIRE_DOOR_BOLTS)
return "Door Bolts"
if(AIRLOCK_WIRE_BACKUP_POWER1)
return "Primary Backup Power"
if(AIRLOCK_WIRE_OPEN_DOOR)
return "Door State"
if(AIRLOCK_WIRE_AI_CONTROL)
return "AI Control"
if(AIRLOCK_WIRE_ELECTRIFY)
return "Electrification"
if(AIRLOCK_WIRE_ELECTRIFY)
return "Door Safeties"
if(AIRLOCK_WIRE_ELECTRIFY)
return "Door Timing"
if(AIRLOCK_WIRE_ELECTRIFY)
return "Bolt Lights"
/datum/wires/airlock/CanUse(mob/living/L)
/datum/wires/airlock/interactable(mob/user)
var/obj/machinery/door/airlock/A = holder
if(iscarbon(L))
if(A.Adjacent(L))
if(A.isElectrified())
if(A.shock(L, 100))
return 0
if(iscarbon(user) && A.Adjacent(user) && A.isElectrified() && A.shock(user, 100))
return FALSE
if(A.panel_open)
return 1
return 0
return TRUE
return FALSE
/datum/wires/airlock/get_status()
. = ..()
@@ -70,21 +32,20 @@
. += "The door bolts [A.locked ? "have fallen!" : "look up."]"
. += "The door bolt lights are [(A.lights && haspower) ? "on." : "off!"]"
. += "The test light is [haspower ? "on." : "off!"]"
. += "The 'AI control allowed' light is [(A.aiControlDisabled == 0 && !A.emagged && haspower) ? "on" : "off"]."
. += "The test light is [haspower ? "on." : "off!"]"
. += "The 'AI control allowed' light is [(A.aiControlDisabled == AICONTROLDISABLED_OFF && !A.emagged && haspower) ? "on" : "off"]."
. += "The 'Check Wiring' light is [(A.safe == 0 && haspower) ? "on" : "off"]."
. += "The 'Check Timing Mechanism' light is [(A.normalspeed == 0 && haspower) ? "on" : "off"]."
. += "The emergency lights are [(A.emergency && haspower) ? "on" : "off"]."
/datum/wires/airlock/UpdateCut(index, mended)
/datum/wires/airlock/on_cut(wire, mend)
var/obj/machinery/door/airlock/A = holder
switch(index)
if(AIRLOCK_WIRE_IDSCAN)
A.aiDisabledIdScanner = !mended
if(AIRLOCK_WIRE_MAIN_POWER1)
switch(wire)
if(WIRE_IDSCAN)
A.aiDisabledIdScanner = !mend
if(WIRE_MAIN_POWER1)
if(!mended)
if(!mend)
//Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be crowbarred open, but bolts-raising will not work. Cutting these wires may electocute the user.
A.loseMainPower()
A.shock(usr, 50)
@@ -92,9 +53,9 @@
A.regainMainPower()
A.shock(usr, 50)
if(AIRLOCK_WIRE_BACKUP_POWER1)
if(WIRE_BACKUP_POWER1)
if(!mended)
if(!mend)
//Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user.
A.loseBackupPower()
A.shock(usr, 50)
@@ -102,66 +63,66 @@
A.regainBackupPower()
A.shock(usr, 50)
if(AIRLOCK_WIRE_DOOR_BOLTS)
if(WIRE_DOOR_BOLTS)
if(!mended)
if(!mend)
//Cutting this wire also drops the door bolts, and mending it does not raise them. (This is what happens now, except there are a lot more wires going to door bolts at present)
A.lock(1)
A.update_icon()
if(AIRLOCK_WIRE_AI_CONTROL)
if(WIRE_AI_CONTROL)
if(!mended)
if(!mend)
//one wire for AI control. Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all.
//aiControlDisabled: If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
//aiControlDisabled: see explanation in code\__DEFINES\construction.dm#32
if(A.aiControlDisabled == AICONTROLDISABLED_OFF)
A.aiControlDisabled = AICONTROLDISABLED_ON
else if(A.aiControlDisabled == AICONTROLDISABLED_PERMA)
A.aiControlDisabled = AICONTROLDISABLED_BYPASS
else
if(A.aiControlDisabled == 1)
A.aiControlDisabled = 0
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
if(A.aiControlDisabled == AICONTROLDISABLED_ON)
A.aiControlDisabled = AICONTROLDISABLED_OFF
else if(A.aiControlDisabled == AICONTROLDISABLED_BYPASS)
A.aiControlDisabled = AICONTROLDISABLED_PERMA
if(AIRLOCK_WIRE_ELECTRIFY)
if(!mended)
if(WIRE_ELECTRIFY)
if(!mend)
//Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted.
A.electrify(-1)
else
A.electrify(0)
return // Don't update the dialog.
if(AIRLOCK_WIRE_SAFETY)
A.safe = mended
if(WIRE_SAFETY)
A.safe = mend
if(AIRLOCK_WIRE_SPEED)
A.autoclose = mended
if(mended)
if(WIRE_SPEED)
A.autoclose = mend
if(mend)
if(!A.density)
spawn(0)
A.close()
INVOKE_ASYNC(A, /obj/machinery/door/airlock/.proc/close)
if(AIRLOCK_WIRE_LIGHT)
A.lights = mended
if(WIRE_BOLT_LIGHT)
A.lights = mend
A.update_icon()
..()
/datum/wires/airlock/UpdatePulsed(index)
/datum/wires/airlock/on_pulse(wire)
var/obj/machinery/door/airlock/A = holder
switch(index)
if(AIRLOCK_WIRE_IDSCAN)
switch(wire)
if(WIRE_IDSCAN)
//Sending a pulse through flashes the red light on the door (if the door has power).
if(A.arePowerSystemsOn() && A.density)
A.do_animate("deny")
if(A.emergency)
A.emergency = 0
A.update_icon()
if(AIRLOCK_WIRE_MAIN_POWER1)
if(WIRE_MAIN_POWER1)
//Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter).
A.loseMainPower()
if(AIRLOCK_WIRE_DOOR_BOLTS)
if(WIRE_DOOR_BOLTS)
//one wire for door bolts. Sending a pulse through this drops door bolts if they're not down (whether power's on or not),
//raises them if they are down (only if power's on)
if(!A.locked)
@@ -170,45 +131,41 @@
else if(A.unlock())
A.audible_message("<span class='italics'>You hear a click from the bottom of the door.</span>", hearing_distance = 1)
if(AIRLOCK_WIRE_BACKUP_POWER1)
if(WIRE_BACKUP_POWER1)
//two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter).
A.loseBackupPower()
if(AIRLOCK_WIRE_AI_CONTROL)
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
spawn(10)
if(A)
if(A.aiControlDisabled == 1)
A.aiControlDisabled = 0
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
if(WIRE_AI_CONTROL)
if(A.aiControlDisabled == AICONTROLDISABLED_OFF)
A.aiControlDisabled = AICONTROLDISABLED_ON
else if(A.aiControlDisabled == AICONTROLDISABLED_PERMA)
A.aiControlDisabled = AICONTROLDISABLED_BYPASS
if(AIRLOCK_WIRE_ELECTRIFY)
addtimer(CALLBACK(A, /obj/machinery/door/airlock/.proc/ai_control_callback), 1 SECONDS)
if(WIRE_ELECTRIFY)
//one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds.
A.electrify(30)
if(AIRLOCK_WIRE_OPEN_DOOR)
if(WIRE_OPEN_DOOR)
//tries to open the door without ID
//will succeed only if the ID wire is cut or the door requires no access and it's not emagged
if(A.emagged) return
if(!A.requiresID() || A.check_access(null))
spawn(0)
if(A.density)
A.open()
else
A.close()
if(AIRLOCK_WIRE_SAFETY)
if(A.density)
INVOKE_ASYNC(A, /obj/machinery/door/airlock/.proc/open)
else
INVOKE_ASYNC(A, /obj/machinery/door/airlock/.proc/close)
if(WIRE_SAFETY)
A.safe = !A.safe
if(!A.density)
spawn(0)
A.close()
INVOKE_ASYNC(A, /obj/machinery/door/airlock/.proc/close)
if(AIRLOCK_WIRE_SPEED)
if(WIRE_SPEED)
A.normalspeed = !A.normalspeed
if(AIRLOCK_WIRE_LIGHT)
if(WIRE_BOLT_LIGHT)
A.lights = !A.lights
A.update_icon()
+41 -69
View File
@@ -2,35 +2,22 @@
/datum/wires/alarm
holder_type = /obj/machinery/alarm
wire_count = 5
window_x = 385
window_y = 90
proper_name = "Air alarm"
#define AALARM_WIRE_IDSCAN 1
#define AALARM_WIRE_POWER 2
#define AALARM_WIRE_SYPHON 4
#define AALARM_WIRE_AI_CONTROL 8
#define AALARM_WIRE_AALARM 16
/datum/wires/alarm/New(atom/_holder)
wires = list(
WIRE_IDSCAN , WIRE_MAIN_POWER1 , WIRE_SYPHON,
WIRE_AI_CONTROL, WIRE_AALARM
)
return ..()
/datum/wires/alarm/GetWireName(index)
switch(index)
if(AALARM_WIRE_IDSCAN)
return "ID Scan"
if(AALARM_WIRE_POWER)
return "Power"
if(AALARM_WIRE_SYPHON)
return "Syphon"
if(AALARM_WIRE_AI_CONTROL)
return "AI Control"
if(AALARM_WIRE_AALARM)
return "Atmospherics Alarm"
/datum/wires/alarm/CanUse(mob/living/L)
/datum/wires/alarm/interactable(mob/user)
var/obj/machinery/alarm/A = holder
if(A.wiresexposed)
return 1
return 0
return TRUE
return FALSE
/datum/wires/alarm/get_status()
. = ..()
@@ -39,75 +26,60 @@
. += "The Air Alarm is [(A.shorted || (A.stat & (NOPOWER|BROKEN))) ? "offline." : "working properly!"]"
. += "The 'AI control allowed' light is [A.aidisabled ? "off" : "on"]."
/datum/wires/alarm/UpdateCut(index, mended)
/datum/wires/alarm/on_cut(wire, mend)
var/obj/machinery/alarm/A = holder
switch(index)
if(AALARM_WIRE_IDSCAN)
if(!mended)
switch(wire)
if(WIRE_IDSCAN)
if(!mend)
A.locked = 1
// to_chat(world, "Idscan wire cut")
if(AALARM_WIRE_POWER)
if(WIRE_MAIN_POWER1)
A.shock(usr, 50)
A.shorted = !mended
A.shorted = !mend
A.update_icon()
// to_chat(world, "Power wire cut")
if(AALARM_WIRE_AI_CONTROL)
A.aidisabled = !mended
// to_chat(world, "AI Control Wire Cut")
if(WIRE_AI_CONTROL)
A.aidisabled = !mend
if(AALARM_WIRE_SYPHON)
if(!mended)
if(WIRE_SYPHON)
if(!mend)
A.mode = 3 // AALARM_MODE_PANIC
A.apply_mode()
// to_chat(world, "Syphon Wire Cut")
if(AALARM_WIRE_AALARM)
if(A.alarm_area.atmosalert(2, A))
A.post_alert(2)
if(WIRE_AALARM)
if(A.alarm_area.atmosalert(ATMOS_ALARM_DANGER, A))
A.post_alert(ATMOS_ALARM_DANGER)
A.update_icon()
..()
/datum/wires/alarm/UpdatePulsed(index)
/datum/wires/alarm/on_pulse(wire)
var/obj/machinery/alarm/A = holder
switch(index)
if(AALARM_WIRE_IDSCAN)
switch(wire)
if(WIRE_IDSCAN)
A.locked = !A.locked
// to_chat(world, "Idscan wire pulsed")
if(AALARM_WIRE_POWER)
// to_chat(world, "Power wire pulsed")
if(A.shorted == 0)
A.shorted = 1
if(WIRE_MAIN_POWER1)
if(!A.shorted)
A.shorted = TRUE
A.update_icon()
addtimer(CALLBACK(A, /obj/machinery/alarm/.proc/unshort_callback), 120 SECONDS)
spawn(12000)
if(A.shorted == 1)
A.shorted = 0
A.update_icon()
if(AALARM_WIRE_AI_CONTROL)
// to_chat(world, "AI Control wire pulsed")
if(A.aidisabled == 0)
A.aidisabled = 1
if(WIRE_AI_CONTROL)
if(!A.aidisabled)
A.aidisabled = TRUE
A.updateDialog()
spawn(100)
if(A.aidisabled == 1)
A.aidisabled = 0
addtimer(CALLBACK(A, /obj/machinery/alarm/.proc/enable_ai_control_callback), 10 SECONDS)
if(AALARM_WIRE_SYPHON)
// to_chat(world, "Syphon wire pulsed")
if(WIRE_SYPHON)
if(A.mode == 1) // AALARM_MODE_SCRUB
A.mode = 3 // AALARM_MODE_PANIC
else
A.mode = 1 // AALARM_MODE_SCRUB
A.apply_mode()
if(AALARM_WIRE_AALARM)
// to_chat(world, "Aalarm wire pulsed")
if(A.alarm_area.atmosalert(0, A))
A.post_alert(0)
if(WIRE_AALARM)
if(A.alarm_area.atmosalert(ATMOS_ALARM_NONE, A))
A.post_alert(ATMOS_ALARM_NONE)
A.update_icon()
..()
+33 -58
View File
@@ -1,25 +1,13 @@
/datum/wires/apc
holder_type = /obj/machinery/power/apc
wire_count = 4
proper_name = "APC"
window_x = 355
window_y = 97
#define APC_WIRE_IDSCAN 1
#define APC_WIRE_MAIN_POWER1 2
#define APC_WIRE_MAIN_POWER2 4
#define APC_WIRE_AI_CONTROL 8
/datum/wires/apc/GetWireName(index)
switch(index)
if(APC_WIRE_IDSCAN)
return "ID Scan"
if(APC_WIRE_MAIN_POWER1)
return "Primary Power"
if(APC_WIRE_MAIN_POWER2)
return "Secondary Power"
if(APC_WIRE_AI_CONTROL)
return "AI Control"
/datum/wires/apc/New(atom/_holder)
wires = list(WIRE_IDSCAN, WIRE_MAIN_POWER1, WIRE_MAIN_POWER2, WIRE_AI_CONTROL)
return ..()
/datum/wires/apc/get_status()
. = ..()
@@ -29,66 +17,53 @@
. += "The 'AI control allowed' light is [A.aidisabled ? "off" : "on"]."
/datum/wires/apc/CanUse(mob/living/L)
/datum/wires/apc/interactable(mob/user)
var/obj/machinery/power/apc/A = holder
if(A.panel_open && !A.opened)
return TRUE
return FALSE
/datum/wires/apc/UpdatePulsed(index)
/datum/wires/apc/on_pulse(wire)
var/obj/machinery/power/apc/A = holder
switch(index)
switch(wire)
if(WIRE_IDSCAN)
A.locked = FALSE
addtimer(CALLBACK(A, /obj/machinery/power/apc/.proc/relock_callback), 30 SECONDS)
if(APC_WIRE_IDSCAN)
A.locked = 0
spawn(300)
if(A)
A.locked = 1
A.updateDialog()
if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
if(!A.shorted)
A.shorted = TRUE
addtimer(CALLBACK(A, /obj/machinery/power/apc/.proc/check_main_power_callback), 120 SECONDS)
if(APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2)
if(A.shorted == 0)
A.shorted = 1
spawn(1200)
if(A && !IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2))
A.shorted = 0
A.updateDialog()
if(APC_WIRE_AI_CONTROL)
if(A.aidisabled == 0)
A.aidisabled = 1
spawn(10)
if(A && !IsIndexCut(APC_WIRE_AI_CONTROL))
A.aidisabled = 0
A.updateDialog()
if(WIRE_AI_CONTROL)
if(!A.aidisabled)
A.aidisabled = TRUE
addtimer(CALLBACK(A, /obj/machinery/power/apc/.proc/check_ai_control_callback), 1 SECONDS)
..()
/datum/wires/apc/UpdateCut(index, mended)
/datum/wires/apc/on_cut(wire, mend)
var/obj/machinery/power/apc/A = holder
switch(index)
if(APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2)
if(!mended)
switch(wire)
if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
if(!mend)
A.shock(usr, 50)
A.shorted = 1
A.shorted = TRUE
else if(!IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2))
A.shorted = 0
else if(!is_cut(WIRE_MAIN_POWER1) && !is_cut(WIRE_MAIN_POWER2))
A.shorted = FALSE
A.shock(usr, 50)
if(APC_WIRE_AI_CONTROL)
if(!mended)
if(A.aidisabled == 0)
A.aidisabled = 1
if(WIRE_AI_CONTROL)
if(!mend)
if(!A.aidisabled)
A.aidisabled = TRUE
else
if(A.aidisabled == 1)
A.aidisabled = 0
if(A.aidisabled)
A.aidisabled = FALSE
..()
+31 -52
View File
@@ -1,21 +1,13 @@
/datum/wires/autolathe
holder_type = /obj/machinery/autolathe
wire_count = 10
proper_name = "Autolathe"
window_x = 340
window_y = 55
#define AUTOLATHE_HACK_WIRE 1
#define AUTOLATHE_SHOCK_WIRE 2
#define AUTOLATHE_DISABLE_WIRE 4
/datum/wires/autolathe/GetWireName(index)
switch(index)
if(AUTOLATHE_HACK_WIRE)
return "Hack"
if(AUTOLATHE_SHOCK_WIRE)
return "Shock"
if(AUTOLATHE_DISABLE_WIRE)
return "Disable"
/datum/wires/autolathe/New(atom/_holder)
wires = list(WIRE_AUTOLATHE_HACK, WIRE_ELECTRIFY, WIRE_AUTOLATHE_DISABLE)
return ..()
/datum/wires/autolathe/get_status()
. = ..()
@@ -24,51 +16,38 @@
. += "The green light is [A.shocked ? "off" : "on"]."
. += "The blue light is [A.hacked ? "off" : "on"]."
/datum/wires/autolathe/CanUse()
/datum/wires/autolathe/interactable(mob/user)
var/obj/machinery/autolathe/A = holder
if(iscarbon(user) && A.Adjacent(user) && A.shocked && A.shock(user, 100))
return FALSE
if(A.panel_open)
return 1
return 0
return TRUE
return FALSE
/datum/wires/autolathe/UpdateCut(index, mended)
/datum/wires/autolathe/on_cut(wire, mend)
var/obj/machinery/autolathe/A = holder
switch(index)
if(AUTOLATHE_HACK_WIRE)
A.adjust_hacked(!mended)
if(AUTOLATHE_SHOCK_WIRE)
A.shocked = !mended
if(AUTOLATHE_DISABLE_WIRE)
A.disabled = !mended
switch(wire)
if(WIRE_AUTOLATHE_HACK)
A.adjust_hacked(!mend)
if(WIRE_ELECTRIFY)
A.shocked = !mend
if(WIRE_AUTOLATHE_DISABLE)
A.disabled = !mend
..()
/datum/wires/autolathe/UpdatePulsed(index)
if(IsIndexCut(index))
/datum/wires/autolathe/on_pulse(wire)
if(is_cut(wire))
return
var/obj/machinery/autolathe/A = holder
switch(index)
if(AUTOLATHE_HACK_WIRE)
switch(wire)
if(WIRE_AUTOLATHE_HACK)
A.adjust_hacked(!A.hacked)
updateUIs()
spawn(50)
if(A && !IsIndexCut(index))
A.adjust_hacked(0)
updateUIs()
if(AUTOLATHE_SHOCK_WIRE)
A.shocked = !A.shocked
updateUIs()
spawn(50)
if(A && !IsIndexCut(index))
A.shocked = 0
updateUIs()
if(AUTOLATHE_DISABLE_WIRE)
A.disabled = !A.disabled
updateUIs()
spawn(50)
if(A && !IsIndexCut(index))
A.disabled = 0
updateUIs()
addtimer(CALLBACK(A, /obj/machinery/autolathe/.proc/check_hacked_callback), 5 SECONDS)
/datum/wires/autolathe/proc/updateUIs()
SSnanoui.update_uis(src)
if(holder)
SSnanoui.update_uis(holder)
if(WIRE_ELECTRIFY)
A.shocked = !A.shocked
addtimer(CALLBACK(A, /obj/machinery/autolathe/.proc/check_electrified_callback), 5 SECONDS)
if(WIRE_AUTOLATHE_DISABLE)
A.disabled = !A.disabled
addtimer(CALLBACK(A, /obj/machinery/autolathe/.proc/check_disabled_callback), 5 SECONDS)
+20 -25
View File
@@ -1,9 +1,15 @@
// Wires for cameras.
/datum/wires/camera
random = 0
holder_type = /obj/machinery/camera
wire_count = 2
proper_name = "Camera"
window_x = 350
window_y = 95
/datum/wires/camera/New(atom/_holder)
wires = list(WIRE_FOCUS, WIRE_MAIN_POWER1)
return ..()
/datum/wires/camera/get_status()
. = ..()
@@ -11,51 +17,40 @@
. += "The focus light is [(C.view_range == initial(C.view_range)) ? "on" : "off"]."
. += "The power link light is [C.can_use() ? "on" : "off"]."
/datum/wires/camera/CanUse(mob/living/L)
/datum/wires/camera/interactable(mob/user)
var/obj/machinery/camera/C = holder
if(!C.panel_open)
return FALSE
return TRUE
#define CAMERA_WIRE_FOCUS 1
#define CAMERA_WIRE_POWER 2
/datum/wires/camera/GetWireName(index)
switch(index)
if(CAMERA_WIRE_FOCUS)
return "Focus"
if(CAMERA_WIRE_POWER)
return "Power"
/datum/wires/camera/UpdateCut(index, mended)
/datum/wires/camera/on_cut(wire, mend)
var/obj/machinery/camera/C = holder
switch(index)
if(CAMERA_WIRE_FOCUS)
var/range = (mended ? initial(C.view_range) : C.short_range)
switch(wire)
if(WIRE_FOCUS)
var/range = (mend ? initial(C.view_range) : C.short_range)
C.setViewRange(range)
if(CAMERA_WIRE_POWER)
if(C.status && !mended || !C.status && mended)
if(WIRE_MAIN_POWER1)
if(C.status && !mend || !C.status && mend)
C.toggle_cam(usr, TRUE)
C.obj_integrity = C.max_integrity //this is a pretty simplistic way to heal the camera, but there's no reason for this to be complex.
..()
/datum/wires/camera/UpdatePulsed(index)
/datum/wires/camera/on_pulse(wire)
var/obj/machinery/camera/C = holder
if(IsIndexCut(index))
if(is_cut(wire))
return
switch(index)
if(CAMERA_WIRE_FOCUS)
switch(wire)
if(WIRE_FOCUS)
var/new_range = (C.view_range == initial(C.view_range) ? C.short_range : initial(C.view_range))
C.setViewRange(new_range)
if(CAMERA_WIRE_POWER)
if(WIRE_MAIN_POWER1)
C.toggle_cam(null) // Deactivate the camera
..()
/datum/wires/camera/proc/CanDeconstruct()
if(IsIndexCut(CAMERA_WIRE_POWER) && IsIndexCut(CAMERA_WIRE_FOCUS))
if(is_cut(WIRE_MAIN_POWER1) && is_cut(WIRE_FOCUS))
return TRUE
else
return FALSE
+14 -14
View File
@@ -1,36 +1,36 @@
/datum/wires/explosive
wire_count = 1
proper_name = "Explosive"
window_x = 320
window_y = 50
#define WIRE_EXPLODE 1
/datum/wires/explosive/GetWireName(index)
switch(index)
if(WIRE_EXPLODE)
return "Explode"
/datum/wires/explosive/New(atom/_holder)
wires = list(WIRE_EXPLODE)
return ..()
/datum/wires/explosive/proc/explode()
return
/datum/wires/explosive/UpdatePulsed(index)
switch(index)
/datum/wires/explosive/on_pulse(wire)
switch(wire)
if(WIRE_EXPLODE)
explode()
..()
/datum/wires/explosive/UpdateCut(index, mended)
switch(index)
/datum/wires/explosive/on_cut(wire, mend)
switch(wire)
if(WIRE_EXPLODE)
if(!mended)
if(!mend)
explode()
..()
/datum/wires/explosive/gibtonite
holder_type = /obj/item/twohanded/required/gibtonite
/datum/wires/explosive/gibtonite/CanUse(mob/L)
return 1
/datum/wires/explosive/gibtonite/interactable(mob/user)
return TRUE
/datum/wires/explosive/gibtonite/UpdateCut(index, mended)
/datum/wires/explosive/gibtonite/on_cut(wire, mend)
return
/datum/wires/explosive/gibtonite/explode()
+20 -75
View File
@@ -1,90 +1,35 @@
/datum/wires/mulebot
random = 1
randomize = TRUE
holder_type = /mob/living/simple_animal/bot/mulebot
wire_count = 10
window_x = 410
proper_name = "Mulebot"
window_x = 370
window_y = -12
#define MULEBOT_WIRE_POWER1 1 // power connections
#define MULEBOT_WIRE_POWER2 2
#define MULEBOT_WIRE_AVOIDANCE 4 // mob avoidance
#define MULEBOT_WIRE_LOADCHECK 8 // load checking (non-crate)
#define MULEBOT_WIRE_MOTOR1 16 // motor wires
#define MULEBOT_WIRE_MOTOR2 32 //
#define MULEBOT_WIRE_REMOTE_RX 64 // remote recv functions
#define MULEBOT_WIRE_REMOTE_TX 128 // remote trans status
#define MULEBOT_WIRE_BEACON_RX 256 // beacon ping recv
/datum/wires/mulebot/New(atom/_holder)
wires = list(
WIRE_MAIN_POWER1, WIRE_MAIN_POWER2, WIRE_MOB_AVOIDANCE,
WIRE_LOADCHECK, WIRE_MOTOR1, WIRE_MOTOR2,
WIRE_REMOTE_RX, WIRE_REMOTE_TX, WIRE_BEACON_RX
)
return ..()
/datum/wires/mulebot/GetWireName(index)
switch(index)
if(MULEBOT_WIRE_POWER1)
return "Primary Power"
if(MULEBOT_WIRE_POWER2)
return "Secondary Power"
if(MULEBOT_WIRE_AVOIDANCE)
return "Mob Avoidance"
if(MULEBOT_WIRE_LOADCHECK)
return "Load Checking"
if(MULEBOT_WIRE_MOTOR1)
return "Primary Motor"
if(MULEBOT_WIRE_MOTOR2)
return "Secondary Motor"
if(MULEBOT_WIRE_REMOTE_RX)
return "Remote Signal Receiver"
if(MULEBOT_WIRE_REMOTE_TX)
return "Remote Signal Sender"
if(MULEBOT_WIRE_BEACON_RX)
return "Navigation Beacon Receiver"
/datum/wires/mulebot/CanUse(mob/living/L)
/datum/wires/mulebot/interactable(mob/user)
var/mob/living/simple_animal/bot/mulebot/M = holder
if(M.open)
return 1
return 0
return TRUE
return FALSE
/datum/wires/mulebot/UpdatePulsed(index)
switch(index)
if(MULEBOT_WIRE_POWER1, MULEBOT_WIRE_POWER2)
/datum/wires/mulebot/on_pulse(wire)
switch(wire)
if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
holder.visible_message("<span class='notice'>[bicon(holder)] The charge light flickers.</span>")
if(MULEBOT_WIRE_AVOIDANCE)
if(WIRE_MOB_AVOIDANCE)
holder.visible_message("<span class='notice'>[bicon(holder)] The external warning lights flash briefly.</span>")
if(MULEBOT_WIRE_LOADCHECK)
if(WIRE_LOADCHECK)
holder.visible_message("<span class='notice'>[bicon(holder)] The load platform clunks.</span>")
if(MULEBOT_WIRE_MOTOR1, MULEBOT_WIRE_MOTOR2)
if(WIRE_MOTOR1, WIRE_MOTOR2)
holder.visible_message("<span class='notice'>[bicon(holder)] The drive motor whines briefly.</span>")
else
holder.visible_message("<span class='notice'>[bicon(holder)] You hear a radio crackle.</span>")
..()
// HELPER PROCS
/datum/wires/mulebot/proc/Motor1()
return !(wires_status & MULEBOT_WIRE_MOTOR1)
/datum/wires/mulebot/proc/Motor2()
return !(wires_status & MULEBOT_WIRE_MOTOR2)
/datum/wires/mulebot/proc/HasPower()
return !(wires_status & MULEBOT_WIRE_POWER1) && !(wires_status & MULEBOT_WIRE_POWER2)
/datum/wires/mulebot/proc/LoadCheck()
return !(wires_status & MULEBOT_WIRE_LOADCHECK)
/datum/wires/mulebot/proc/MobAvoid()
return !(wires_status & MULEBOT_WIRE_AVOIDANCE)
/datum/wires/mulebot/proc/RemoteTX()
return !(wires_status & MULEBOT_WIRE_REMOTE_TX)
/datum/wires/mulebot/proc/RemoteRX()
return !(wires_status & MULEBOT_WIRE_REMOTE_RX)
/datum/wires/mulebot/proc/BeaconRX()
return !(wires_status & MULEBOT_WIRE_BEACON_RX)
+29 -53
View File
@@ -1,28 +1,20 @@
/datum/wires/nuclearbomb
holder_type = /obj/machinery/nuclearbomb
random = 1
wire_count = 7
randomize = TRUE
wire_count = 7 // 3 actual, 4 duds.
proper_name = "Nuclear bomb"
window_x = 345
window_y = 75
#define NUCLEARBOMB_WIRE_LIGHT 1
#define NUCLEARBOMB_WIRE_TIMING 2
#define NUCLEARBOMB_WIRE_SAFETY 4
/datum/wires/nuclearbomb/New(atom/_holder)
wires = list(WIRE_BOMB_LIGHT, WIRE_BOMB_TIMING, WIRE_BOMB_SAFETY)
return ..()
/datum/wires/nuclearbomb/GetWireName(index)
switch(index)
if(NUCLEARBOMB_WIRE_LIGHT)
return "Bomb Light"
if(NUCLEARBOMB_WIRE_TIMING)
return "Bomb Timing"
if(NUCLEARBOMB_WIRE_SAFETY)
return "Bomb Safety"
/datum/wires/nuclearbomb/CanUse(mob/living/L)
/datum/wires/nuclearbomb/interactable(mob/user)
var/obj/machinery/nuclearbomb/N = holder
if(N.panel_open)
return 1
return 0
return TRUE
return FALSE
/datum/wires/nuclearbomb/get_status()
. = ..()
@@ -31,52 +23,36 @@
. += "The device is is [N.safety ? "quiet" : "whirring"]."
. += "The lights are [N.lighthack ? "static" : "functional"]."
/datum/wires/nuclearbomb/UpdatePulsed(index)
/datum/wires/nuclearbomb/on_pulse(wire)
var/obj/machinery/nuclearbomb/N = holder
switch(index)
if(NUCLEARBOMB_WIRE_LIGHT)
switch(wire)
if(WIRE_BOMB_LIGHT)
N.lighthack = !N.lighthack
updateUIs()
spawn(100)
N.lighthack = !N.lighthack
updateUIs()
if(NUCLEARBOMB_WIRE_TIMING)
addtimer(CALLBACK(N, /obj/machinery/nuclearbomb/.proc/reset_lighthack_callback), 10 SECONDS)
if(WIRE_BOMB_TIMING)
if(N.timing)
message_admins("[key_name_admin(usr)] pulsed a nuclear bomb's detonation wire, causing it to explode (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[holder.x];Y=[holder.y];Z=[holder.z]'>JMP</a>)")
N.explode()
if(NUCLEARBOMB_WIRE_SAFETY)
N.safety = !N.safety
updateUIs()
spawn(100)
N.safety = !N.safety
if(N.safety == 1)
if(!N.is_syndicate)
set_security_level(N.previous_level)
N.visible_message("<span class='notice'>The [N] quiets down.</span>")
if(!N.lighthack)
if(N.icon_state == "nuclearbomb2")
N.icon_state = "nuclearbomb1"
else
N.visible_message("<span class='notice'>The [N] emits a quiet whirling noise!</span>")
updateUIs()
/datum/wires/nuclearbomb/UpdateCut(index, mended)
if(WIRE_BOMB_SAFETY)
N.safety = !N.safety
addtimer(CALLBACK(N, /obj/machinery/nuclearbomb/.proc/reset_safety_callback), 10 SECONDS)
/datum/wires/nuclearbomb/on_cut(wire, mend)
var/obj/machinery/nuclearbomb/N = holder
switch(index)
if(NUCLEARBOMB_WIRE_SAFETY)
switch(wire)
if(WIRE_BOMB_SAFETY)
if(N.timing)
message_admins("[key_name_admin(usr)] cut a nuclear bomb's timing wire, causing it to explode (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[holder.x];Y=[holder.y];Z=[holder.z]'>JMP</a>)")
N.explode()
if(NUCLEARBOMB_WIRE_TIMING)
if(WIRE_BOMB_TIMING)
if(!N.lighthack)
if(N.icon_state == "nuclearbomb2")
N.icon_state = "nuclearbomb1"
N.timing = 0
GLOB.bomb_set = 0
if(NUCLEARBOMB_WIRE_LIGHT)
N.lighthack = !N.lighthack
GLOB.bomb_set = FALSE
/datum/wires/nuclearbomb/proc/updateUIs()
SSnanoui.update_uis(src)
if(holder)
SSnanoui.update_uis(holder)
if(WIRE_BOMB_LIGHT)
N.lighthack = !N.lighthack
+25 -40
View File
@@ -1,67 +1,52 @@
/datum/wires/particle_acc/control_box
wire_count = 5
holder_type = /obj/machinery/particle_accelerator/control_box
proper_name = "Particle accelerator control"
window_x = 361
window_y = 22
#define PARTICLE_TOGGLE_WIRE 1 // Toggles whether the PA is on or not.
#define PARTICLE_STRENGTH_WIRE 2 // Determines the strength of the PA.
#define PARTICLE_INTERFACE_WIRE 4 // Determines the interface showing up.
#define PARTICLE_LIMIT_POWER_WIRE 8 // Determines how strong the PA can be.
/datum/wires/particle_acc/control_box/New(atom/_holder)
wires = list(WIRE_PARTICLE_POWER, WIRE_PARTICLE_STRENGTH, WIRE_PARTICLE_INTERFACE, WIRE_PARTICLE_POWER_LIMIT)
return ..()
/datum/wires/particle_acc/control_box/GetWireName(index)
switch(index)
if(PARTICLE_TOGGLE_WIRE)
return "Power Toggle"
if(PARTICLE_STRENGTH_WIRE)
return "Strength"
if(PARTICLE_INTERFACE_WIRE)
return "Interface"
if(PARTICLE_LIMIT_POWER_WIRE)
return "Maximum Power"
/datum/wires/particle_acc/control_box/CanUse(mob/living/L)
/datum/wires/particle_acc/control_box/interactable(mob/user)
var/obj/machinery/particle_accelerator/control_box/C = holder
if(C.construction_state == 2)
return 1
return 0
return TRUE
return FALSE
/datum/wires/particle_acc/control_box/UpdatePulsed(index)
/datum/wires/particle_acc/control_box/on_pulse(wire)
var/obj/machinery/particle_accelerator/control_box/C = holder
switch(index)
if(PARTICLE_TOGGLE_WIRE)
switch(wire)
if(WIRE_PARTICLE_POWER)
C.toggle_power()
if(PARTICLE_STRENGTH_WIRE)
if(WIRE_PARTICLE_STRENGTH)
C.add_strength()
if(PARTICLE_INTERFACE_WIRE)
if(WIRE_PARTICLE_INTERFACE)
C.interface_control = !C.interface_control
if(PARTICLE_LIMIT_POWER_WIRE)
if(WIRE_PARTICLE_POWER_LIMIT)
C.visible_message("[bicon(C)]<b>[C]</b> makes a large whirring noise.")
..()
/datum/wires/particle_acc/control_box/UpdateCut(index, mended)
/datum/wires/particle_acc/control_box/on_cut(wire, mend)
var/obj/machinery/particle_accelerator/control_box/C = holder
switch(index)
if(PARTICLE_TOGGLE_WIRE)
if(C.active == !mended)
switch(wire)
if(WIRE_PARTICLE_POWER)
if(C.active == !mend)
C.toggle_power()
if(PARTICLE_STRENGTH_WIRE)
for(var/i = 1; i < 3; i++)
if(WIRE_PARTICLE_STRENGTH)
for(var/i in 1 to 2)
C.remove_strength()
if(PARTICLE_INTERFACE_WIRE)
C.interface_control = mended
if(WIRE_PARTICLE_INTERFACE)
C.interface_control = mend
if(PARTICLE_LIMIT_POWER_WIRE)
C.strength_upper_limit = (mended ? 2 : 3)
if(WIRE_PARTICLE_POWER_LIMIT)
C.strength_upper_limit = (mend ? 2 : 3)
if(C.strength_upper_limit < C.strength)
C.remove_strength()
..()
+27 -35
View File
@@ -1,52 +1,44 @@
/datum/wires/radio
holder_type = /obj/item/radio
wire_count = 3
proper_name = "Radio"
window_x = 330
window_y = 37
#define RADIO_WIRE_SIGNAL 1
#define RADIO_WIRE_RECEIVE 2
#define RADIO_WIRE_TRANSMIT 4
/datum/wires/radio/New(atom/_holder)
wires = list(WIRE_RADIO_SIGNAL, WIRE_RADIO_RECEIVER, WIRE_RADIO_TRANSMIT)
return ..()
/datum/wires/radio/GetWireName(index)
switch(index)
if(RADIO_WIRE_SIGNAL)
return "Signal"
if(RADIO_WIRE_RECEIVE)
return "Receiver"
if(RADIO_WIRE_TRANSMIT)
return "Transmitter"
/datum/wires/radio/CanUse(mob/living/L)
/datum/wires/radio/interactable(mob/user)
var/obj/item/radio/R = holder
if(R.b_stat)
return 1
return 0
return TRUE
return FALSE
/datum/wires/radio/UpdatePulsed(index)
/datum/wires/radio/on_pulse(wire)
var/obj/item/radio/R = holder
switch(index)
if(RADIO_WIRE_SIGNAL)
R.listening = !R.listening && !IsIndexCut(RADIO_WIRE_RECEIVE)
R.broadcasting = R.listening && !IsIndexCut(RADIO_WIRE_TRANSMIT)
switch(wire)
if(WIRE_RADIO_SIGNAL)
R.listening = !R.listening && !is_cut(WIRE_RADIO_RECEIVER)
R.broadcasting = R.listening && !is_cut(WIRE_RADIO_TRANSMIT)
if(RADIO_WIRE_RECEIVE)
R.listening = !R.listening && !IsIndexCut(RADIO_WIRE_SIGNAL)
if(WIRE_RADIO_RECEIVER)
R.listening = !R.listening && !is_cut(WIRE_RADIO_SIGNAL)
if(RADIO_WIRE_TRANSMIT)
R.broadcasting = !R.broadcasting && !IsIndexCut(RADIO_WIRE_SIGNAL)
if(WIRE_RADIO_TRANSMIT)
R.broadcasting = !R.broadcasting && !is_cut(WIRE_RADIO_SIGNAL)
..()
/datum/wires/radio/UpdateCut(index, mended)
/datum/wires/radio/on_cut(wire, mend)
var/obj/item/radio/R = holder
switch(index)
if(RADIO_WIRE_SIGNAL)
R.listening = mended && !IsIndexCut(RADIO_WIRE_RECEIVE)
R.broadcasting = mended && !IsIndexCut(RADIO_WIRE_TRANSMIT)
switch(wire)
if(WIRE_RADIO_SIGNAL)
R.listening = mend && !is_cut(WIRE_RADIO_RECEIVER)
R.broadcasting = mend && !is_cut(WIRE_RADIO_TRANSMIT)
if(RADIO_WIRE_RECEIVE)
R.listening = mended && !IsIndexCut(RADIO_WIRE_SIGNAL)
if(WIRE_RADIO_RECEIVER)
R.listening = mend && !is_cut(WIRE_RADIO_SIGNAL)
if(RADIO_WIRE_TRANSMIT)
R.broadcasting = mended && !IsIndexCut(RADIO_WIRE_SIGNAL)
if(WIRE_RADIO_TRANSMIT)
R.broadcasting = mend && !is_cut(WIRE_RADIO_SIGNAL)
..()
+29 -64
View File
@@ -1,32 +1,14 @@
/datum/wires/robot
random = 1
randomize = TRUE
holder_type = /mob/living/silicon/robot
wire_count = 5
window_x = 340
window_y = 106
proper_name = "Cyborg"
// /vg/ ordering
#define BORG_WIRE_MAIN_POWER 1 // The power wires do nothing whyyyyyyyyyyyyy
#define BORG_WIRE_LOCKED_DOWN 2
#define BORG_WIRE_CAMERA 4
#define BORG_WIRE_AI_CONTROL 8 // Not used on MoMMIs
#define BORG_WIRE_LAWCHECK 16 // Not used on MoMMIs
/datum/wires/robot/GetWireName(index)
switch(index)
if(BORG_WIRE_MAIN_POWER)
return "Main Power"
if(BORG_WIRE_LOCKED_DOWN)
return "Lockdown"
if(BORG_WIRE_CAMERA)
return "Camera"
if(BORG_WIRE_AI_CONTROL)
return "AI Control"
if(BORG_WIRE_LAWCHECK)
return "Law Check"
/datum/wires/robot/New(atom/_holder)
wires = list(WIRE_AI_CONTROL, WIRE_BORG_CAMERA, WIRE_BORG_LAWCHECK, WIRE_BORG_LOCKED)
return ..()
/datum/wires/robot/get_status()
. = ..()
@@ -36,70 +18,53 @@
. += "The Camera light is [(R.camera && R.camera.status == 1) ? "on" : "off"]."
. += "The lockdown light is [R.lockcharge ? "on" : "off"]."
/datum/wires/robot/UpdateCut(index, mended)
/datum/wires/robot/on_cut(wire, mend)
var/mob/living/silicon/robot/R = holder
switch(index)
if(BORG_WIRE_LAWCHECK) //Cut the law wire, and the borg will no longer receive law updates from its AI
if(!mended)
if(R.lawupdate == 1)
switch(wire)
if(WIRE_BORG_LAWCHECK) //Cut the law wire, and the borg will no longer receive law updates from its AI
if(!mend)
if(R.lawupdate)
to_chat(R, "LawSync protocol engaged.")
R.lawsync()
R.show_laws()
else
if(R.lawupdate == 0 && !R.emagged)
R.lawupdate = 1
if(!R.lawupdate && !R.emagged)
R.lawupdate = TRUE
if(BORG_WIRE_AI_CONTROL) //Cut the AI wire to reset AI control
if(!mended)
if(WIRE_AI_CONTROL) //Cut the AI wire to reset AI control
if(!mend)
if(R.connected_ai)
R.disconnect_from_ai()
if(BORG_WIRE_CAMERA)
if(WIRE_BORG_CAMERA)
if(!isnull(R.camera) && !R.scrambledcodes)
R.camera.status = mended
R.camera.status = mend
R.camera.toggle_cam(usr, 0) // Will kick anyone who is watching the Cyborg's camera.
if(BORG_WIRE_LAWCHECK) //Forces a law update if the borg is set to receive them. Since an update would happen when the borg checks its laws anyway, not much use, but eh
if(R.lawupdate)
R.lawsync()
if(BORG_WIRE_LOCKED_DOWN)
R.SetLockdown(!mended)
if(WIRE_BORG_LOCKED)
R.SetLockdown(!mend)
..()
/datum/wires/robot/UpdatePulsed(index)
/datum/wires/robot/on_pulse(wire)
var/mob/living/silicon/robot/R = holder
switch(index)
if(BORG_WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI
switch(wire)
if(WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI
if(!R.emagged)
R.connect_to_ai(select_active_ai())
if(BORG_WIRE_CAMERA)
if(WIRE_BORG_CAMERA)
if(!isnull(R.camera) && R.camera.can_use() && !R.scrambledcodes)
R.camera.toggle_cam(usr, 0) // Kick anyone watching the Cyborg's camera, doesn't display you disconnecting the camera.
R.visible_message("[R]'s camera lense focuses loudly.")
to_chat(R, "Your camera lense focuses loudly.")
if(BORG_WIRE_LOCKED_DOWN)
if(WIRE_BORG_LOCKED)
R.SetLockdown(!R.lockcharge) // Toggle
..()
/datum/wires/robot/CanUse(mob/living/L)
/datum/wires/robot/interactable(mob/user)
var/mob/living/silicon/robot/R = holder
if(R.wiresexposed)
return 1
return 0
/datum/wires/robot/proc/IsCameraCut()
return wires_status & BORG_WIRE_CAMERA
/datum/wires/robot/proc/LockedCut()
return wires_status & BORG_WIRE_LOCKED_DOWN
/datum/wires/robot/proc/CanLawCheck()
return wires_status & BORG_WIRE_LAWCHECK
/datum/wires/robot/proc/AIHasControl()
return wires_status & BORG_WIRE_AI_CONTROL
return TRUE
return FALSE
+28 -37
View File
@@ -1,35 +1,26 @@
/datum/wires/smartfridge
holder_type = /obj/machinery/smartfridge
wire_count = 3
proper_name = "Smartfridge"
window_x = 340
window_y = 103
/datum/wires/smartfridge/New(atom/_holder)
wires = list(WIRE_ELECTRIFY, WIRE_IDSCAN, WIRE_THROW_ITEM)
return ..()
/datum/wires/smartfridge/secure
random = 1
wire_count = 4
randomize = TRUE
wire_count = 4 // 3 actual, 1 dud.
window_y = 97
#define SMARTFRIDGE_WIRE_ELECTRIFY 1
#define SMARTFRIDGE_WIRE_THROW 2
#define SMARTFRIDGE_WIRE_IDSCAN 4
/datum/wires/smartfridge/GetWireName(index)
switch(index)
if(SMARTFRIDGE_WIRE_ELECTRIFY)
return "Electrification"
if(SMARTFRIDGE_WIRE_THROW)
return "Item Throw"
if(SMARTFRIDGE_WIRE_IDSCAN)
return "ID Scan"
/datum/wires/smartfridge/CanUse(mob/living/L)
/datum/wires/smartfridge/interactable(mob/user)
var/obj/machinery/smartfridge/S = holder
if(!issilicon(L))
if(S.seconds_electrified)
if(S.shock(L, 100))
return 0
if(iscarbon(user) && S.Adjacent(user) && S.seconds_electrified && S.shock(user, 100))
return FALSE
if(S.panel_open)
return 1
return 0
return TRUE
return FALSE
/datum/wires/smartfridge/get_status()
. = ..()
@@ -38,27 +29,27 @@
. += "The red light is [S.shoot_inventory ? "off" : "blinking"]."
. += "A [S.scan_id ? "purple" : "yellow"] light is on."
/datum/wires/smartfridge/UpdatePulsed(index)
/datum/wires/smartfridge/on_pulse(wire)
var/obj/machinery/smartfridge/S = holder
switch(index)
if(SMARTFRIDGE_WIRE_THROW)
switch(wire)
if(WIRE_THROW_ITEM)
S.shoot_inventory = !S.shoot_inventory
if(SMARTFRIDGE_WIRE_ELECTRIFY)
if(WIRE_ELECTRIFY)
S.seconds_electrified = 30
if(SMARTFRIDGE_WIRE_IDSCAN)
if(WIRE_IDSCAN)
S.scan_id = !S.scan_id
..()
/datum/wires/smartfridge/UpdateCut(index, mended)
/datum/wires/smartfridge/on_cut(wire, mend)
var/obj/machinery/smartfridge/S = holder
switch(index)
if(SMARTFRIDGE_WIRE_THROW)
S.shoot_inventory = !mended
if(SMARTFRIDGE_WIRE_ELECTRIFY)
if(mended)
switch(wire)
if(WIRE_THROW_ITEM)
S.shoot_inventory = !mend
if(WIRE_ELECTRIFY)
if(mend)
S.seconds_electrified = 0
else
S.seconds_electrified = -1
if(SMARTFRIDGE_WIRE_IDSCAN)
S.scan_id = 1
if(WIRE_IDSCAN)
S.scan_id = TRUE
..()
+35 -40
View File
@@ -1,24 +1,13 @@
/datum/wires/suitstorage
holder_type = /obj/machinery/suit_storage_unit
wire_count = 8
proper_name = "Suit storage unit"
window_x = 350
window_y = 85
#define SSU_WIRE_ID 1
#define SSU_WIRE_SHOCK 2
#define SSU_WIRE_SAFETY 4
#define SSU_WIRE_UV 8
/datum/wires/suitstorage/GetWireName(index)
switch(index)
if(SSU_WIRE_ID)
return "ID lock"
if(SSU_WIRE_SHOCK)
return "Shock wire"
if(SSU_WIRE_SAFETY)
return "Safety wire"
if(SSU_WIRE_UV)
return "UV wire"
/datum/wires/suitstorage/New(atom/_holder)
wires = list(WIRE_IDSCAN, WIRE_ELECTRIFY, WIRE_SAFETY, WIRE_SSU_UV)
return ..()
/datum/wires/suitstorage/get_status()
. = ..()
@@ -28,42 +17,48 @@
. += "The green light is [A.shocked ? "on" : "off"]."
. += "The UV display shows [A.uv_super ? "15 nm" : "185 nm"]."
datum/wires/suitstorage/CanUse()
datum/wires/suitstorage/interactable(mob/user)
var/obj/machinery/suit_storage_unit/A = holder
if(iscarbon(user) && A.Adjacent(user) && A.shocked)
return A.shock(user, 100)
if(A.panel_open)
return 1
return 0
return TRUE
return FALSE
/datum/wires/suitstorage/UpdateCut(index, mended)
/datum/wires/suitstorage/on_cut(wire, mend)
var/obj/machinery/suit_storage_unit/A = holder
switch(index)
if(SSU_WIRE_ID)
A.secure = mended
if(SSU_WIRE_SAFETY)
A.safeties = mended
if(SSU_WIRE_SHOCK)
A.shocked = !mended
switch(wire)
if(WIRE_IDSCAN)
A.secure = mend
if(WIRE_SAFETY)
A.safeties = mend
if(WIRE_ELECTRIFY)
A.shocked = !mend
A.shock(usr, 50)
if(SSU_WIRE_UV)
A.uv_super = !mended
if(WIRE_SSU_UV)
A.uv_super = !mend
..()
datum/wires/suitstorage/UpdatePulsed(index)
datum/wires/suitstorage/on_pulse(wire)
var/obj/machinery/suit_storage_unit/A = holder
if(IsIndexCut(index))
if(is_cut(wire))
return
switch(index)
if(SSU_WIRE_ID)
switch(wire)
if(WIRE_IDSCAN)
A.secure = !A.secure
if(SSU_WIRE_SAFETY)
if(WIRE_SAFETY)
A.safeties = !A.safeties
if(SSU_WIRE_SHOCK)
if(WIRE_ELECTRIFY)
A.shocked = !A.shocked
if(A.shocked)
A.shock(usr, 100)
spawn(50)
if(A && !IsIndexCut(index))
A.shocked = FALSE
if(SSU_WIRE_UV)
addtimer(CALLBACK(A, /obj/machinery/suit_storage_unit/.proc/check_electrified_callback), 5 SECONDS)
if(WIRE_SSU_UV)
A.uv_super = !A.uv_super
..()
+25 -41
View File
@@ -1,47 +1,31 @@
/datum/wires/syndicatebomb
random = TRUE
randomize = TRUE
holder_type = /obj/machinery/syndicatebomb
wire_count = 5
proper_name = "Syndicate bomb"
window_x = 320
window_y = 22
#define BOMB_WIRE_BOOM 1 // Explodes if pulsed or cut while active, defuses a bomb that isn't active on cut
#define BOMB_WIRE_UNBOLT 2 // Unbolts the bomb if cut, hint on pulsed
#define BOMB_WIRE_DELAY 4 // Raises the timer on pulse, does nothing on cut
#define BOMB_WIRE_PROCEED 8 // Lowers the timer, explodes if cut while the bomb is active
#define BOMB_WIRE_ACTIVATE 16 // Will start a bombs timer if pulsed, will hint if pulsed while already active, will stop a timer a bomb on cut
/datum/wires/syndicatebomb/New(atom/_holder)
wires = list(WIRE_BOMB_DELAY, WIRE_EXPLODE, WIRE_BOMB_UNBOLT,WIRE_BOMB_PROCEED, WIRE_BOMB_ACTIVATE)
return ..()
/datum/wires/syndicatebomb/GetWireName(index)
switch(index)
if(BOMB_WIRE_BOOM)
return "Explode"
if(BOMB_WIRE_UNBOLT)
return "Unbolt"
if(BOMB_WIRE_DELAY)
return "Delay"
if(BOMB_WIRE_PROCEED)
return "Proceed"
if(BOMB_WIRE_ACTIVATE)
return "Activate"
/datum/wires/syndicatebomb/CanUse(mob/living/L)
/datum/wires/syndicatebomb/interactable(mob/user)
var/obj/machinery/syndicatebomb/P = holder
if(P.open_panel)
return TRUE
return FALSE
/datum/wires/syndicatebomb/UpdatePulsed(index)
/datum/wires/syndicatebomb/on_pulse(wire)
var/obj/machinery/syndicatebomb/B = holder
switch(index)
if(BOMB_WIRE_BOOM)
switch(wire)
if(WIRE_EXPLODE)
if(B.active)
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
if(BOMB_WIRE_UNBOLT)
if(WIRE_BOMB_UNBOLT)
holder.visible_message("<span class='notice'>[bicon(holder)] The bolts spin in place for a moment.</span>")
if(BOMB_WIRE_DELAY)
if(WIRE_BOMB_DELAY)
if(B.delayedbig)
holder.visible_message("<span class='notice'>[bicon(B)] The bomb has already been delayed.</span>")
else
@@ -49,7 +33,7 @@
playsound(B, 'sound/machines/chime.ogg', 30, 1)
B.detonation_timer += 300
B.delayedbig = TRUE
if(BOMB_WIRE_PROCEED)
if(WIRE_BOMB_PROCEED)
holder.visible_message("<span class='danger'>[bicon(B)] The bomb buzzes ominously!</span>")
playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1)
var/seconds = B.seconds_remaining()
@@ -59,7 +43,7 @@
B.detonation_timer -= 100
else if(seconds >= 11) // Both to prevent negative timers and to have a little mercy.
B.detonation_timer = world.time + 100
if(BOMB_WIRE_ACTIVATE)
if(WIRE_BOMB_ACTIVATE)
if(!B.active && !B.defused)
holder.visible_message("<span class='danger'>[bicon(B)] You hear the bomb start ticking!</span>")
B.activate()
@@ -72,11 +56,11 @@
B.delayedlittle = TRUE
..()
/datum/wires/syndicatebomb/UpdateCut(index, mended)
/datum/wires/syndicatebomb/on_cut(wire, mend)
var/obj/machinery/syndicatebomb/B = holder
switch(index)
if(BOMB_WIRE_BOOM)
if(mended)
switch(wire)
if(WIRE_EXPLODE)
if(mend)
B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage.
else
if(B.active)
@@ -84,17 +68,17 @@
B.explode_now = TRUE
else
B.defused = TRUE
if(BOMB_WIRE_UNBOLT)
if(!mended && B.anchored)
if(WIRE_BOMB_UNBOLT)
if(!mend && B.anchored)
holder.visible_message("<span class='notice'>[bicon(B)] The bolts lift out of the ground!</span>")
playsound(B, 'sound/effects/stealthoff.ogg', 30, 1)
B.anchored = FALSE
if(BOMB_WIRE_PROCEED)
if(!mended && B.active)
if(WIRE_BOMB_PROCEED)
if(!mend && B.active)
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
if(BOMB_WIRE_ACTIVATE)
if(!mended && B.active)
if(WIRE_BOMB_ACTIVATE)
if(!mend && B.active)
holder.visible_message("<span class='notice'>[bicon(B)] The timer stops! The bomb has been defused!</span>")
B.defused = TRUE
B.update_icon()
+12 -12
View File
@@ -1,23 +1,23 @@
/datum/wires/tesla_coil
wire_count = 1
holder_type = /obj/machinery/power/tesla_coil
proper_name = "Tesla coil"
window_x = 320
window_y = 50
#define TESLACOIL_WIRE_ZAP 1
/datum/wires/tesla_coil/New(atom/_holder)
wires = list(WIRE_TESLACOIL_ZAP)
return ..()
/datum/wires/tesla_coil/GetWireName(index)
switch(index)
if(TESLACOIL_WIRE_ZAP)
return "Zap"
/datum/wires/tesla_coil/CanUse(mob/living/L)
/datum/wires/tesla_coil/interactable(mob/user)
var/obj/machinery/power/tesla_coil/T = holder
if(T && T.panel_open)
return 1
return 0
return TRUE
return FALSE
/datum/wires/tesla_coil/UpdatePulsed(index)
/datum/wires/tesla_coil/on_pulse(wire)
var/obj/machinery/power/tesla_coil/T = holder
switch(index)
if(TESLACOIL_WIRE_ZAP)
switch(wire)
if(WIRE_TESLACOIL_ZAP)
T.zap()
..()
+26 -40
View File
@@ -1,35 +1,21 @@
/datum/wires/vending
holder_type = /obj/machinery/vending
wire_count = 4
window_y = 112
window_x = 350
proper_name = "Vending machine"
#define VENDING_WIRE_THROW 1
#define VENDING_WIRE_CONTRABAND 2
#define VENDING_WIRE_ELECTRIFY 4
#define VENDING_WIRE_IDSCAN 8
/datum/wires/vending/New(atom/_holder)
wires = list(WIRE_THROW_ITEM, WIRE_IDSCAN, WIRE_ELECTRIFY, WIRE_CONTRABAND)
return ..()
/datum/wires/vending/GetWireName(index)
switch(index)
if(VENDING_WIRE_THROW)
return "Item Throw"
if(VENDING_WIRE_CONTRABAND)
return "Contraband"
if(VENDING_WIRE_ELECTRIFY)
return "Electrification"
if(VENDING_WIRE_IDSCAN)
return "ID Scan"
/datum/wires/vending/CanUse(mob/living/L)
/datum/wires/vending/interactable(mob/user)
var/obj/machinery/vending/V = holder
if(!istype(L, /mob/living/silicon))
if(V.seconds_electrified)
if(V.shock(L, 100))
return 0
if(!istype(user, /mob/living/silicon) && V.seconds_electrified && V.shock(user, 100))
return FALSE
if(V.panel_open)
return 1
return 0
return TRUE
return FALSE
/datum/wires/vending/get_status()
. = ..()
@@ -39,31 +25,31 @@
. += "The green light is [V.extended_inventory ? "on" : "off"]."
. += "A [V.scan_id ? "purple" : "yellow"] light is on."
/datum/wires/vending/UpdatePulsed(index)
/datum/wires/vending/on_pulse(wire)
var/obj/machinery/vending/V = holder
switch(index)
if(VENDING_WIRE_THROW)
switch(wire)
if(WIRE_THROW_ITEM)
V.shoot_inventory = !V.shoot_inventory
if(VENDING_WIRE_CONTRABAND)
if(WIRE_CONTRABAND)
V.extended_inventory = !V.extended_inventory
if(VENDING_WIRE_ELECTRIFY)
if(WIRE_ELECTRIFY)
V.seconds_electrified = 30
if(VENDING_WIRE_IDSCAN)
if(WIRE_IDSCAN)
V.scan_id = !V.scan_id
..()
/datum/wires/vending/UpdateCut(index, mended)
/datum/wires/vending/on_cut(wire, mend)
var/obj/machinery/vending/V = holder
switch(index)
if(VENDING_WIRE_THROW)
V.shoot_inventory = !mended
if(VENDING_WIRE_CONTRABAND)
switch(wire)
if(WIRE_THROW_ITEM)
V.shoot_inventory = !mend
if(WIRE_CONTRABAND)
V.extended_inventory = FALSE
if(VENDING_WIRE_ELECTRIFY)
if(mended)
if(WIRE_ELECTRIFY)
if(mend)
V.seconds_electrified = 0
else
V.seconds_electrified = -1
if(VENDING_WIRE_IDSCAN)
V.scan_id = 1
if(WIRE_IDSCAN)
V.scan_id = TRUE
..()
+395 -270
View File
@@ -1,331 +1,456 @@
// Wire datums. Created by Giacomand.
// Was created to replace a horrible case of copy and pasted code with no care for maintability.
// Goodbye Door wires, Cyborg wires, Vending Machine wires, Autolathe wires
// Protolathe wires, APC wires and Camera wires!
#define MAX_FLAG 65535
GLOBAL_LIST_EMPTY(same_wires)
// 12 colours, if you're adding more than 12 wires then add more colours here
GLOBAL_LIST_INIT(wireColours, list("red", "blue", "green", "black", "orange", "brown", "gold", "gray", "cyan", "navy", "purple", "pink"))
/datum/wires
/// TRUE if the wires will be different every time a new wire datum is created.
var/randomize = FALSE
/// The atom the wires belong too. For example: an airlock.
var/atom/holder
/// The holder type; used to make sure that the holder is the correct type.
var/holder_type
/// The display name for the TGUI window. For example, given the var is "APC"...
/// When the TGUI window is opened, "wires" will be appended to it's title, and it would become "APC wires".
var/proper_name = "Unknown"
/// The total number of wires that our holder atom has.
var/wire_count = NONE
/// A list of all wires. For a list of valid wires defines that can go here, see `code/__DEFINES/wires.dm`
var/list/wires
/// A list of all cut wires. The same values that can go into `wires` will get added and removed from this list.
var/list/cut_wires
/// An associative list with the wire color as the key, and the wire define as the value.
var/list/colors
/// An associative list of signalers attached to the wires. The wire color is the key, and the signaler object reference is the value.
var/list/assemblies
/// The width of the wire TGUI window.
var/window_x = 300
/// The height of the wire TGUI window. Will get longer as needed, based on the `wire_count`.
var/window_y = 100
var/random = 0 // Will the wires be different for every single instance.
var/atom/holder = null // The holder
var/holder_type = null // The holder type; used to make sure that the holder is the correct type.
var/wire_count = 0 // Max is 16
var/wires_status = 0 // BITFLAG OF WIRES
var/list/wires = list()
var/list/signallers = list()
var/table_options = " align='center'"
var/row_options1 = " width='80px'"
var/row_options2 = " width='260px'"
var/window_x = 370
var/window_y = 470
/datum/wires/New(atom/holder)
/datum/wires/New(atom/_holder)
..()
src.holder = holder
if(!istype(holder, holder_type))
if(!istype(_holder, holder_type))
CRASH("Our holder is null/the wrong type!")
// Generate new wires
if(random)
GenerateWires()
// Get the same wires
holder = _holder
cut_wires = list()
colors = list()
assemblies = list()
// Add in the appropriate amount of dud wires.
var/wire_len = length(wires)
if(wire_len < wire_count) // If the amount of "real" wires is less than the total we're suppose to have...
add_duds(wire_count - wire_len) // Add in the appropriate amount of duds to reach `wire_count`.
// If the randomize is true, we need to generate a new set of wires and ignore any wire color directories.
if(randomize)
randomize()
return
if(!GLOB.wire_color_directory[holder_type])
randomize()
GLOB.wire_color_directory[holder_type] = colors
else
// We don't have any wires to copy yet, generate some and then copy it.
if(!GLOB.same_wires[holder_type])
GenerateWires()
GLOB.same_wires[holder_type] = src.wires.Copy()
else
var/list/wires = GLOB.same_wires[holder_type]
src.wires = wires // Reference the wires list.
colors = GLOB.wire_color_directory[holder_type]
/datum/wires/Destroy()
holder = null
for(var/color in colors)
detach_assembly(color)
return ..()
/datum/wires/proc/GenerateWires()
var/list/colours_to_pick = GLOB.wireColours.Copy() // Get a copy, not a reference.
var/list/indexes_to_pick = list()
//Generate our indexes
for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
indexes_to_pick += i
colours_to_pick.len = wire_count // Downsize it to our specifications.
/**
* Randomly generates a new set of wires. and corresponding colors from the given pool. Assigns the information as an associative list, to `colors`.
*
* In the `colors` list, the name of the color is the key, and the wire is the value.
* For example: `colors["red"] = WIRE_ELECTRIFY`. This will look like `list("red" = WIRE_ELECTRIFY)` internally.
*/
datum/wires/proc/randomize()
var/static/list/possible_colors = list("red", "blue", "green", "silver", "orange", "brown", "gold", "white", "cyan", "magenta", "purple", "pink")
var/list/my_possible_colors = possible_colors.Copy()
while(colours_to_pick.len && indexes_to_pick.len)
// Pick and remove a colour
var/colour = pick_n_take(colours_to_pick)
// Pick and remove an index
var/index = pick_n_take(indexes_to_pick)
src.wires[colour] = index
//wires = shuffle(wires)
/datum/wires/proc/get_status()
return list()
for(var/wire in shuffle(wires))
colors[pick_n_take(my_possible_colors)] = wire
/**
* Proc called when the user attempts to interact with wires UI.
*
* Checks if the user exists, is a mob, the wires are attached to something (`holder`) and makes sure `interactable(user)` returns TRUE.
* If all the checks succeed, open the TGUI interface for the user.
*
* Arugments:
* * user - the mob trying to interact with the wires.
*/
/datum/wires/proc/Interact(mob/user)
if(user && istype(user) && holder && CanUse(user))
ui_interact(user)
if(user && istype(user) && holder && interactable(user))
tgui_interact(user)
/datum/wires/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/**
* Base proc, intended to be overriden. Wire datum specific checks you want to run before the TGUI is shown to the user should go here.
*/
/datum/wires/proc/interactable(mob/user)
return TRUE
/// Users will be interacting with our holder object and not the wire datum directly, therefore we need to return the holder.
/datum/wires/tgui_host()
return holder
/datum/wires/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_physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "wires.tmpl", holder.name, window_x, window_y)
ui = new(user, src, ui_key, "Wires", "[proper_name] wires", window_x, window_y + wire_count * 30, master_ui, state)
ui.open()
/datum/wires/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.physical_state)
var/data[0]
var/list/replace_colours = null
/datum/wires/tgui_data(mob/user)
var/list/data = list()
var/list/replace_colors
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes)
if(eyes && (COLOURBLIND in H.mutations))
replace_colours = eyes.replace_colours
if(eyes && (COLOURBLIND in H.mutations)) // Check if the human has colorblindness.
replace_colors = eyes.replace_colours // Get the colorblind replacement colors list.
var/list/wires_list = list()
var/list/W[0]
for(var/colour in wires)
var/new_colour = colour
var/colour_name = colour
if(colour in replace_colours)
new_colour = replace_colours[colour]
if(new_colour in LIST_REPLACE_RENAME)
colour_name = LIST_REPLACE_RENAME[new_colour]
for(var/color in colors)
var/replaced_color = color
var/color_name = color
if(color in replace_colors) // If this color is one that needs to be replaced using the colorblindness list.
replaced_color = replace_colors[color]
if(replaced_color in LIST_COLOR_RENAME) // If its an ugly written color name like "darkolivegreen", rename it to something like "dark green".
color_name = LIST_COLOR_RENAME[replaced_color]
else
colour_name = new_colour
else
new_colour = colour
colour_name = new_colour
W[++W.len] = list("colour_name" = capitalize(colour_name), "seen_colour" = capitalize(new_colour),"colour" = capitalize(colour), "cut" = IsColourCut(colour), "index" = can_see_wire_index(user) ? GetWireName(GetIndex(colour)) : null, "attached" = IsAttached(colour))
color_name = replaced_color // Else just keep the normal color name
if(W.len > 0)
data["wires"] = W
wires_list += list(list(
"seen_color" = replaced_color, // The color of the wire that the mob will see. This will be the same as `color` if the user is NOT colorblind.
"color_name" = color_name, // The wire's name. This will be the same as `color` if the user is NOT colorblind.
"color" = color, // The "real" color of the wire. No replacements.
"wire" = can_see_wire_info(user) && !is_dud_color(color) ? get_wire(color) : null, // Wire define information like "Contraband" or "Door Bolts".
"cut" = is_color_cut(color), // Whether the wire is cut or not. Used to display "cut" or "mend".
"attached" = is_attached(color) // Whether or not a signaler is attached to this wire.
))
data["wires"] = wires_list
// Get the information shown at the bottom of wire TGUI window, such as "The red light is blinking", etc.
// If the user is colorblind, we need to replace these colors as well.
var/list/status = get_status()
if(replace_colours)
var/i
for(i=1, i<=status.len, i++)
for(var/colour in replace_colours)
var/new_colour = replace_colours[colour]
if(new_colour in LIST_REPLACE_RENAME)
new_colour = LIST_REPLACE_RENAME[new_colour]
if(findtext(status[i],colour))
status[i] = replacetext(status[i],colour,new_colour)
break
data["status_len"] = status.len
data["status"] = status
if(replace_colors)
var/i
for(i in 1 to length(status))
for(var/color in replace_colors)
var/new_color = replace_colors[color]
if(new_color in LIST_COLOR_RENAME)
new_color = LIST_COLOR_RENAME[new_color]
if(findtext(status[i], color))
status[i] = replacetext(status[i], color, new_color)
break
data["status"] = status
return data
/datum/wires/nano_host()
return holder
/datum/wires/tgui_act(action, list/params)
if(..())
return
/datum/wires/proc/can_see_wire_index(mob/user)
var/mob/user = usr
if(!interactable(user))
return
var/obj/item/I = user.get_active_hand()
var/color = lowertext(params["wire"])
holder.add_hiddenprint(user)
switch(action)
// Toggles the cut/mend status.
if("cut")
if(!istype(I, /obj/item/wirecutters) && !user.can_admin_interact())
to_chat(user, "<span class='error'>You need wirecutters!</span>")
return
if(istype(I))
playsound(holder, I.usesound, 20, 1)
cut_color(color)
return TRUE
// Pulse a wire.
if("pulse")
if(!istype(I, /obj/item/multitool) && !user.can_admin_interact())
to_chat(user, "<span class='error'>You need a multitool!</span>")
return
playsound(holder, 'sound/weapons/empty.ogg', 20, 1)
pulse_color(color)
// If they pulse the electrify wire, call interactable() and try to shock them.
if(get_wire(color) == WIRE_ELECTRIFY)
interactable(user)
return TRUE
// Attach a signaler to a wire.
if("attach")
if(is_attached(color))
var/obj/item/O = detach_assembly(color)
if(O)
user.put_in_hands(O)
return TRUE
if(!istype(I, /obj/item/assembly/signaler))
to_chat(user, "<span class='error'>You need a remote signaller!</span>")
return
if(user.drop_item())
attach_assembly(color, I)
return TRUE
else
to_chat(user, "<span class='warning'>[user.get_active_hand()] is stuck to your hand!</span>")
/**
* Proc called to determine if the user can see wire define information, such as "Contraband", "Door Bolts", etc.
*
* If the user is an admin, or has a multitool which reveals wire information in their active hand, the proc returns TRUE.
*
* Arguments:
* * user - the mob who is interacting with the wires.
*/
/datum/wires/proc/can_see_wire_info(mob/user)
if(user.can_admin_interact())
return TRUE
else if(istype(user.get_active_hand(), /obj/item/multitool))
var/obj/item/multitool/M = user.get_active_hand()
if(M.shows_wire_information)
return TRUE
return FALSE
/datum/wires/Topic(href, href_list)
if(..())
return 1
var/mob/L = usr
if(CanUse(L) && href_list["action"])
var/obj/item/I = L.get_active_hand()
var/colour = lowertext(href_list["wire"])
holder.add_hiddenprint(L)
switch(href_list["action"])
if("cut") // Toggles the cut/mend status
if(istype(I, /obj/item/wirecutters) || L.can_admin_interact())
if(istype(I))
playsound(holder, I.usesound, 20, 1)
CutWireColour(colour)
else
to_chat(L, "<span class='error'>You need wirecutters!</span>")
if("pulse")
if(istype(I, /obj/item/multitool) || L.can_admin_interact())
playsound(holder, 'sound/weapons/empty.ogg', 20, 1)
PulseColour(colour)
else
to_chat(L, "<span class='error'>You need a multitool!</span>")
if("attach")
if(IsAttached(colour))
var/obj/item/O = Detach(colour)
if(O)
L.put_in_hands(O)
else
if(istype(I, /obj/item/assembly/signaler))
if(L.drop_item())
Attach(colour, I)
else
to_chat(L, "<span class='warning'>[L.get_active_hand()] is stuck to your hand!</span>")
else
to_chat(L, "<span class='error'>You need a remote signaller!</span>")
/**
* Base proc, intended to be overwritten. Put wire information you'll see at the botton of the TGUI window here, such as "The red light is blinking".
*/
/datum/wires/proc/get_status()
return list()
SSnanoui.update_uis(src)
return 1
/**
* Clears the `colors` list, and randomizes it to a new set of color-to-wire relations.
*/
/datum/wires/proc/shuffle_wires()
colors.Cut()
randomize()
//
// Overridable Procs
//
/**
* Repairs all cut wires.
*/
/datum/wires/proc/repair()
cut_wires.Cut()
// Called when wires cut/mended.
/datum/wires/proc/UpdateCut(index, mended)
if(holder)
SSnanoui.update_uis(holder)
/**
* Adds in dud wires, which do nothing when cut/pulsed.
*
* Arguments:
* * duds - the amount of dud wires to generate.
*/
/datum/wires/proc/add_duds(duds)
while(duds)
var/dud = WIRE_DUD_PREFIX + "[--duds]"
if(dud in wires)
continue
wires += dud
// Called when wire pulsed. Add code here.
/datum/wires/proc/UpdatePulsed(index)
if(holder)
SSnanoui.update_uis(holder)
/**
* Determines if the passed in wire is a dud or not. Returns TRUE if the wire is a dud, FALSE otherwise.
*
* Arugments:
* * wire - a wire define, NOT a color. For example `WIRE_ELECTRIFY`.
*/
/datum/wires/proc/is_dud(wire)
return findtext(wire, WIRE_DUD_PREFIX, 1, length(WIRE_DUD_PREFIX) + 1)
/datum/wires/proc/CanUse(mob/L)
return 1
/**
* Returns TRUE if the wire that corresponds to the passed in color is a dud. FALSE otherwise.
*
* Arugments:
* * color - a wire color.
*/
/datum/wires/proc/is_dud_color(color)
return is_dud(get_wire(color))
/datum/wires/CanUseTopic(mob/user, datum/topic_state/state)
if(!holder || !CanUse(user))
return STATUS_CLOSE
return ..()
/**
* Gets the wire associated with the color passed in.
*
* Arugments:
* * color - a wire color.
*/
/datum/wires/proc/get_wire(color)
return colors[color]
// Example of use:
/*
/**
* Determines if the passed in wire is cut or not. Returns TRUE if it's cut, FALSE otherwise.
*
* Arugments:
* * wire - a wire define, NOT a color. For example `WIRE_ELECTRIFY`.
*/
/datum/wires/proc/is_cut(wire)
return (wire in cut_wires)
#define NAME_WIRE_BOLTED 1
#define NAME_WIRE_SHOCKED 2
#define NAME_WIRE_SAFETY 4
#define NAME_WIRE_POWER 8
/**
* Determines if the wire associated with the passed in color, is cut or not. Returns TRUE if it's cut, FALSE otherwise.
*
* Arugments:
* * wire - a wire color.
*/
/datum/wires/proc/is_color_cut(color)
return is_cut(get_wire(color))
/datum/wires/door/UpdateCut(var/index, var/mended)
var/obj/machinery/door/airlock/A = holder
switch(index)
if(NAME_WIRE_BOLTED)
if(!mended)
A.bolt()
if(NAME_WIRE_SHOCKED)
A.shock()
if(NAME_WIRE_SAFETY)
A.safety()
/**
* Determines if all of the wires are cut. Returns TRUE they're all cut, FALSE otherwise.
*/
/datum/wires/proc/is_all_cut()
return (length(cut_wires) == length(wires))
*/
//
// Helper Procs
//
/datum/wires/proc/PulseColour(colour)
PulseIndex(GetIndex(colour))
/datum/wires/proc/PulseIndex(index)
if(IsIndexCut(index))
return
UpdatePulsed(index)
/datum/wires/proc/GetIndex(colour)
if(wires[colour])
var/index = wires[colour]
return index
/**
* Cut or mend a wire. Calls `on_cut()`.
*
* Arugments:
* * wire - a wire define, NOT a color. For example `WIRE_ELECTRIFY`.
*/
/datum/wires/proc/cut(wire)
if(is_cut(wire))
cut_wires -= wire
on_cut(wire, mend = TRUE)
else
CRASH("[colour] is not a key in wires.")
cut_wires += wire
on_cut(wire, mend = FALSE)
/datum/wires/proc/GetWireName(index)
/**
* Cut the wire which corresponds with the passed in color.
*
* Arugments:
* * color - a wire color.
*/
/datum/wires/proc/cut_color(color)
cut(get_wire(color))
/**
* Cuts a random wire.
*/
/datum/wires/proc/cut_random()
cut(wires[rand(1, length(wires))])
/**
* Cuts all wires.
*/
/datum/wires/proc/cut_all()
for(var/wire in wires)
cut(wire)
/**
* Proc called when any wire is cut.
*
* Base proc, intended to be overriden.
* Place an behavior you want to happen when certain wires are cut, into this proc.
*
* Arugments:
* * wire - a wire define, NOT color. For example 'WIRE_ELECTRIFY'.
* * mend - TRUE if we're mending the wire. FALSE if we're cutting.
*/
/datum/wires/proc/on_cut(wire, mend = FALSE)
return
//
// Is Index/Colour Cut procs
//
/**
* Pulses the given wire. Calls `on_pulse()`.
*
* Arugments:
* * wire - a wire define, NOT a color. For example `WIRE_ELECTRIFY`.
*/
/datum/wires/proc/pulse(wire)
if(is_cut(wire))
return
on_pulse(wire)
/datum/wires/proc/IsColourCut(colour)
var/index = GetIndex(colour)
return IsIndexCut(index)
/**
* Pulses the wire associated with the given color.
*
* Arugments:
* * wire - a wire color.
*/
/datum/wires/proc/pulse_color(color)
pulse(get_wire(color))
/datum/wires/proc/IsIndexCut(index)
return (index & wires_status)
/**
* Proc called when any wire is pulsed.
*
* Base proc, intended to be overriden.
* Place behavior you want to happen when certain wires are pulsed, into this proc.
*
* Arugments:
* * wire - a wire define, NOT color. For example 'WIRE_ELECTRIFY'.
*/
/datum/wires/proc/on_pulse(wire)
return
//
// Signaller Procs
//
/**
* Proc called when an attached signaler receives a signal.
*
* Searches through the `assemblies` list for the wire that the signaler is attached to. Pulses the wire when it's found.
*
* Arugments:
* * S - the attached signaler receiving the signal.
*/
/datum/wires/proc/pulse_assembly(obj/item/assembly/signaler/S)
for(var/color in assemblies)
if(S == assemblies[color])
pulse_color(color)
return TRUE
/datum/wires/proc/IsAttached(colour)
if(signallers[colour])
return 1
return 0
/**
* Proc called when a mob tries to attach a signaler to a wire.
*
* Makes sure that `S` is actually a signaler and that something is not already attached to the wire.
* Adds the signaler to the `assemblies` list as a value, with the `color` as a the key.
*
* Arguments:
* * color - the wire color.
* * S - the signaler that a mob is trying to attach.
*/
/datum/wires/proc/attach_assembly(color, obj/item/assembly/signaler/S)
if(S && istype(S) && !is_attached(color))
assemblies[color] = S
S.forceMove(holder)
S.connected = src
return S
/datum/wires/proc/GetAttached(colour)
if(signallers[colour])
return signallers[colour]
/**
* Proc called when a mob tries to detach a signaler from a wire.
*
* First checks if there is a signaler on the wire. If so, removes the signaler, and clears it from `assemblies` list.
*
* Arguments:
* * color - the wire color.
*/
/datum/wires/proc/detach_assembly(color)
var/obj/item/assembly/signaler/S = get_attached(color)
if(S && istype(S))
assemblies -= color
S.connected = null
S.forceMove(holder.drop_location())
return S
/**
* Gets the signaler attached to the given wire color, if there is one.
*
* Arguments:
* * color - the wire color.
*/
/datum/wires/proc/get_attached(color)
if(assemblies[color])
return assemblies[color]
return null
/datum/wires/proc/Attach(colour, obj/item/assembly/signaler/S)
if(colour && S)
if(!IsAttached(colour))
signallers[colour] = S
S.loc = holder
S.connected = src
return S
/datum/wires/proc/Detach(colour)
if(colour)
var/obj/item/assembly/signaler/S = GetAttached(colour)
if(S)
signallers -= colour
S.connected = null
S.loc = holder.loc
return S
/datum/wires/proc/Pulse(obj/item/assembly/signaler/S)
for(var/colour in signallers)
if(S == signallers[colour])
PulseColour(colour)
break
//
// Cut Wire Colour/Index procs
//
/datum/wires/proc/CutWireColour(colour)
var/index = GetIndex(colour)
CutWireIndex(index)
/datum/wires/proc/CutWireIndex(index)
if(IsIndexCut(index))
wires_status &= ~index
UpdateCut(index, 1)
else
wires_status |= index
UpdateCut(index, 0)
/datum/wires/proc/RandomCut()
var/r = rand(1, wires.len)
CutWireIndex(r)
/datum/wires/proc/CutAll()
for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
CutWireIndex(i)
/datum/wires/proc/IsAllCut()
if(wires_status == (1 << wire_count) - 1)
return 1
return 0
//
//Shuffle and Mend
//
/datum/wires/proc/Shuffle()
wires_status = 0
GenerateWires()
/**
* Checks if the given wire has a signaler on it.
*
* Arguments:
* * color - the wire color.
*/
/datum/wires/proc/is_attached(color)
if(assemblies[color])
return TRUE
+10 -1
View File
@@ -1,7 +1,16 @@
// List is required to compile the resources into the game when it loads.
// Dynamically loading it has bad results with sounds overtaking each other, even with the wait variable.
GLOBAL_LIST_INIT(vox_sounds, list("," = 'sound/vox_fem/,.ogg',
GLOBAL_LIST_INIT(vox_alerts, list(
"bizwarn" = 'sound/vox_fem/bizwarn.ogg',
"bloop" = 'sound/vox_fem/bloop.ogg',
"buzwarn" = 'sound/vox_fem/buzwarn.ogg',
"dadeda" = 'sound/vox_fem/dadeda.ogg',
"deeoo" = 'sound/vox_fem/deeoo.ogg'
))
GLOBAL_LIST_INIT(vox_sounds, list(
"," = 'sound/vox_fem/,.ogg',
"." = 'sound/vox_fem/..ogg',
"a" = 'sound/vox_fem/a.ogg',
"abortions" = 'sound/vox_fem/abortions.ogg',
+2 -2
View File
@@ -50,10 +50,10 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/space/atmosalert()
return
/area/space/fire_alert()
/area/space/firealert(obj/source)
return
/area/space/fire_reset()
/area/space/firereset(obj/source)
return
/area/space/readyalert()
+19 -13
View File
@@ -1,24 +1,30 @@
/area/ai_monitored
name = "AI Monitored Area"
var/obj/machinery/camera/motioncamera = null
var/list/motioncameras = list()
var/list/motionTargets = list()
/area/ai_monitored/LateInitialize()
/area/ai_monitored/Initialize(mapload)
. = ..()
// locate and store the motioncamera
for(var/obj/machinery/camera/M in src)
if(M.isMotion())
motioncamera = M
M.area_motion = src
break
if(mapload)
for(var/obj/machinery/camera/M in src)
if(M.isMotion())
motioncameras.Add(M)
M.set_area_motion(src)
/area/ai_monitored/Entered(atom/movable/O)
..()
if(ismob(O) && motioncamera)
motioncamera.newTarget(O)
if(ismob(O) && length(motioncameras))
for(var/X in motioncameras)
var/obj/machinery/camera/cam = X
cam.newTarget(O)
return
/area/ai_monitored/Exited(atom/movable/O)
if(ismob(O) && motioncamera)
motioncamera.lostTarget(O)
..()
if(ismob(O) && length(motioncameras))
for(var/X in motioncameras)
var/obj/machinery/camera/cam = X
cam.lostTargetRef(O.UID())
return
+195 -63
View File
@@ -57,6 +57,11 @@
var/list/ambientsounds = GENERIC_SOUNDS
var/list/firedoors
var/list/cameras
var/list/firealarms
var/firedoors_last_closed_on = 0
var/fast_despawn = FALSE
var/can_get_auto_cryod = TRUE
var/hide_attacklogs = FALSE // For areas such as thunderdome, lavaland syndiebase, etc which generate a lot of spammy attacklogs. Reduces log priority.
@@ -125,35 +130,6 @@
cameras += C
return cameras
/area/proc/atmosalert(danger_level, var/alarm_source, var/force = FALSE)
if(report_alerts)
if(danger_level == ATMOS_ALARM_NONE)
SSalarms.atmosphere_alarm.clearAlarm(src, alarm_source)
else
SSalarms.atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level)
//Check all the alarms before lowering atmosalm. Raising is perfectly fine. If force = 1 we don't care.
for(var/obj/machinery/alarm/AA in src)
if(!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted && AA.report_danger_level && !force)
danger_level = max(danger_level, AA.danger_level)
if(danger_level != atmosalm)
if(danger_level < ATMOS_ALARM_WARNING && atmosalm >= ATMOS_ALARM_WARNING)
//closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise
air_doors_open()
else if(danger_level >= ATMOS_ALARM_DANGER && atmosalm < ATMOS_ALARM_DANGER)
air_doors_close()
atmosalm = danger_level
for(var/obj/machinery/alarm/AA in src)
AA.update_icon()
GLOB.air_alarm_repository.update_cache(src)
return 1
GLOB.air_alarm_repository.update_cache(src)
return 0
/area/proc/air_doors_close()
if(!air_doors_activated)
air_doors_activated = TRUE
@@ -179,44 +155,151 @@
D.open()
/area/proc/fire_alert()
if(!fire)
fire = 1 //used for firedoor checks
updateicon()
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
air_doors_close()
/area/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/area/proc/fire_reset()
if(fire)
fire = 0 //used for firedoor checks
updateicon()
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
air_doors_open()
/**
* Generate a power alert for this area
*
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
*/
/area/proc/poweralert(state, obj/source)
if(state != poweralm)
poweralm = state
if(istype(source)) //Only report power alarms on the z-level where the source is located.
for(var/thing in cameras)
var/obj/machinery/camera/C = locateUID(thing)
if(!QDELETED(C) && is_station_level(C.z))
if(state)
C.network -= "Power Alarms"
else
C.network |= "Power Alarms"
return
if(state)
SSalarm.cancelAlarm("Power", src, source)
else
SSalarm.triggerAlarm("Power", src, cameras, source)
/area/proc/burglaralert(var/obj/trigger)
if(always_unpowered == 1) //no burglar alarms in space/asteroid
/**
* Generate an atmospheric alert for this area
*
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
*/
/area/proc/atmosalert(danger_level, obj/source)
if(danger_level != atmosalm)
if(danger_level == ATMOS_ALARM_DANGER)
for(var/thing in cameras)
var/obj/machinery/camera/C = locateUID(thing)
if(!QDELETED(C) && is_station_level(C.z))
C.network |= "Atmosphere Alarms"
SSalarm.triggerAlarm("Atmosphere", src, cameras, source)
else if(atmosalm == ATMOS_ALARM_DANGER)
for(var/thing in cameras)
var/obj/machinery/camera/C = locateUID(thing)
if(!QDELETED(C) && is_station_level(C.z))
C.network -= "Atmosphere Alarms"
SSalarm.cancelAlarm("Atmosphere", src, source)
atmosalm = danger_level
return TRUE
return FALSE
/**
* Try to close all the firedoors in the area
*/
/area/proc/ModifyFiredoors(opening)
if(firedoors)
firedoors_last_closed_on = world.time
for(var/FD in firedoors)
var/obj/machinery/door/firedoor/D = FD
var/cont = !D.welded
if(cont && opening) //don't open if adjacent area is on fire
for(var/I in D.affecting_areas)
var/area/A = I
if(A.fire)
cont = FALSE
break
if(cont && D.is_operational())
if(D.operating)
D.nextstate = opening ? FD_OPEN : FD_CLOSED
else if(!(D.density ^ opening))
INVOKE_ASYNC(D, (opening ? /obj/machinery/door/firedoor.proc/open : /obj/machinery/door/firedoor.proc/close))
/**
* Generate a firealarm alert for this area
*
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
*
* Also starts the area processing on SSobj
*/
/area/proc/firealert(obj/source)
if(always_unpowered) //no fire alarms in space/asteroid
return
//Trigger alarm effect
set_fire_alarm_effect()
if(!fire)
set_fire_alarm_effect()
ModifyFiredoors(FALSE)
for(var/item in firealarms)
var/obj/machinery/firealarm/F = item
F.update_icon()
//Lockdown airlocks
for(var/obj/machinery/door/airlock/A in src)
spawn(0)
A.close()
if(A.density)
A.lock()
for(var/thing in cameras)
var/obj/machinery/camera/C = locateUID(thing)
if(!QDELETED(C) && is_station_level(C.z))
C.network |= "Fire Alarms"
SSalarms.burglar_alarm.triggerAlarm(src, trigger)
spawn(600)
SSalarms.burglar_alarm.clearAlarm(src, trigger)
SSalarm.triggerAlarm("Fire", src, cameras, source)
/area/proc/set_fire_alarm_effect()
fire = 1
updateicon()
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
START_PROCESSING(SSobj, src)
/**
* Reset the firealarm alert for this area
*
* resets the alert sent to all ai players, alert consoles, drones and alarm monitor programs
* in the world
*
* Also cycles the icons of all firealarms and deregisters the area from processing on SSOBJ
*/
/area/proc/firereset(obj/source)
if(fire)
unset_fire_alarm_effects()
ModifyFiredoors(TRUE)
for(var/item in firealarms)
var/obj/machinery/firealarm/F = item
F.update_icon()
for(var/thing in cameras)
var/obj/machinery/camera/C = locateUID(thing)
if(!QDELETED(C) && is_station_level(C.z))
C.network -= "Fire Alarms"
SSalarm.cancelAlarm("Fire", src, source)
STOP_PROCESSING(SSobj, src)
/**
* If 100 ticks has elapsed, toggle all the firedoors closed again
*/
/area/process()
if(firedoors_last_closed_on + 100 < world.time) //every 10 seconds
ModifyFiredoors(FALSE)
/**
* Close and lock a door passed into this proc
*
* Does this need to exist on area? probably not
*/
/area/proc/close_and_lock_door(obj/machinery/door/DOOR)
set waitfor = FALSE
DOOR.close()
if(DOOR.density)
DOOR.lock()
/area/proc/readyalert()
if(!eject)
@@ -240,13 +323,62 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
updateicon()
/**
* Raise a burglar alert for this area
*
* Close and locks all doors in the area and alerts silicon mobs of a break in
*
* Alarm auto resets after 600 ticks
*/
/area/proc/burglaralert(obj/trigger)
if(always_unpowered) //no burglar alarms in space/asteroid
return
//Trigger alarm effect
set_fire_alarm_effect()
//Lockdown airlocks
for(var/obj/machinery/door/DOOR in src)
close_and_lock_door(DOOR)
if(SSalarm.triggerAlarm("Burglar", src, cameras, trigger))
//Cancel silicon alert after 1 minute
addtimer(CALLBACK(SSalarm, /datum/controller/subsystem/alarm.proc/cancelAlarm, "Burglar", src, trigger), 600)
/**
* Trigger the fire alarm visual affects in an area
*
* Updates the fire light on fire alarms in the area and sets all lights to emergency mode
*/
/area/proc/set_fire_alarm_effect()
fire = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
for(var/alarm in firealarms)
var/obj/machinery/firealarm/F = alarm
F.update_fire_light(fire)
for(var/obj/machinery/light/L in src)
L.update()
/**
* unset the fire alarm visual affects in an area
*
* Updates the fire light on fire alarms in the area and sets all lights to emergency mode
*/
/area/proc/unset_fire_alarm_effects()
fire = FALSE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
for(var/alarm in firealarms)
var/obj/machinery/firealarm/F = alarm
F.update_fire_light(fire)
for(var/obj/machinery/light/L in src)
L.update()
/area/proc/updateicon()
if((fire || eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
if(fire && !eject && !party)
if((eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
if(!eject && !party)
icon_state = "red"
else if(!fire && eject && !party)
else if(eject && !party)
icon_state = "red"
else if(party && !fire && !eject)
else if(party && !eject)
icon_state = "party"
else
icon_state = "blue-red"
+13 -5
View File
@@ -61,7 +61,7 @@
/atom/movable/proc/get_cell()
return
/atom/movable/proc/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
/atom/movable/proc/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
if(QDELETED(AM))
return FALSE
if(!(AM.can_be_pulled(src, state, force)))
@@ -87,7 +87,7 @@
if(ismob(AM))
var/mob/M = AM
add_attack_logs(src, M, "passively grabbed", ATKLOG_ALMOSTALL)
if(!supress_message)
if(show_message)
visible_message("<span class='warning'>[src] has grabbed [M] passively!</span>")
return TRUE
@@ -120,12 +120,18 @@
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
/atom/movable/proc/can_be_pulled(user, grab_state, force)
/atom/movable/proc/can_be_pulled(user, grab_state, force, show_message = FALSE)
if(src == user || !isturf(loc))
return FALSE
if(anchored || throwing)
if(anchored || move_resist == INFINITY)
if(show_message)
to_chat(user, "<span class='warning'>[src] appears to be anchored to the ground!</span>")
return FALSE
if(throwing)
return FALSE
if(force < (move_resist * MOVE_FORCE_PULL_RATIO))
if(show_message)
to_chat(user, "<span class='warning'>[src] is too heavy to pull!</span>")
return FALSE
return TRUE
@@ -506,6 +512,7 @@
return //don't do an animation if attacking self
var/pixel_x_diff = 0
var/pixel_y_diff = 0
var/direction = get_dir(src, A)
if(direction & NORTH)
pixel_y_diff = 8
@@ -525,7 +532,8 @@
if(visual_effect_icon)
I = image('icons/effects/effects.dmi', A, visual_effect_icon, A.layer + 0.1)
else if(used_item)
I = image(used_item.icon, A, used_item.icon_state, A.layer + 0.1)
I = image(icon = used_item, loc = A, layer = A.layer + 0.1)
I.plane = GAME_PLANE
// Scale the icon.
I.transform *= 0.75
+343 -403
View File
@@ -7,6 +7,11 @@
#define NEGATE_MUTATION_THRESHOLD 30 // Occupants with over ## percent radiation threshold will not gain mutations
#define PAGE_UI "ui"
#define PAGE_SE "se"
#define PAGE_BUFFER "buffer"
#define PAGE_REJUVENATORS "rejuvenators"
//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
/datum/dna2/record
var/datum/dna/dna = null
@@ -161,6 +166,7 @@
occupant = usr
icon_state = "scanner_occupied"
add_fingerprint(usr)
SStgui.update_uis(src)
/obj/machinery/dna_scannernew/MouseDrop_T(atom/movable/O, mob/user)
if(!istype(O))
@@ -214,6 +220,7 @@
return
beaker = I
SStgui.update_uis(src)
I.forceMove(src)
user.visible_message("[user] adds \a [I] to \the [src]!", "You add \a [I] to \the [src]!")
return
@@ -260,6 +267,7 @@
M.forceMove(src)
occupant = M
icon_state = "scanner_occupied"
SStgui.update_uis(src)
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
@@ -281,6 +289,7 @@
occupant.forceMove(loc)
occupant = null
icon_state = "scanner_open"
SStgui.update_uis(src)
/obj/machinery/dna_scannernew/force_eject_occupant()
go_out(null, TRUE)
@@ -296,6 +305,7 @@
occupant = null
updateUsrDialog()
update_icon()
SStgui.update_uis(src)
// Checks if occupants can be irradiated/mutated - prevents exploits where wearing full rad protection would still let you gain mutations
/obj/machinery/dna_scannernew/proc/radiation_check()
@@ -333,12 +343,11 @@
var/injector_ready = FALSE //Quick fix for issue 286 (screwdriver the screen twice to restore injector) -Pete
var/obj/machinery/dna_scannernew/connected = null
var/obj/item/disk/data/disk = null
var/selected_menu_key = null
var/selected_menu_key = PAGE_UI
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 400
var/waiting_for_user_input = 0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X
/obj/machinery/computer/scan_consolenew/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/disk/data)) //INSERT SOME diskS
@@ -347,7 +356,7 @@
I.forceMove(src)
disk = I
to_chat(user, "You insert [I].")
SSnanoui.update_uis(src) // update all UIs attached to src()
SStgui.update_uis(src)
return
else
return ..()
@@ -399,35 +408,18 @@
if(stat & (NOPOWER|BROKEN))
return
ui_interact(user)
tgui_interact(user)
/**
* The ui_interact proc is used to open and update Nano UIs
* If ui_interact is not used then the UI will not update correctly
* ui_interact is currently defined for /atom/movable
*
* @param user /mob The mob who is interacting with this ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
*
* @return nothing
*/
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
/obj/machinery/computer/scan_consolenew/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)
if(user == connected.occupant)
return
// update the ui if it exists, returns null if no ui is passed/found
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)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "dna_modifier.tmpl", "DNA Modifier Console", 660, 700)
// open the new ui window
ui = new(user, src, ui_key, "DNAModifier", name, 660, 700, master_ui, state)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/computer/scan_consolenew/ui_data(mob/user, datum/topic_state/state)
/obj/machinery/computer/scan_consolenew/tgui_data(mob/user)
var/data[0]
data["selectedMenuKey"] = selected_menu_key
data["locked"] = connected.locked
@@ -501,9 +493,12 @@
for(var/datum/reagent/R in connected.beaker.reagents.reagent_list)
data["beakerVolume"] += R.volume
// Transfer modal information if there is one
data["modal"] = tgui_modal_data(src)
return data
/obj/machinery/computer/scan_consolenew/Topic(href, href_list)
/obj/machinery/computer/scan_consolenew/tgui_act(action, params)
if(..())
return FALSE // don't update uis
if(!istype(usr.loc, /turf))
@@ -512,405 +507,350 @@
return FALSE // don't update uis
if(irradiating) // Make sure that it isn't already irradiating someone...
return FALSE // don't update uis
if(stat & (NOPOWER|BROKEN))
return
add_fingerprint(usr)
if(href_list["selectMenuKey"])
selected_menu_key = href_list["selectMenuKey"]
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["toggleLock"])
if((connected && connected.occupant))
connected.locked = !(connected.locked)
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["pulseRadiation"])
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SSnanoui.update_uis(src) // update all UIs attached to src
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
if(!connected.occupant)
return TRUE // return 1 forces an update to all Nano uis attached to src
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return TRUE
if(prob(95))
if(prob(75))
randmutb(connected.occupant)
else
randmuti(connected.occupant)
else
if(prob(95))
randmutg(connected.occupant)
else
randmuti(connected.occupant)
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["radiationDuration"])
if(text2num(href_list["radiationDuration"]) > 0)
if(radiation_duration < 20)
radiation_duration += 2
else
if(radiation_duration > 2)
radiation_duration -= 2
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["radiationIntensity"])
if(text2num(href_list["radiationIntensity"]) > 0)
if(radiation_intensity < 10)
radiation_intensity++
else
if(radiation_intensity > 1)
radiation_intensity--
return TRUE // return 1 forces an update to all Nano uis attached to src
////////////////////////////////////////////////////////
if(href_list["changeUITarget"] && text2num(href_list["changeUITarget"]) > 0)
if(selected_ui_target < 15)
selected_ui_target++
selected_ui_target_hex = selected_ui_target
switch(selected_ui_target)
if(10)
selected_ui_target_hex = "A"
if(11)
selected_ui_target_hex = "B"
if(12)
selected_ui_target_hex = "C"
if(13)
selected_ui_target_hex = "D"
if(14)
selected_ui_target_hex = "E"
if(15)
selected_ui_target_hex = "F"
else
selected_ui_target = 0
selected_ui_target_hex = 0
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["changeUITarget"] && text2num(href_list["changeUITarget"]) < 1)
if(selected_ui_target > 0)
selected_ui_target--
selected_ui_target_hex = selected_ui_target
switch(selected_ui_target)
if(10)
selected_ui_target_hex = "A"
if(11)
selected_ui_target_hex = "B"
if(12)
selected_ui_target_hex = "C"
if(13)
selected_ui_target_hex = "D"
if(14)
selected_ui_target_hex = "E"
else
selected_ui_target = 15
selected_ui_target_hex = "F"
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["selectUIBlock"] && href_list["selectUISubblock"]) // This chunk of code updates selected block / sub-block based on click
var/select_block = text2num(href_list["selectUIBlock"])
var/select_subblock = text2num(href_list["selectUISubblock"])
if((select_block <= DNA_UI_LENGTH) && (select_block >= 1))
selected_ui_block = select_block
if((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
selected_ui_subblock = select_subblock
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["pulseUIRadiation"])
var/block = connected.occupant.dna.GetUISubBlock(selected_ui_block, selected_ui_subblock)
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SSnanoui.update_uis(src) // update all UIs attached to src
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
if(!connected.occupant)
return TRUE
if(prob((80 + (radiation_duration / 2))))
var/radiation = (radiation_intensity + radiation_duration)
connected.occupant.apply_effect(radiation,IRRADIATE,0)
if(connected.radiation_check())
return TRUE
block = miniscrambletarget(num2text(selected_ui_target), radiation_intensity, radiation_duration)
connected.occupant.dna.SetUISubBlock(selected_ui_block, selected_ui_subblock, block)
connected.occupant.UpdateAppearance()
else
var/radiation = ((radiation_intensity * 2) + radiation_duration)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return TRUE
if(prob(20 + radiation_intensity))
randmutb(connected.occupant)
domutcheck(connected.occupant, connected)
else
randmuti(connected.occupant)
connected.occupant.UpdateAppearance()
return TRUE // return 1 forces an update to all Nano uis attached to src
////////////////////////////////////////////////////////
if(href_list["injectRejuvenators"])
if(!connected.occupant)
return FALSE
var/inject_amount = round(text2num(href_list["injectRejuvenators"]), 5) // round to nearest 5
if(inject_amount < 0) // Since the user can actually type the commands himself, some sanity checking
inject_amount = 0
if(inject_amount > 50)
inject_amount = 50
connected.beaker.reagents.trans_to(connected.occupant, inject_amount)
connected.beaker.reagents.reaction(connected.occupant)
return TRUE // return 1 forces an update to all Nano uis attached to src
////////////////////////////////////////////////////////
if(href_list["selectSEBlock"] && href_list["selectSESubblock"]) // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes)
var/select_block = text2num(href_list["selectSEBlock"])
var/select_subblock = text2num(href_list["selectSESubblock"])
if((select_block <= DNA_SE_LENGTH) && (select_block >= 1))
selected_se_block = select_block
if((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
selected_se_subblock = select_subblock
//testing("User selected block [selected_se_block] (sent [select_block]), subblock [selected_se_subblock] (sent [select_block]).")
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["pulseSERadiation"])
var/block = connected.occupant.dna.GetSESubBlock(selected_se_block, selected_se_subblock)
//var/original_block=block
//testing("Irradiating SE block [selected_se_block]:[selected_se_subblock] ([block])...")
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SSnanoui.update_uis(src) // update all UIs attached to src
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
if(connected.occupant)
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return 1
var/real_SE_block=selected_se_block
block = miniscramble(block, radiation_intensity, radiation_duration)
if(prob(20))
if(selected_se_block > 1 && selected_se_block < DNA_SE_LENGTH/2)
real_SE_block++
else if(selected_se_block > DNA_SE_LENGTH/2 && selected_se_block < DNA_SE_LENGTH)
real_SE_block--
//testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block)
domutcheck(connected.occupant, connected)
else
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return 1
if(prob(80 - radiation_duration))
//testing("Random bad mut!")
randmutb(connected.occupant)
domutcheck(connected.occupant, connected)
else
randmuti(connected.occupant)
//testing("Random identity mut!")
connected.occupant.UpdateAppearance()
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["ejectBeaker"])
if(connected.beaker)
var/obj/item/reagent_containers/glass/B = connected.beaker
B.forceMove(connected.loc)
connected.beaker = null
if(tgui_act_modal(action, params))
return TRUE
if(href_list["ejectOccupant"])
connected.eject_occupant(usr)
return TRUE
// Transfer Buffer Management
if(href_list["bufferOption"])
var/bufferOption = href_list["bufferOption"]
// These bufferOptions do not require a bufferId
if(bufferOption == "wipeDisk")
if((isnull(disk)) || (disk.read_only))
//temphtml = "Invalid disk. Please try again."
return FALSE
disk.buf = null
//temphtml = "Data saved."
return TRUE
if(bufferOption == "ejectDisk")
if(!disk)
. = TRUE
switch(action)
if("selectMenuKey")
var/key = params["key"]
if(!(key in list(PAGE_UI, PAGE_SE, PAGE_BUFFER, PAGE_REJUVENATORS)))
return
disk.forceMove(get_turf(src))
disk = null
return TRUE
// All bufferOptions from here on require a bufferId
if(!href_list["bufferId"])
return FALSE
var/bufferId = text2num(href_list["bufferId"])
if(bufferId < 1 || bufferId > 3)
return FALSE // Not a valid buffer id
if(bufferOption == "saveUI")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_UI // DNA2_BUF_UE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name=connected.occupant.name
databuf.name = "Unique Identifier"
buffers[bufferId] = databuf
return TRUE
if(bufferOption == "saveUIAndUE")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name=connected.occupant.dna.real_name
databuf.name = "Unique Identifier + Unique Enzymes"
buffers[bufferId] = databuf
return TRUE
if(bufferOption == "saveSE")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_SE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name = connected.occupant.dna.real_name
databuf.name = "Structural Enzymes"
buffers[bufferId] = databuf
return TRUE
if(bufferOption == "clear")
buffers[bufferId] = new /datum/dna2/record()
return TRUE
if(bufferOption == "changeLabel")
var/datum/dna2/record/buf = buffers[bufferId]
var/text = sanitize(input(usr, "New Label:", "Edit Label", buf.name) as text|null)
buf.name = text
buffers[bufferId] = buf
return TRUE
if(bufferOption == "transfer")
if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna)
return TRUE
irradiating = 2
selected_menu_key = key
if("toggleLock")
if(connected && connected.occupant)
connected.locked = !(connected.locked)
if("pulseRadiation")
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SSnanoui.update_uis(src) // update all UIs attached to src
sleep(2 SECONDS)
SStgui.update_uis(src)
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
var/radiation = (rand(20,50) / connected.damage_coeff)
if(!connected.occupant)
return
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return TRUE
return
var/datum/dna2/record/buf = buffers[bufferId]
if((buf.types & DNA2_BUF_UI))
if((buf.types & DNA2_BUF_UE))
connected.occupant.real_name = buf.dna.real_name
connected.occupant.name = buf.dna.real_name
connected.occupant.UpdateAppearance(buf.dna.UI.Copy())
else if(buf.types & DNA2_BUF_SE)
connected.occupant.dna.SE = buf.dna.SE.Copy()
connected.occupant.dna.UpdateSE()
domutcheck(connected.occupant, connected)
return TRUE
if(bufferOption == "createInjector")
if(injector_ready && !waiting_for_user_input)
var/success = 1
var/obj/item/dnainjector/I = new /obj/item/dnainjector
var/datum/dna2/record/buf = buffers[bufferId]
buf = buf.copy()
if(href_list["createBlockInjector"])
waiting_for_user_input=1
var/list/selectedbuf
if(buf.types & DNA2_BUF_SE)
selectedbuf=buf.dna.SE
else
selectedbuf=buf.dna.UI
var/blk = input(usr,"Select Block","Block") as null|anything in all_dna_blocks(selectedbuf)
success = setInjectorBlock(I,blk,buf)
if(prob(95))
if(prob(75))
randmutb(connected.occupant)
else
I.buf = buf
waiting_for_user_input = 0
if(success)
I.forceMove(loc)
I.name += " ([buf.name])"
if(connected)
I.damage_coeff = connected.damage_coeff
injector_ready = FALSE
spawn(300)
injector_ready = TRUE
return TRUE
randmuti(connected.occupant)
else
if(prob(95))
randmutg(connected.occupant)
else
randmuti(connected.occupant)
if("radiationDuration")
radiation_duration = clamp(text2num(params["value"]), 1, 20)
if("radiationIntensity")
radiation_intensity = clamp(text2num(params["value"]), 1, 10)
////////////////////////////////////////////////////////
if("changeUITarget")
selected_ui_target = clamp(text2num(params["value"]), 1, 15)
selected_ui_target_hex = num2text(selected_ui_target, 1, 16)
if("selectUIBlock") // This chunk of code updates selected block / sub-block based on click
var/select_block = text2num(params["block"])
var/select_subblock = text2num(params["subblock"])
if(!select_block || !select_subblock)
return
if(bufferOption == "loadDisk")
if((isnull(disk)) || (!disk.buf))
//temphtml = "Invalid disk. Please try again."
return FALSE
selected_ui_block = clamp(select_block, 1, DNA_UI_LENGTH)
selected_ui_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
if("pulseUIRadiation")
var/block = connected.occupant.dna.GetUISubBlock(selected_ui_block, selected_ui_subblock)
buffers[bufferId] = disk.buf.copy()
//temphtml = "Data loaded."
return TRUE
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
if(bufferOption == "saveDisk")
if((isnull(disk)) || (disk.read_only))
//temphtml = "Invalid disk. Please try again."
return FALSE
SStgui.update_uis(src)
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
var/datum/dna2/record/buf = buffers[bufferId]
irradiating = 0
connected.locked = lock_state
disk.buf = buf.copy()
disk.name = "data disk - '[buf.dna.real_name]'"
//temphtml = "Data saved."
return TRUE
if(!connected.occupant)
return
if(prob((80 + (radiation_duration / 2))))
var/radiation = (radiation_intensity + radiation_duration)
connected.occupant.apply_effect(radiation,IRRADIATE,0)
if(connected.radiation_check())
return
block = miniscrambletarget(num2text(selected_ui_target), radiation_intensity, radiation_duration)
connected.occupant.dna.SetUISubBlock(selected_ui_block, selected_ui_subblock, block)
connected.occupant.UpdateAppearance()
else
var/radiation = ((radiation_intensity * 2) + radiation_duration)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return
if(prob(20 + radiation_intensity))
randmutb(connected.occupant)
domutcheck(connected.occupant, connected)
else
randmuti(connected.occupant)
connected.occupant.UpdateAppearance()
////////////////////////////////////////////////////////
if("injectRejuvenators")
if(!connected.occupant || !connected.beaker)
return
var/inject_amount = clamp(round(text2num(params["amount"]), 5), 0, 50) // round to nearest 5 and clamp to 0-50
if(!inject_amount)
return
connected.beaker.reagents.trans_to(connected.occupant, inject_amount)
connected.beaker.reagents.reaction(connected.occupant)
////////////////////////////////////////////////////////
if("selectSEBlock") // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes)
var/select_block = text2num(params["block"])
var/select_subblock = text2num(params["subblock"])
if(!select_block || !select_subblock)
return
selected_se_block = clamp(select_block, 1, DNA_SE_LENGTH)
selected_se_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
if("pulseSERadiation")
var/block = connected.occupant.dna.GetSESubBlock(selected_se_block, selected_se_subblock)
//var/original_block=block
//testing("Irradiating SE block [selected_se_block]:[selected_se_subblock] ([block])...")
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SStgui.update_uis(src)
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
if(connected.occupant)
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return 1
var/real_SE_block=selected_se_block
block = miniscramble(block, radiation_intensity, radiation_duration)
if(prob(20))
if(selected_se_block > 1 && selected_se_block < DNA_SE_LENGTH/2)
real_SE_block++
else if(selected_se_block > DNA_SE_LENGTH/2 && selected_se_block < DNA_SE_LENGTH)
real_SE_block--
//testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block)
domutcheck(connected.occupant, connected)
else
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return
if(prob(80 - radiation_duration))
//testing("Random bad mut!")
randmutb(connected.occupant)
domutcheck(connected.occupant, connected)
else
randmuti(connected.occupant)
//testing("Random identity mut!")
connected.occupant.UpdateAppearance()
if("ejectBeaker")
if(connected.beaker)
var/obj/item/reagent_containers/glass/B = connected.beaker
B.forceMove(connected.loc)
connected.beaker = null
if("ejectOccupant")
connected.eject_occupant()
// Transfer Buffer Management
if("bufferOption")
var/bufferOption = params["option"]
var/bufferId = text2num(params["id"])
if(bufferId < 1 || bufferId > 3) // Not a valid buffer id
return
var/datum/dna2/record/buffer = buffers[bufferId]
switch(bufferOption)
if("saveUI")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_UI // DNA2_BUF_UE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name=connected.occupant.name
databuf.name = "Unique Identifier"
buffers[bufferId] = databuf
if("saveUIAndUE")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name=connected.occupant.dna.real_name
databuf.name = "Unique Identifier + Unique Enzymes"
buffers[bufferId] = databuf
if("saveSE")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_SE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name = connected.occupant.dna.real_name
databuf.name = "Structural Enzymes"
buffers[bufferId] = databuf
if("clear")
buffers[bufferId] = new /datum/dna2/record()
if("changeLabel")
tgui_modal_input(src, "changeBufferLabel", "Please enter the new buffer label:", null, list("id" = bufferId), buffer.name, TGUI_MODAL_INPUT_MAX_LENGTH_NAME)
if("transfer")
if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna)
return
irradiating = 2
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SStgui.update_uis(src)
sleep(2 SECONDS)
irradiating = 0
connected.locked = lock_state
var/radiation = (rand(20,50) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return
var/datum/dna2/record/buf = buffers[bufferId]
if((buf.types & DNA2_BUF_UI))
if((buf.types & DNA2_BUF_UE))
connected.occupant.real_name = buf.dna.real_name
connected.occupant.name = buf.dna.real_name
connected.occupant.UpdateAppearance(buf.dna.UI.Copy())
else if(buf.types & DNA2_BUF_SE)
connected.occupant.dna.SE = buf.dna.SE.Copy()
connected.occupant.dna.UpdateSE()
domutcheck(connected.occupant, connected)
if("createInjector")
if(!injector_ready)
return
if(text2num(params["block"]) > 0)
var/list/choices = all_dna_blocks((buffer.types & DNA2_BUF_SE) ? buffer.dna.SE : buffer.dna.UI)
tgui_modal_choice(src, "createInjectorBlock", "Please select the block to create an injector from:", null, list("id" = bufferId), null, choices)
else
create_injector(bufferId, TRUE)
if("loadDisk")
if(isnull(disk) || disk.read_only)
return
buffers[bufferId] = disk.buf.copy()
if("saveDisk")
if(isnull(disk) || disk.read_only)
return
var/datum/dna2/record/buf = buffers[bufferId]
disk.buf = buf.copy()
disk.name = "data disk - '[buf.dna.real_name]'"
if("wipeDisk")
if(isnull(disk) || disk.read_only)
return
disk.buf = null
if("ejectDisk")
if(!disk)
return
disk.forceMove(get_turf(src))
disk = null
/**
* Creates a blank injector with the name of the buffer at the given buffer_id
*
* Arguments:
* * buffer_id - The ID of the buffer
* * copy_buffer - Whether the injector should copy the buffer contents
*/
/obj/machinery/computer/scan_consolenew/proc/create_injector(buffer_id, copy_buffer = FALSE)
if(buffer_id < 1 || buffer_id > length(buffers))
return
// Cooldown
injector_ready = FALSE
addtimer(CALLBACK(src, .proc/injector_cooldown_finish), 30 SECONDS)
// Create it
var/datum/dna2/record/buf = buffers[buffer_id]
var/obj/item/dnainjector/I = new()
I.forceMove(loc)
I.name += " ([buf.name])"
if(copy_buffer)
I.buf = buf.copy()
if(connected)
I.damage_coeff = connected.damage_coeff
return I
/**
* Called when the injector creation cooldown finishes
*/
/obj/machinery/computer/scan_consolenew/proc/injector_cooldown_finish()
injector_ready = TRUE
/**
* Called in tgui_act() to process modal actions
*
* Arguments:
* * action - The action passed by tgui
* * params - The params passed by tgui
*/
/obj/machinery/computer/scan_consolenew/proc/tgui_act_modal(action, params)
. = TRUE
var/id = params["id"] // The modal's ID
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
switch(tgui_modal_act(src, action, params))
if(TGUI_MODAL_ANSWER)
var/answer = params["answer"]
switch(id)
if("createInjectorBlock")
var/buffer_id = text2num(arguments["id"])
if(buffer_id < 1 || buffer_id > length(buffers))
return
var/datum/dna2/record/buf = buffers[buffer_id]
var/obj/item/dnainjector/I = create_injector(buffer_id)
setInjectorBlock(I, answer, buf.copy())
if("changeBufferLabel")
var/buffer_id = text2num(arguments["id"])
if(buffer_id < 1 || buffer_id > length(buffers))
return
var/datum/dna2/record/buf = buffers[buffer_id]
buf.name = answer
buffers[buffer_id] = buf
else
return FALSE
else
return FALSE
#undef PAGE_UI
#undef PAGE_SE
#undef PAGE_BUFFER
#undef PAGE_REJUVENATORS
/////////////////////////// DNA MACHINES
+4 -5
View File
@@ -249,14 +249,13 @@
block = GLOB.wingdingsblock
/datum/dna/gene/disability/wingdings/OnSay(mob/M, message)
var/list/chars = string2charlist(message)
var/garbled_message = ""
for(var/C in chars)
if(C in GLOB.alphabet_uppercase)
for(var/i in 1 to length(message))
if(message[i] in GLOB.alphabet_uppercase)
garbled_message += pick(GLOB.alphabet_uppercase)
else if(C in GLOB.alphabet)
else if(message[i] in GLOB.alphabet)
garbled_message += pick(GLOB.alphabet)
else
garbled_message += C
garbled_message += message[i]
message = garbled_message
return message
@@ -7,6 +7,7 @@
/mob/living/simple_animal/hostile/blob
icon = 'icons/mob/blob.dmi'
pass_flags = PASSBLOB
status_flags = NONE //No throwing blobspores into deep space to despawn, or throwing blobbernaughts, which are bigger than you.
faction = list(ROLE_BLOB)
bubble_icon = "blob"
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)
@@ -49,6 +50,7 @@
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
attacktext = "hits"
attack_sound = 'sound/weapons/genhit1.ogg'
flying = TRUE
speak_emote = list("pulses")
var/obj/structure/blob/factory/factory = null
var/list/human_overlays = list()
+7 -6
View File
@@ -17,12 +17,12 @@
START_PROCESSING(SSobj, src)
GLOB.poi_list |= src
adjustcolors(color) //so it atleast appears
if(!overmind)
create_overmind(new_overmind)
if(overmind)
adjustcolors(overmind.blob_reagent_datum.color)
if(offspring)
is_offspring = 1
if(overmind)
adjustcolors(overmind.blob_reagent_datum.color)
if(!overmind)
create_overmind(new_overmind)
point_rate = new_rate
..(loc, h)
@@ -104,10 +104,11 @@
var/mob/C = null
var/list/candidates = list()
if(!new_overmind)
// sendit
if(is_offspring)
candidates = pollCandidates("Do you want to play as a blob offspring?", ROLE_BLOB, 1)
candidates = SSghost_spawns.poll_candidates("Do you want to play as a blob offspring?", ROLE_BLOB, TRUE, source = src)
else
candidates = pollCandidates("Do you want to play as a blob?", ROLE_BLOB, 1)
candidates = SSghost_spawns.poll_candidates("Do you want to play as a blob?", ROLE_BLOB, TRUE, source = src)
if(length(candidates))
C = pick(candidates)
+2 -2
View File
@@ -237,7 +237,7 @@
blobber.AIStatus = AI_OFF
blobber.LoseTarget()
spawn()
var/list/candidates = pollCandidates("Do you want to play as a blobbernaut?", ROLE_BLOB, 1, 100)
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a blobbernaut?", ROLE_BLOB, TRUE, 10 SECONDS, source = blobber)
if(candidates.len)
var/mob/C = pick(candidates)
if(C)
@@ -389,7 +389,7 @@
return
split_used = TRUE
new /obj/structure/blob/core/ (get_turf(N), 200, null, blob_core.point_rate, "offspring")
new /obj/structure/blob/core/ (get_turf(N), 200, null, blob_core.point_rate, offspring = TRUE)
qdel(N)
if(SSticker && SSticker.mode.name == "blob")
@@ -370,16 +370,11 @@ GLOBAL_LIST_EMPTY(sting_paths)
mind.changeling.purchasedpowers += path
path.on_purchase(src)
else //for respec
var/datum/action/changeling/hivemind_upload/S1 = new
var/datum/action/changeling/hivemind_pick/S1 = new
if(!mind.changeling.has_sting(S1))
mind.changeling.purchasedpowers+=S1
S1.Grant(src)
var/datum/action/changeling/hivemind_download/S2 = new
if(!mind.changeling.has_sting(S2))
mind.changeling.purchasedpowers+=S2
S2.Grant(src)
var/mob/living/carbon/C = src //only carbons have dna now, so we have to typecaste
mind.changeling.absorbed_dna |= C.dna.Clone()
mind.changeling.trim_dna()
@@ -12,27 +12,36 @@
var/datum/changeling/changeling=user.mind.changeling
changeling.changeling_speak = 1
to_chat(user, "<i><font color=#800080>Use say \":g message\" to communicate with the other changelings.</font></i>")
var/datum/action/changeling/hivemind_upload/S1 = new
var/datum/action/changeling/hivemind_pick/S1 = new
if(!changeling.has_sting(S1))
changeling.purchasedpowers+=S1
S1.Grant(user)
var/datum/action/changeling/hivemind_download/S2 = new
if(!changeling.has_sting(S2))
S2.Grant(user)
changeling.purchasedpowers+=S2
return
// HIVE MIND UPLOAD/DOWNLOAD DNA
GLOBAL_LIST_EMPTY(hivemind_bank)
/datum/action/changeling/hivemind_upload
/datum/action/changeling/hivemind_pick
name = "Hive Channel DNA"
desc = "Allows us to channel DNA in the airwaves to allow other changelings to absorb it. Costs 10 chemicals."
button_icon_state = "hivemind_channel"
desc = "Allows us to upload or absorb DNA in the airwaves. Does not count towards absorb objectives. Costs 10 chemicals."
button_icon_state = "hive_absorb"
chemical_cost = 10
dna_cost = -1
/datum/action/changeling/hivemind_upload/sting_action(var/mob/user)
/datum/action/changeling/hivemind_pick/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/channel_pick = alert("Upload or Absorb DNA?", "Channel Select", "Upload", "Absorb")
if(channel_pick == "Upload")
dna_upload(user)
if(channel_pick == "Absorb")
if(changeling.using_stale_dna(user))//If our current DNA is the stalest, we gotta ditch it.
to_chat(user, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
return
else
dna_absorb(user)
/datum/action/changeling/proc/dna_upload(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/list/names = list()
for(var/datum/dna/DNA in (changeling.absorbed_dna+changeling.protected_dna))
@@ -56,23 +65,7 @@ GLOBAL_LIST_EMPTY(hivemind_bank)
feedback_add_details("changeling_powers","HU")
return 1
/datum/action/changeling/hivemind_download
name = "Hive Absorb DNA"
desc = "Allows us to absorb DNA that has been channeled to the airwaves. Does not count towards absorb objectives. Costs 10 chemicals."
button_icon_state = "hive_absorb"
chemical_cost = 10
dna_cost = -1
/datum/action/changeling/hivemind_download/can_sting(var/mob/living/carbon/user)
if(!..())
return
var/datum/changeling/changeling = user.mind.changeling
if(changeling.using_stale_dna(user))//If our current DNA is the stalest, we gotta ditch it.
to_chat(user, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
return
return 1
/datum/action/changeling/hivemind_download/sting_action(var/mob/user)
/datum/action/changeling/proc/dna_absorb(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/list/names = list()
for(var/datum/dna/DNA in GLOB.hivemind_bank)
@@ -18,12 +18,15 @@
if((NOCLONE || SKELETON || HUSK) in target.mutations)
to_chat(user, "<span class='warning'>DNA of [target] is ruined beyond usability!</span>")
return
if(!istype(target) || issmall(target) || (NO_DNA in target.dna.species.species_traits))
if(!istype(target) || !target.mind || issmall(target) || (NO_DNA in target.dna.species.species_traits))
to_chat(user, "<span class='warning'>[target] is not compatible with this ability.</span>")
return
if(target.mind.changeling)
to_chat(user, "<span class='warning'>We are unable to swap forms with another changeling!</span>")
return
if(target.has_brain_worms() || user.has_brain_worms())
to_chat(user, "<span class='warning'>A foreign presence repels us from this body!</span>")
return
return 1
/datum/action/changeling/swap_form/sting_action(var/mob/living/carbon/user)
@@ -63,6 +66,8 @@
target.add_language("Changeling")
user.remove_language("Changeling")
user.regenerate_icons()
if(target.stat == DEAD && target.suiciding) //If Target committed suicide, unset flag for User
target.suiciding = 0
for(var/power in lingpowers)
var/datum/action/changeling/S = power
+23 -6
View File
@@ -140,6 +140,7 @@
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
allowed = list(/obj/item/tome,/obj/item/melee/cultblade)
var/current_charges = 3
var/shield_state = "shield-cult"
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie
/obj/item/clothing/head/hooded/cult_hoodie
@@ -164,33 +165,49 @@
if(current_charges)
owner.visible_message("<span class='danger'>\The [attack_text] is deflected in a burst of blood-red sparks!</span>")
current_charges--
playsound(loc, "sparks", 100, 1)
new /obj/effect/temp_visual/cult/sparks(get_turf(owner))
if(!current_charges)
owner.visible_message("<span class='danger'>The runed shield around [owner] suddenly disappears!</span>")
shield_state = "broken"
owner.update_inv_wear_suit()
return 1
return 0
/obj/item/clothing/suit/hooded/cultrobes/berserker
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/special_overlays()
return mutable_appearance('icons/effects/cult_effects.dmi', shield_state, MOB_LAYER + 0.01)
/obj/item/clothing/suit/hooded/cultrobes/flagellant_robe
name = "flagellant's robes"
desc = "Blood-soaked robes infused with dark magic; allows the user to move at inhuman speeds, but at the cost of increased damage."
icon_state = "hardsuit-berserker"
item_state = "hardsuit-berserker"
icon_state = "flagellantrobe"
item_state = "flagellantrobe"
flags_inv = HIDEJUMPSUIT
allowed = list(/obj/item/tome,/obj/item/melee/cultblade)
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
armor = list("melee" = -45, "bullet" = -45, "laser" = -45,"energy" = -45, "bomb" = -45, "bio" = -45, "rad" = -45, "fire" = 0, "acid" = 0)
slowdown = -1
hoodtype = /obj/item/clothing/head/hooded/berserkerhood
sprite_sheets = list(
"Vox" = 'icons/mob/species/vox/suit.dmi',
"Drask" = 'icons/mob/species/drask/suit.dmi',
"Grey" = 'icons/mob/species/grey/suit.dmi'
)
hoodtype = /obj/item/clothing/head/hooded/flagellant_hood
/obj/item/clothing/head/hooded/berserkerhood
/obj/item/clothing/head/hooded/flagellant_hood
name = "flagellant's robes"
desc = "Blood-soaked garb infused with dark magic; allows the user to move at inhuman speeds, but at the cost of increased damage."
icon_state = "culthood"
icon_state = "flagellanthood"
item_state = "flagellanthood"
flags_inv = HIDEFACE
flags_cover = HEADCOVERSEYES
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
sprite_sheets = list(
"Vox" = 'icons/mob/species/vox/head.dmi',
"Drask" = 'icons/mob/species/drask/head.dmi',
"Grey" = 'icons/mob/species/grey/head.dmi'
)
/obj/item/whetstone/cult
name = "eldritch whetstone"
+1 -1
View File
@@ -120,7 +120,7 @@
selection_prompt = "You study the schematics etched on the forge..."
selection_title = "Forge"
creation_message = "<span class='cultitalic'>You work the forge as dark knowledge guides your hands, creating %ITEM%!</span>"
choosable_items = list("Shielded Robe" = /obj/item/clothing/suit/hooded/cultrobes/cult_shield, "Flagellant's Robe" = /obj/item/clothing/suit/hooded/cultrobes/berserker, \
choosable_items = list("Shielded Robe" = /obj/item/clothing/suit/hooded/cultrobes/cult_shield, "Flagellant's Robe" = /obj/item/clothing/suit/hooded/cultrobes/flagellant_robe, \
"Cultist Hardsuit" = /obj/item/storage/box/cult)
/obj/structure/cult/functional/forge/New()
+1 -1
View File
@@ -1,5 +1,5 @@
/obj/item/paper/talisman
icon = 'icons/obj/paper.dmi'
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "paper_talisman"
var/cultist_name = "talisman"
var/cultist_desc = "A basic talisman. It serves no purpose."
+2 -2
View File
@@ -424,9 +424,9 @@ proc/display_roundstart_logout_report()
return nukecode
/datum/game_mode/proc/replace_jobbanned_player(mob/living/M, role_type)
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a [role_type]?", role_type, 0, 100)
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as a [role_type]?", role_type, FALSE, 10 SECONDS)
var/mob/dead/observer/theghost = null
if(candidates.len)
if(length(candidates))
theghost = pick(candidates)
to_chat(M, "<span class='userdanger'>Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!</span>")
message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(M)]) to replace a jobbanned player.")
@@ -616,7 +616,7 @@
active = FALSE
return
var/turf/T = get_turf(owner_AI.eyeobj)
new /obj/machinery/transformer/conveyor(T)
new /obj/machinery/transformer(T, owner_AI)
playsound(T, 'sound/effects/phasein.ogg', 100, 1)
owner_AI.can_shunt = FALSE
to_chat(owner, "<span class='warning'>You are no longer able to shunt your core to APCs.</span>")
@@ -781,3 +781,17 @@
if(AI.eyeobj)
AI.eyeobj.relay_speech = TRUE
/datum/AI_Module/large/cameracrack
module_name = "Core Camera Cracker"
mod_pick_name = "cameracrack"
description = "By shortcirucuting the camera network chip, it overheats, preventing the camera console from using your internal camera."
cost = 10
one_purchase = TRUE
upgrade = TRUE
unlock_text = "<span class='notice'>Network chip short circuited. Internal camera disconected from network. Minimal damage to other internal components.</span>"
unlock_sound = 'sound/items/wirecutter.ogg'
/datum/AI_Module/large/cameracrack/upgrade(mob/living/silicon/ai/AI)
if(AI.builtInCamera)
QDEL_NULL(AI.builtInCamera)

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