Merge remote-tracking branch 'origin/master' into TGUI-3.0
This commit is contained in:
@@ -23380,7 +23380,7 @@
|
||||
/obj/structure/extinguisher_cabinet{
|
||||
pixel_y = -32
|
||||
},
|
||||
/obj/item/paper/guides/cogstation/letter_sec,
|
||||
/obj/item/paper/fluff/cogstation/secsolars,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/main)
|
||||
"aYJ" = (
|
||||
@@ -27342,13 +27342,16 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/courtroom)
|
||||
"bhA" = (
|
||||
/obj/machinery/disposal/bin,
|
||||
/obj/effect/turf_decal/delivery,
|
||||
/obj/structure/disposalpipe/trunk{
|
||||
dir = 4
|
||||
/obj/item/stack/cable_coil/red,
|
||||
/obj/item/multitool,
|
||||
/obj/item/wrench,
|
||||
/obj/item/stack/sheet/metal/five{
|
||||
pixel_x = 6;
|
||||
pixel_y = -6
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/quartermaster/sorting)
|
||||
/obj/item/paper/fluff/cogstation/letter_arrd,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/disposal)
|
||||
"bhB" = (
|
||||
/obj/structure/table/wood,
|
||||
/obj/item/stack/packageWrap,
|
||||
@@ -28343,6 +28346,7 @@
|
||||
/obj/effect/turf_decal/tile/yellow{
|
||||
dir = 4
|
||||
},
|
||||
/obj/item/paper/guides/cogstation/letter_atmos,
|
||||
/turf/open/floor/plasteel/dark/corner{
|
||||
dir = 1
|
||||
},
|
||||
@@ -34940,15 +34944,19 @@
|
||||
},
|
||||
/area/maintenance/disposal)
|
||||
"bxz" = (
|
||||
/obj/item/stack/cable_coil/red,
|
||||
/obj/item/multitool,
|
||||
/obj/item/wrench,
|
||||
/obj/item/stack/sheet/metal/five{
|
||||
pixel_x = 6;
|
||||
pixel_y = -6
|
||||
/obj/effect/turf_decal/tile/yellow{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/disposal)
|
||||
/obj/machinery/computer/station_alert,
|
||||
/obj/structure/sign/poster/official/safety_eye_protection{
|
||||
pixel_y = 32
|
||||
},
|
||||
/obj/effect/turf_decal/tile/red{
|
||||
dir = 1
|
||||
},
|
||||
/obj/item/paper/guides/cogstation/letter_eng,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/break_room)
|
||||
"bxA" = (
|
||||
/obj/machinery/announcement_system,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
@@ -43875,14 +43883,19 @@
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/science/robotics/lab)
|
||||
"bQq" = (
|
||||
/obj/machinery/atmospherics/components/unary/vent_pump/on,
|
||||
/obj/structure/cable{
|
||||
icon_state = "4-8"
|
||||
/obj/effect/turf_decal/tile/yellow{
|
||||
dir = 1
|
||||
},
|
||||
/obj/effect/landmark/event_spawn,
|
||||
/obj/machinery/atmospherics/pipe/simple/orange/hidden{
|
||||
dir = 8
|
||||
/obj/effect/turf_decal/tile/yellow,
|
||||
/obj/structure/table/wood,
|
||||
/obj/machinery/airalarm{
|
||||
pixel_y = 24
|
||||
},
|
||||
/obj/item/modular_computer/laptop/preset/civilian,
|
||||
/obj/effect/turf_decal/tile/blue{
|
||||
dir = 4
|
||||
},
|
||||
/obj/item/paper/guides/cogstation/letter_atmos,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/break_room)
|
||||
"bQr" = (
|
||||
@@ -51737,27 +51750,17 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/atmos)
|
||||
"cfU" = (
|
||||
/obj/structure/table,
|
||||
/obj/effect/turf_decal/tile/purple{
|
||||
dir = 4
|
||||
/obj/machinery/atmospherics/components/unary/vent_pump/on,
|
||||
/obj/structure/cable{
|
||||
icon_state = "4-8"
|
||||
},
|
||||
/obj/effect/turf_decal/tile/purple{
|
||||
/obj/effect/landmark/event_spawn,
|
||||
/obj/machinery/atmospherics/pipe/simple/orange/hidden{
|
||||
dir = 8
|
||||
},
|
||||
/obj/effect/turf_decal/tile/yellow{
|
||||
dir = 1
|
||||
},
|
||||
/obj/effect/turf_decal/tile/yellow,
|
||||
/obj/item/clothing/gloves/color/latex,
|
||||
/obj/item/book/manual/wiki/cit/chem_recipies,
|
||||
/obj/item/book/manual/wiki/cit/chemistry{
|
||||
pixel_x = 2;
|
||||
pixel_y = -3
|
||||
},
|
||||
/obj/item/reagent_containers/dropper,
|
||||
/obj/machinery/atmospherics/pipe/manifold/orange/hidden,
|
||||
/turf/open/floor/plasteel/white,
|
||||
/area/medical/chemistry)
|
||||
/obj/item/beacon,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/break_room)
|
||||
"cfV" = (
|
||||
/obj/machinery/door/airlock/external{
|
||||
name = "Atmospherics External Airlock";
|
||||
@@ -57026,18 +57029,18 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/break_room)
|
||||
"cqt" = (
|
||||
/obj/effect/turf_decal/tile/yellow{
|
||||
/obj/machinery/disposal/bin,
|
||||
/obj/effect/turf_decal/delivery,
|
||||
/obj/structure/disposalpipe/trunk{
|
||||
dir = 4
|
||||
},
|
||||
/obj/machinery/computer/station_alert,
|
||||
/obj/structure/sign/poster/official/safety_eye_protection{
|
||||
pixel_y = 32
|
||||
},
|
||||
/obj/effect/turf_decal/tile/red{
|
||||
dir = 1
|
||||
/obj/structure/noticeboard/qm{
|
||||
dir = 4;
|
||||
icon_state = "nboard00";
|
||||
pixel_x = -32
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/break_room)
|
||||
/area/quartermaster/sorting)
|
||||
"cqu" = (
|
||||
/obj/effect/turf_decal/tile/yellow{
|
||||
dir = 4
|
||||
@@ -57106,20 +57109,28 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/break_room)
|
||||
"cqz" = (
|
||||
/obj/structure/table,
|
||||
/obj/effect/turf_decal/tile/purple{
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/turf_decal/tile/purple{
|
||||
dir = 8
|
||||
},
|
||||
/obj/effect/turf_decal/tile/yellow{
|
||||
dir = 1
|
||||
},
|
||||
/obj/effect/turf_decal/tile/yellow,
|
||||
/obj/structure/table/wood,
|
||||
/obj/machinery/airalarm{
|
||||
pixel_y = 24
|
||||
/obj/item/clothing/gloves/color/latex,
|
||||
/obj/item/book/manual/wiki/cit/chem_recipies,
|
||||
/obj/item/book/manual/wiki/cit/chemistry{
|
||||
pixel_x = 2;
|
||||
pixel_y = -3
|
||||
},
|
||||
/obj/item/modular_computer/laptop/preset/civilian,
|
||||
/obj/effect/turf_decal/tile/blue{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/engine/break_room)
|
||||
/obj/machinery/atmospherics/pipe/manifold/orange/hidden,
|
||||
/obj/item/paper/fluff/cogstation/chemists,
|
||||
/obj/item/reagent_containers/dropper,
|
||||
/turf/open/floor/plasteel/white,
|
||||
/area/medical/chemistry)
|
||||
"cqA" = (
|
||||
/obj/structure/cable{
|
||||
icon_state = "1-2"
|
||||
@@ -96465,7 +96476,7 @@ bBQ
|
||||
csV
|
||||
bIe
|
||||
bYB
|
||||
cfU
|
||||
cqz
|
||||
bIM
|
||||
cvt
|
||||
cmS
|
||||
@@ -109285,7 +109296,7 @@ asR
|
||||
aSK
|
||||
aSr
|
||||
aeI
|
||||
cqt
|
||||
bxz
|
||||
bwP
|
||||
cBn
|
||||
cBH
|
||||
@@ -110315,7 +110326,7 @@ aUf
|
||||
aeI
|
||||
bnp
|
||||
cmO
|
||||
bQq
|
||||
cfU
|
||||
cmm
|
||||
cri
|
||||
cdH
|
||||
@@ -111598,7 +111609,7 @@ aRR
|
||||
cpj
|
||||
aSr
|
||||
aeI
|
||||
cqz
|
||||
bQq
|
||||
cqI
|
||||
bQM
|
||||
cdl
|
||||
@@ -114945,7 +114956,7 @@ bbV
|
||||
bjf
|
||||
bkh
|
||||
blu
|
||||
bbV
|
||||
ciI
|
||||
ccZ
|
||||
cgs
|
||||
cxo
|
||||
@@ -116742,7 +116753,7 @@ cPH
|
||||
bfU
|
||||
bFD
|
||||
bgO
|
||||
bhA
|
||||
cqt
|
||||
bUQ
|
||||
cvj
|
||||
cDg
|
||||
@@ -117990,7 +118001,7 @@ bwb
|
||||
aMs
|
||||
cAb
|
||||
cAl
|
||||
bxz
|
||||
bhA
|
||||
bgP
|
||||
bzO
|
||||
caD
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,224 @@
|
||||
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
|
||||
"a" = (
|
||||
/turf/template_noop,
|
||||
/area/template_noop)
|
||||
"b" = (
|
||||
/turf/closed/wall/mineral/titanium,
|
||||
/area/shuttle/arrival)
|
||||
"c" = (
|
||||
/obj/machinery/door/airlock/titanium{
|
||||
name = "Arrivals Shuttle Airlock"
|
||||
},
|
||||
/obj/structure/fans/tiny,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"d" = (
|
||||
/obj/effect/spawner/structure/window/shuttle,
|
||||
/turf/open/floor/plating,
|
||||
/area/shuttle/arrival)
|
||||
"e" = (
|
||||
/obj/structure/closet/wardrobe/black,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"f" = (
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"g" = (
|
||||
/obj/machinery/computer/arcade,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"h" = (
|
||||
/obj/structure/closet/wardrobe/grey,
|
||||
/obj/machinery/light/small{
|
||||
dir = 1
|
||||
},
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"i" = (
|
||||
/obj/structure/closet/wardrobe/green,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"j" = (
|
||||
/obj/machinery/requests_console{
|
||||
department = "Arrival shuttle";
|
||||
name = "Arrivals Shuttle console";
|
||||
pixel_y = 30
|
||||
},
|
||||
/obj/machinery/light{
|
||||
dir = 1
|
||||
},
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"k" = (
|
||||
/obj/structure/shuttle/engine/heater{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 8
|
||||
},
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/shuttle/arrival)
|
||||
"m" = (
|
||||
/obj/machinery/light{
|
||||
dir = 1
|
||||
},
|
||||
/obj/structure/closet/wardrobe/mixed,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"n" = (
|
||||
/obj/docking_port/mobile/arrivals{
|
||||
name = "Snaxi Arrivals Shuttle"
|
||||
},
|
||||
/obj/structure/shuttle/engine/propulsion/burst/right{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/shuttle/arrival)
|
||||
"o" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/storage/firstaid/regular,
|
||||
/obj/machinery/light/small,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"p" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/storage/toolbox/emergency,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"q" = (
|
||||
/obj/machinery/light,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"r" = (
|
||||
/obj/structure/chair/comfy/shuttle{
|
||||
dir = 8
|
||||
},
|
||||
/turf/open/floor/mineral/titanium,
|
||||
/area/shuttle/arrival)
|
||||
"s" = (
|
||||
/obj/item/radio/intercom{
|
||||
name = "Station Intercom (General)";
|
||||
pixel_y = -29
|
||||
},
|
||||
/obj/machinery/light,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"x" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/open/floor/mineral/titanium/blue,
|
||||
/area/shuttle/arrival)
|
||||
"z" = (
|
||||
/obj/structure/shuttle/engine/propulsion/burst/right{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/shuttle/arrival)
|
||||
|
||||
(1,1,1) = {"
|
||||
a
|
||||
b
|
||||
d
|
||||
d
|
||||
d
|
||||
b
|
||||
a
|
||||
"}
|
||||
(2,1,1) = {"
|
||||
b
|
||||
b
|
||||
r
|
||||
r
|
||||
r
|
||||
b
|
||||
b
|
||||
"}
|
||||
(3,1,1) = {"
|
||||
b
|
||||
h
|
||||
f
|
||||
f
|
||||
f
|
||||
o
|
||||
b
|
||||
"}
|
||||
(4,1,1) = {"
|
||||
b
|
||||
i
|
||||
r
|
||||
r
|
||||
r
|
||||
p
|
||||
b
|
||||
"}
|
||||
(5,1,1) = {"
|
||||
b
|
||||
e
|
||||
f
|
||||
f
|
||||
f
|
||||
x
|
||||
b
|
||||
"}
|
||||
(6,1,1) = {"
|
||||
b
|
||||
m
|
||||
r
|
||||
r
|
||||
r
|
||||
q
|
||||
b
|
||||
"}
|
||||
(7,1,1) = {"
|
||||
d
|
||||
g
|
||||
f
|
||||
f
|
||||
f
|
||||
f
|
||||
d
|
||||
"}
|
||||
(8,1,1) = {"
|
||||
c
|
||||
f
|
||||
r
|
||||
r
|
||||
r
|
||||
f
|
||||
c
|
||||
"}
|
||||
(9,1,1) = {"
|
||||
c
|
||||
f
|
||||
f
|
||||
f
|
||||
f
|
||||
f
|
||||
c
|
||||
"}
|
||||
(10,1,1) = {"
|
||||
b
|
||||
j
|
||||
r
|
||||
r
|
||||
r
|
||||
s
|
||||
b
|
||||
"}
|
||||
(11,1,1) = {"
|
||||
b
|
||||
k
|
||||
k
|
||||
k
|
||||
k
|
||||
k
|
||||
b
|
||||
"}
|
||||
(12,1,1) = {"
|
||||
b
|
||||
z
|
||||
z
|
||||
n
|
||||
z
|
||||
z
|
||||
b
|
||||
"}
|
||||
@@ -342,11 +342,6 @@
|
||||
},
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/shuttle/syndicate/eva)
|
||||
"aN" = (
|
||||
/obj/machinery/portable_atmospherics/canister/oxygen,
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/shuttle/syndicate/eva)
|
||||
"aO" = (
|
||||
/obj/structure/chair/comfy/shuttle{
|
||||
dir = 4;
|
||||
@@ -385,8 +380,9 @@
|
||||
/turf/open/floor/mineral/plastitanium,
|
||||
/area/shuttle/syndicate/eva)
|
||||
"aS" = (
|
||||
/obj/structure/tank_dispenser/oxygen,
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/vehicle/ridden/atv/snowmobile,
|
||||
/obj/item/key,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/shuttle/syndicate/eva)
|
||||
"aT" = (
|
||||
@@ -1172,15 +1168,37 @@
|
||||
},
|
||||
/turf/closed/wall/r_wall/syndicate,
|
||||
/area/shuttle/syndicate/armory)
|
||||
"gZ" = (
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/vehicle/ridden/atv/snowmobile,
|
||||
/obj/item/key,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/shuttle/syndicate/airlock)
|
||||
"pd" = (
|
||||
/obj/machinery/porta_turret/syndicate/shuttle{
|
||||
dir = 5
|
||||
},
|
||||
/turf/closed/wall/r_wall/syndicate,
|
||||
/area/shuttle/syndicate/bridge)
|
||||
"vv" = (
|
||||
/obj/structure/reagent_dispensers/fueltank,
|
||||
"qk" = (
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 1
|
||||
},
|
||||
/obj/effect/turf_decal/tile/neutral,
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 8
|
||||
},
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/vehicle/ridden/atv/snowmobile,
|
||||
/obj/item/key,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/shuttle/syndicate/airlock)
|
||||
"vv" = (
|
||||
/obj/effect/turf_decal/bot_white,
|
||||
/obj/structure/tank_dispenser/oxygen,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/shuttle/syndicate/eva)
|
||||
"In" = (
|
||||
@@ -1195,6 +1213,14 @@
|
||||
},
|
||||
/turf/closed/wall/r_wall/syndicate,
|
||||
/area/shuttle/syndicate/medical)
|
||||
"Sz" = (
|
||||
/obj/effect/turf_decal/tile/neutral,
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 8
|
||||
},
|
||||
/obj/structure/reagent_dispensers/fueltank,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/shuttle/syndicate/armory)
|
||||
|
||||
(1,1,1) = {"
|
||||
aa
|
||||
@@ -1330,7 +1356,7 @@ ac
|
||||
ad
|
||||
aa
|
||||
ax
|
||||
aN
|
||||
aS
|
||||
aS
|
||||
aU
|
||||
aZ
|
||||
@@ -1480,7 +1506,7 @@ ac
|
||||
In
|
||||
aa
|
||||
aB
|
||||
aO
|
||||
gZ
|
||||
aO
|
||||
aX
|
||||
bc
|
||||
@@ -1505,7 +1531,7 @@ ac
|
||||
aa
|
||||
aa
|
||||
aB
|
||||
aP
|
||||
qk
|
||||
aP
|
||||
aP
|
||||
aP
|
||||
@@ -1530,7 +1556,7 @@ aa
|
||||
aa
|
||||
aa
|
||||
aB
|
||||
aP
|
||||
qk
|
||||
aP
|
||||
aP
|
||||
aP
|
||||
@@ -1587,7 +1613,7 @@ bd
|
||||
aB
|
||||
bm
|
||||
bB
|
||||
bG
|
||||
Sz
|
||||
bQ
|
||||
bX
|
||||
ci
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
|
||||
"a" = (
|
||||
/turf/closed/wall/mineral/titanium,
|
||||
/area/shuttle/snowtaxi)
|
||||
"b" = (
|
||||
/obj/structure/shuttle/engine/propulsion/burst{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 8
|
||||
},
|
||||
/obj/structure/fans/tiny/invisible,
|
||||
/turf/open/floor/plating,
|
||||
/area/shuttle/snowtaxi)
|
||||
"c" = (
|
||||
/obj/machinery/door/airlock/titanium{
|
||||
name = "Mining Shuttle Airlock"
|
||||
},
|
||||
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
|
||||
/obj/structure/fans/tiny,
|
||||
/turf/open/floor/plating,
|
||||
/area/shuttle/snowtaxi)
|
||||
"e" = (
|
||||
/obj/effect/spawner/structure/window/shuttle,
|
||||
/obj/structure/fans/tiny/invisible,
|
||||
/turf/open/floor/plating,
|
||||
/area/shuttle/snowtaxi)
|
||||
"f" = (
|
||||
/obj/machinery/light{
|
||||
dir = 1
|
||||
},
|
||||
/obj/structure/chair/comfy/shuttle{
|
||||
dir = 8
|
||||
},
|
||||
/turf/open/floor/mineral/titanium,
|
||||
/area/shuttle/snowtaxi)
|
||||
"g" = (
|
||||
/obj/machinery/door/airlock/titanium{
|
||||
name = "Mining Shuttle Airlock"
|
||||
},
|
||||
/obj/docking_port/mobile{
|
||||
dwidth = 3;
|
||||
height = 4;
|
||||
id = "snow_taxi";
|
||||
name = "snow taxi";
|
||||
port_direction = 8;
|
||||
width = 6
|
||||
},
|
||||
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
|
||||
dir = 1
|
||||
},
|
||||
/obj/structure/fans/tiny,
|
||||
/turf/open/floor/plating,
|
||||
/area/shuttle/snowtaxi)
|
||||
"i" = (
|
||||
/obj/machinery/light,
|
||||
/obj/machinery/computer/shuttle/snow_taxi{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/mineral/titanium,
|
||||
/area/shuttle/snowtaxi)
|
||||
"j" = (
|
||||
/obj/structure/chair/comfy/shuttle{
|
||||
dir = 1
|
||||
},
|
||||
/turf/open/floor/mineral/titanium,
|
||||
/area/shuttle/snowtaxi)
|
||||
"k" = (
|
||||
/turf/open/floor/mineral/titanium,
|
||||
/area/shuttle/snowtaxi)
|
||||
"l" = (
|
||||
/obj/effect/spawner/structure/window/shuttle,
|
||||
/obj/structure/fans/tiny/invisible,
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/shuttle/snowtaxi)
|
||||
"u" = (
|
||||
/obj/structure/chair/comfy/shuttle,
|
||||
/turf/open/floor/mineral/titanium,
|
||||
/area/shuttle/snowtaxi)
|
||||
|
||||
(1,1,1) = {"
|
||||
a
|
||||
e
|
||||
e
|
||||
a
|
||||
"}
|
||||
(2,1,1) = {"
|
||||
a
|
||||
f
|
||||
i
|
||||
a
|
||||
"}
|
||||
(3,1,1) = {"
|
||||
e
|
||||
u
|
||||
j
|
||||
l
|
||||
"}
|
||||
(4,1,1) = {"
|
||||
c
|
||||
k
|
||||
k
|
||||
g
|
||||
"}
|
||||
(5,1,1) = {"
|
||||
a
|
||||
u
|
||||
j
|
||||
a
|
||||
"}
|
||||
(6,1,1) = {"
|
||||
a
|
||||
b
|
||||
b
|
||||
a
|
||||
"}
|
||||
@@ -0,0 +1 @@
|
||||
#define FORCE_MAP "_maps/snaxi.json"
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"map_name":"Snow Taxi",
|
||||
"map_path":"map_files/Snaxi",
|
||||
"map_file":[
|
||||
"IcemoonUnderground_Below.dmm",
|
||||
"IcemoonUnderground_Above.dmm",
|
||||
"Snaxi.dmm"
|
||||
],
|
||||
"station_ruin_budget":0,
|
||||
"space_ruin_levels":0,
|
||||
"space_empty_levels":0,
|
||||
"shuttles":{
|
||||
"cargo":"cargo_box",
|
||||
"ferry":"ferry_fancy",
|
||||
"whiteship":"whiteship_box",
|
||||
"emergency":"emergency_box"
|
||||
},
|
||||
"traits":[
|
||||
{
|
||||
"Up":1,
|
||||
"Station":0,
|
||||
"Mining":true,
|
||||
"Linkage":null,
|
||||
"Gravity":true,
|
||||
"Ice Ruins Underground":true,
|
||||
"Baseturf":"/turf/open/lava/plasma/ice_moon"
|
||||
},
|
||||
{
|
||||
"Down":-1,
|
||||
"Up":1,
|
||||
"Station":0,
|
||||
"Mining":true,
|
||||
"Linkage":null,
|
||||
"Gravity":true,
|
||||
"Ice Ruins Underground":true,
|
||||
"Baseturf":"/turf/open/openspace/icemoon"
|
||||
},
|
||||
{
|
||||
"Down":-1,
|
||||
"Mining":true,
|
||||
"Linkage":null,
|
||||
"Gravity":true,
|
||||
"Ice Ruins":true,
|
||||
"Weather_Snowstorm":true,
|
||||
"Baseturf":"/turf/open/floor/plating/asteroid/snow/icemoon"
|
||||
}
|
||||
],
|
||||
"minetype":"none"
|
||||
}
|
||||
@@ -61,10 +61,18 @@
|
||||
#define CHECK_STAMCRIT(mob) ((mob.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)? HARD_STAMCRIT : ((mob.combat_flags & COMBAT_FLAG_SOFT_STAMCRIT)? SOFT_STAMCRIT : NOT_STAMCRIT))
|
||||
|
||||
//stamina stuff
|
||||
#define STAMINA_SOFTCRIT 100 //softcrit for stamina damage. prevents standing up, prevents performing actions that cost stamina, etc, but doesn't force a rest or stop movement
|
||||
#define STAMINA_CRIT 140 //crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit
|
||||
#define STAMINA_SOFTCRIT_TRADITIONAL 0 //same as STAMINA_SOFTCRIT except for the more traditional health calculations
|
||||
#define STAMINA_CRIT_TRADITIONAL -40 //ditto, but for STAMINA_CRIT
|
||||
///Threshold over which attacks start being hindered.
|
||||
#define STAMINA_NEAR_SOFTCRIT 90
|
||||
///softcrit for stamina damage. prevents standing up, some actions that cost stamina, etc, but doesn't force a rest or stop movement
|
||||
#define STAMINA_SOFTCRIT 100
|
||||
///sanity cap to prevent stamina actions (that are still performable) from sending you into crit.
|
||||
#define STAMINA_NEAR_CRIT 130
|
||||
///crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit
|
||||
#define STAMINA_CRIT 140
|
||||
///same as STAMINA_SOFTCRIT except for the more traditional health calculations
|
||||
#define STAMINA_SOFTCRIT_TRADITIONAL 0
|
||||
///ditto, but for STAMINA_CRIT
|
||||
#define STAMINA_CRIT_TRADITIONAL -40
|
||||
|
||||
#define CRAWLUNDER_DELAY 30 //Delay for crawling under a standing mob
|
||||
|
||||
@@ -182,6 +190,9 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
#define EGUN_SELFCHARGE 1
|
||||
#define EGUN_SELFCHARGE_BORG 2
|
||||
|
||||
///Time to spend without clicking on other things required for your shots to become accurate.
|
||||
#define GUN_AIMING_TIME (2 SECONDS)
|
||||
|
||||
//Object/Item sharpness
|
||||
#define IS_BLUNT 0
|
||||
#define IS_SHARP 1
|
||||
@@ -249,6 +260,21 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
#define STAM_COST_W_CLASS_MULT 1.25
|
||||
#define STAM_COST_THROW_MULT 2
|
||||
|
||||
///Multiplier of the (STAMINA_NEAR_CRIT - user current stamina loss) : (STAMINA_NEAR_CRIT - STAMINA_SOFTCRIT) ratio used in damage penalties when stam soft-critted.
|
||||
#define STAM_CRIT_ITEM_ATTACK_PENALTY 0.66
|
||||
/// changeNext_move penalty multiplier of the above.
|
||||
#define STAM_CRIT_ITEM_ATTACK_DELAY 1.75
|
||||
/// Damage penalty when fighting prone.
|
||||
#define LYING_DAMAGE_PENALTY 0.5
|
||||
/// Added delay when firing guns stam-softcritted. Summed with a hardset CLICK_CD_RANGE delay, similar to STAM_CRIT_DAMAGE_DELAY otherwise.
|
||||
#define STAM_CRIT_GUN_DELAY 2.75
|
||||
|
||||
/**
|
||||
* should the current-attack-damage be lower than the item force multiplied by this value,
|
||||
* a "inefficiently" prefix will be added to the message.
|
||||
*/
|
||||
#define INEFFICIENT_ATTACK_MSG_THRESHOLD 0.7
|
||||
|
||||
|
||||
//bullet_act() return values
|
||||
#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
|
||||
|
||||
@@ -88,3 +88,28 @@
|
||||
#define EMISSIVE_BLOCK_GENERIC 1
|
||||
/// Uses a dedicated render_target object to copy the entire appearance in real time to the blocking layer. For things that can change in appearance a lot from the base state, like humans.
|
||||
#define EMISSIVE_BLOCK_UNIQUE 2
|
||||
|
||||
|
||||
/// Returns the red part of a #RRGGBB hex sequence as number
|
||||
#define GETREDPART(hexa) hex2num(copytext(hexa, 2, 4))
|
||||
|
||||
/// Returns the green part of a #RRGGBB hex sequence as number
|
||||
#define GETGREENPART(hexa) hex2num(copytext(hexa, 4, 6))
|
||||
|
||||
/// Returns the blue part of a #RRGGBB hex sequence as number
|
||||
#define GETBLUEPART(hexa) hex2num(copytext(hexa, 6, 8))
|
||||
|
||||
/// Parse the hexadecimal color into lumcounts of each perspective.
|
||||
#define PARSE_LIGHT_COLOR(source) \
|
||||
do { \
|
||||
if (source.light_color) { \
|
||||
var/__light_color = source.light_color; \
|
||||
source.lum_r = GETREDPART(__light_color) / 255; \
|
||||
source.lum_g = GETGREENPART(__light_color) / 255; \
|
||||
source.lum_b = GETBLUEPART(__light_color) / 255; \
|
||||
} else { \
|
||||
source.lum_r = 1; \
|
||||
source.lum_g = 1; \
|
||||
source.lum_b = 1; \
|
||||
}; \
|
||||
} while (FALSE)
|
||||
|
||||
+22
-11
@@ -18,18 +18,29 @@
|
||||
// Flags for the item_flags var on /obj/item
|
||||
|
||||
#define BEING_REMOVED (1<<0)
|
||||
#define IN_INVENTORY (1<<1) //is this item equipped into an inventory slot or hand of a mob? used for tooltips
|
||||
#define FORCE_STRING_OVERRIDE (1<<2) //used for tooltips
|
||||
#define NEEDS_PERMIT (1<<3) //Used by security bots to determine if this item is safe for public use.
|
||||
///is this item equipped into an inventory slot or hand of a mob? used for tooltips
|
||||
#define IN_INVENTORY (1<<1)
|
||||
///used for tooltips
|
||||
#define FORCE_STRING_OVERRIDE (1<<2)
|
||||
///Used by security bots to determine if this item is safe for public use.
|
||||
#define NEEDS_PERMIT (1<<3)
|
||||
#define SLOWS_WHILE_IN_HAND (1<<4)
|
||||
#define NO_MAT_REDEMPTION (1<<5) //Stops you from putting things like an RCD or other items into an ORM or protolathe for materials.
|
||||
#define DROPDEL (1<<6) //When dropped, it calls qdel on itself
|
||||
#define NOBLUDGEON (1<<7) //when an item has this it produces no "X has been hit by Y with Z" message in the default attackby()
|
||||
#define ABSTRACT (1<<8) //for all things that are technically items but used for various different stuff
|
||||
#define IMMUTABLE_SLOW (1<<9) //When players should not be able to change the slowdown of the item (Speed potions, ect)
|
||||
#define SURGICAL_TOOL (1<<10) //Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes)
|
||||
#define NO_UNIFORM_REQUIRED (1<<11) //Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
|
||||
#define NO_ATTACK_CHAIN_SOFT_STAMCRIT (1<<12) //Entirely blocks melee_attack_chain() if user is soft stamcritted. Uses getStaminaLoss() to check at this point in time. THIS DOES NOT BLOCK RANGED AFTERATTACK()S, ONLY MELEE RANGE AFTERATTACK()S.
|
||||
///Stops you from putting things like an RCD or other items into an ORM or protolathe for materials.
|
||||
#define NO_MAT_REDEMPTION (1<<5)
|
||||
///When dropped, it calls qdel on itself
|
||||
#define DROPDEL (1<<6)
|
||||
///when an item has this it produces no "X has been hit by Y with Z" message in the default attackby()
|
||||
#define NOBLUDGEON (1<<7)
|
||||
///for all things that are technically items but used for various different stuff
|
||||
#define ABSTRACT (1<<8)
|
||||
///When players should not be able to change the slowdown of the item (Speed potions, ect)
|
||||
#define IMMUTABLE_SLOW (1<<9)
|
||||
///Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes)
|
||||
#define SURGICAL_TOOL (1<<10)
|
||||
///Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
|
||||
#define NO_UNIFORM_REQUIRED (1<<11)
|
||||
///Damage when attacking people is not affected by combat mode.
|
||||
#define NO_COMBAT_MODE_FORCE_MODIFIER (1<<12)
|
||||
|
||||
// Flags for the clothing_flags var on /obj/item/clothing
|
||||
|
||||
|
||||
@@ -36,4 +36,5 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list(
|
||||
#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 7)
|
||||
#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 10)
|
||||
#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 20)
|
||||
|
||||
#define STORAGE_VOLUME_CHEMISTRY_BAG (DEFAULT_VOLUME_TINY * 50)
|
||||
#define STORAGE_VOLUME_PILL_BOTTLE (DEFAULT_VOLUME_TINY * 7)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define VALENTINES "Valentine's Day"
|
||||
#define APRIL_FOOLS "April Fool's Day"
|
||||
#define EASTER "Easter"
|
||||
#define PRIDE_MONTH "Pride Month"
|
||||
#define HALLOWEEN "Halloween"
|
||||
#define CHRISTMAS "Christmas"
|
||||
#define FESTIVE_SEASON "Festive Season"
|
||||
|
||||
@@ -170,6 +170,7 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
|
||||
newA.setup(str)
|
||||
newA.set_dynamic_lighting()
|
||||
newA.has_gravity = oldA.has_gravity
|
||||
newA.noteleport = oldA.noteleport
|
||||
else
|
||||
newA = area_choice
|
||||
|
||||
|
||||
@@ -565,22 +565,6 @@
|
||||
var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
|
||||
announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common
|
||||
|
||||
/proc/GetHexColors(const/hexa)
|
||||
return list(
|
||||
GetRedPart(hexa)/ 255,
|
||||
GetGreenPart(hexa)/ 255,
|
||||
GetBluePart(hexa)/ 255
|
||||
)
|
||||
|
||||
/proc/GetRedPart(const/hexa)
|
||||
return hex2num(copytext(hexa, 2, 4))
|
||||
|
||||
/proc/GetGreenPart(const/hexa)
|
||||
return hex2num(copytext(hexa, 4, 6))
|
||||
|
||||
/proc/GetBluePart(const/hexa)
|
||||
return hex2num(copytext(hexa, 6, 8))
|
||||
|
||||
/proc/lavaland_equipment_pressure_check(turf/T)
|
||||
. = FALSE
|
||||
if(!istype(T))
|
||||
|
||||
@@ -216,6 +216,7 @@
|
||||
"ipc_screen" = snowflake_ipc_antenna_list ? pick(snowflake_ipc_antenna_list) : "None",
|
||||
"ipc_antenna" = "None",
|
||||
"flavor_text" = "",
|
||||
"silicon_flavor_text" = "",
|
||||
"meat_type" = "Mammalian",
|
||||
"body_model" = body_model,
|
||||
"body_size" = RESIZE_DEFAULT_SIZE
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
|
||||
|
||||
/mob/living/changeNext_move(num)
|
||||
last_click_move = next_move
|
||||
var/mod = next_move_modifier
|
||||
var/adj = next_move_adjust
|
||||
for(var/i in status_effects)
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params)
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
if(item_flags & NO_ATTACK_CHAIN_SOFT_STAMCRIT)
|
||||
if(IS_STAMCRIT(L))
|
||||
to_chat(L, "<span class='warning'>You are too exhausted to swing [src]!</span>")
|
||||
return
|
||||
if(!CHECK_MOBILITY(L, MOBILITY_USE))
|
||||
to_chat(L, "<span class='warning'>You are unable to swing [src] right now!</span>")
|
||||
return
|
||||
@@ -59,8 +55,10 @@
|
||||
/mob/living/attackby(obj/item/I, mob/living/user, params)
|
||||
if(..())
|
||||
return TRUE
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
return I.attack(src, user)
|
||||
I.attack_delay_done = FALSE //Should be set TRUE in pre_attacked_by()
|
||||
. = I.attack(src, user)
|
||||
if(!I.attack_delay_done) //Otherwise, pre_attacked_by() should handle it.
|
||||
user.changeNext_move(I.click_delay)
|
||||
|
||||
/obj/item/proc/attack(mob/living/M, mob/living/user)
|
||||
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK)
|
||||
@@ -68,11 +66,6 @@
|
||||
SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user)
|
||||
if(item_flags & NOBLUDGEON)
|
||||
return
|
||||
|
||||
if(IS_STAMCRIT(user)) // CIT CHANGE - makes it impossible to attack in stamina softcrit
|
||||
to_chat(user, "<span class='warning'>You're too exhausted.</span>") // CIT CHANGE - ditto
|
||||
return // CIT CHANGE - ditto
|
||||
|
||||
if(force && damtype != STAMINA && HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
|
||||
return
|
||||
@@ -91,7 +84,9 @@
|
||||
log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
|
||||
add_fingerprint(user)
|
||||
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_MOB_MULT))//CIT CHANGE - makes attacking things cause stamina loss
|
||||
var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) //CIT CHANGE - makes attacking things cause stamina loss
|
||||
if(weight)
|
||||
user.adjustStaminaLossBuffered(weight)
|
||||
|
||||
//the equivalent of the standard version of attack() but for object targets.
|
||||
/obj/item/proc/attack_obj(obj/O, mob/living/user)
|
||||
@@ -99,13 +94,12 @@
|
||||
return
|
||||
if(item_flags & NOBLUDGEON)
|
||||
return
|
||||
if(IS_STAMCRIT(user)) // CIT CHANGE - makes it impossible to attack in stamina softcrit
|
||||
to_chat(user, "<span class='warning'>You're too exhausted.</span>") // CIT CHANGE - ditto
|
||||
return // CIT CHANGE - ditto
|
||||
user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_OBJ_MULT))//CIT CHANGE - makes attacking things cause stamina loss
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(O)
|
||||
O.attacked_by(src, user)
|
||||
if(!O.attacked_by(src, user))
|
||||
user.changeNext_move(click_delay)
|
||||
var/weight = getweight(user, STAM_COST_ATTACK_OBJ_MULT)
|
||||
if(weight)
|
||||
user.adjustStaminaLossBuffered(weight)//CIT CHANGE - makes attacking things cause stamina loss
|
||||
|
||||
/atom/movable/proc/attacked_by()
|
||||
return
|
||||
@@ -113,9 +107,18 @@
|
||||
/obj/attacked_by(obj/item/I, mob/living/user)
|
||||
var/totitemdamage = I.force
|
||||
var/bad_trait
|
||||
if(!SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
totitemdamage *= 0.5
|
||||
|
||||
var/stamloss = user.getStaminaLoss()
|
||||
var/next_move_mult = 1
|
||||
if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
|
||||
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
|
||||
totitemdamage *= 1 - penalty
|
||||
next_move_mult += penalty*STAM_CRIT_ITEM_ATTACK_DELAY
|
||||
user.changeNext_move(I.click_delay*next_move_mult)
|
||||
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
|
||||
if(I.used_skills && user.mind)
|
||||
if(totitemdamage)
|
||||
totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait)
|
||||
@@ -123,17 +126,19 @@
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
|
||||
continue
|
||||
user.mind.auto_gain_experience(skill, I.skill_gain)
|
||||
|
||||
if(totitemdamage)
|
||||
visible_message("<span class='danger'>[user] has hit [src] with [I]!</span>", null, null, COMBAT_MESSAGE_RANGE)
|
||||
//only witnesses close by and the victim see a hit message.
|
||||
log_combat(user, src, "attacked", I)
|
||||
take_damage(totitemdamage, I.damtype, "melee", 1)
|
||||
return TRUE
|
||||
|
||||
/mob/living/attacked_by(obj/item/I, mob/living/user)
|
||||
var/totitemdamage = pre_attacked_by(I, user)
|
||||
if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, null, null) & BLOCK_SUCCESS)
|
||||
return FALSE
|
||||
send_item_attack_message(I, user)
|
||||
send_item_attack_message(I, user, null, totitemdamage)
|
||||
I.do_stagger_action(src, user, totitemdamage)
|
||||
if(I.force)
|
||||
apply_damage(totitemdamage, I.damtype)
|
||||
@@ -149,19 +154,37 @@
|
||||
/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user)
|
||||
if(I.force < force_threshold || I.damtype == STAMINA)
|
||||
playsound(loc, 'sound/weapons/tap.ogg', I.get_clamped_volume(), 1, -1)
|
||||
user.changeNext_move(I.click_delay) //pre_attacked_by not called
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user)
|
||||
. = I.force
|
||||
if(!.)
|
||||
return
|
||||
|
||||
var/stamloss = user.getStaminaLoss()
|
||||
var/stam_mobility_mult = 1
|
||||
var/next_move_mult = 1
|
||||
if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
|
||||
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
|
||||
stam_mobility_mult -= penalty
|
||||
next_move_mult += penalty*STAM_CRIT_ITEM_ATTACK_DELAY
|
||||
if(stam_mobility_mult > LYING_DAMAGE_PENALTY && !CHECK_MOBILITY(user, MOBILITY_STAND)) //damage penalty for fighting prone, doesn't stack with the above.
|
||||
stam_mobility_mult = LYING_DAMAGE_PENALTY
|
||||
. *= stam_mobility_mult
|
||||
user.changeNext_move(I.click_delay*next_move_mult)
|
||||
I.attack_delay_done = TRUE
|
||||
|
||||
var/bad_trait
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
. *= 0.5
|
||||
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
. *= 1.5
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
|
||||
. *= 0.5
|
||||
if(!(I.item_flags & NO_COMBAT_MODE_FORCE_MODIFIER))
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
|
||||
. *= 0.5
|
||||
else if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
. *= 1.5
|
||||
|
||||
if(!user.mind || !I.used_skills)
|
||||
return
|
||||
if(.)
|
||||
@@ -171,7 +194,6 @@
|
||||
continue
|
||||
user.mind.auto_gain_experience(skill, I.skill_gain)
|
||||
|
||||
|
||||
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
|
||||
// Click parameters is the params string from byond Click() code, see that documentation.
|
||||
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
@@ -185,10 +207,12 @@
|
||||
else
|
||||
return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
|
||||
|
||||
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
|
||||
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, current_force)
|
||||
var/message_verb = "attacked"
|
||||
if(I.attack_verb && I.attack_verb.len)
|
||||
message_verb = "[pick(I.attack_verb)]"
|
||||
if(current_force < I.force * INEFFICIENT_ATTACK_MSG_THRESHOLD)
|
||||
message_verb = "inefficiently [message_verb]"
|
||||
else if(!I.force)
|
||||
return
|
||||
var/message_hit_area = ""
|
||||
@@ -215,6 +239,8 @@
|
||||
bad_trait = SKILL_COMBAT_MODE
|
||||
if(used_skills && user.mind)
|
||||
. = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, bad_trait, FALSE)
|
||||
var/total_health = user.getStaminaLoss()
|
||||
. = clamp(., 0, STAMINA_NEAR_CRIT - total_health)
|
||||
|
||||
/// How long this staggers for. 0 and negatives supported.
|
||||
/obj/item/proc/melee_stagger_duration(force_override)
|
||||
|
||||
@@ -307,7 +307,11 @@ SUBSYSTEM_DEF(research)
|
||||
for(var/A in subtypesof(/obj/item/seeds))
|
||||
var/obj/item/seeds/S = A
|
||||
var/list/L = list()
|
||||
L[TECHWEB_POINT_TYPE_GENERIC] = 50 + initial(S.rarity) * 2
|
||||
//First we get are yield and rarity and times it by two
|
||||
//Then we subtract production and maturation, making it so faster growing plants are better for RnD
|
||||
//Then we add in lifespan and potency,
|
||||
//A basic seed can be worth 268 points if its the best it can be.
|
||||
L[TECHWEB_POINT_TYPE_GENERIC] = 50 + initial(S.rarity) * 2 + initial(S.yield) * 2 - initial(S.maturation) - initial(S.production) + initial(S.lifespan) + initial(S.potency)
|
||||
techweb_point_items[S] = L
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/datum/component/decal
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
can_transfer = TRUE
|
||||
var/cleanable
|
||||
var/description
|
||||
var/mutable_appearance/pic
|
||||
|
||||
var/first_dir // This only stores the dir arg from init
|
||||
|
||||
/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_GOD, _color, _layer=TURF_LAYER, _description, _alpha=255)
|
||||
if(!isatom(parent) || !generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
first_dir = _dir
|
||||
description = _description
|
||||
cleanable = _cleanable
|
||||
|
||||
apply()
|
||||
|
||||
/datum/component/decal/RegisterWithParent()
|
||||
. = ..()
|
||||
if(first_dir)
|
||||
RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_react)
|
||||
if(cleanable)
|
||||
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react)
|
||||
if(description)
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
|
||||
/datum/component/decal/UnregisterFromParent()
|
||||
. = ..()
|
||||
UnregisterSignal(parent, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE))
|
||||
|
||||
/datum/component/decal/Destroy()
|
||||
remove()
|
||||
return ..()
|
||||
|
||||
/datum/component/decal/PreTransfer()
|
||||
remove()
|
||||
|
||||
/datum/component/decal/PostTransfer()
|
||||
remove()
|
||||
apply()
|
||||
|
||||
/datum/component/decal/proc/generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha)
|
||||
if(!_icon || !_icon_state)
|
||||
return FALSE
|
||||
// It has to be made from an image or dir breaks because of a byond bug
|
||||
var/temp_image = image(_icon, null, _icon_state, _layer, _dir)
|
||||
pic = new(temp_image)
|
||||
pic.color = _color
|
||||
pic.alpha = _alpha
|
||||
return TRUE
|
||||
|
||||
/datum/component/decal/proc/apply(atom/thing)
|
||||
var/atom/master = thing || parent
|
||||
master.add_overlay(pic, TRUE)
|
||||
if(isitem(master))
|
||||
addtimer(CALLBACK(master, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
|
||||
|
||||
/datum/component/decal/proc/remove(atom/thing)
|
||||
var/atom/master = thing || parent
|
||||
master.cut_overlay(pic, TRUE)
|
||||
if(isitem(master))
|
||||
addtimer(CALLBACK(master, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
|
||||
|
||||
/datum/component/decal/proc/rotate_react(datum/source, old_dir, new_dir)
|
||||
if(old_dir == new_dir)
|
||||
return
|
||||
remove()
|
||||
pic.dir = turn(pic.dir, dir2angle(old_dir) - dir2angle(new_dir))
|
||||
apply()
|
||||
|
||||
/datum/component/decal/proc/clean_react(datum/source, strength)
|
||||
if(strength >= cleanable)
|
||||
qdel(src)
|
||||
|
||||
/datum/component/decal/proc/examine(datum/source, mob/user, list/examine_list)
|
||||
examine_list += description
|
||||
@@ -1,13 +0,0 @@
|
||||
/datum/component/decal/blood
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
|
||||
/datum/component/decal/blood/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_STRENGTH_BLOOD, _color, _layer=ABOVE_OBJ_LAYER)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_ATOM_GET_EXAMINE_NAME, .proc/get_examine_name)
|
||||
|
||||
/datum/component/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override)
|
||||
var/atom/A = parent
|
||||
|
||||
return COMPONENT_EXNAME_CHANGED
|
||||
@@ -73,7 +73,7 @@
|
||||
if(!material_amount)
|
||||
to_chat(user, "<span class='warning'>[I] does not contain sufficient materials to be accepted by [parent].</span>")
|
||||
return
|
||||
if((!precise_insertion || !GLOB.typecache_stack[I]) && !has_space(material_amount))
|
||||
if((!precise_insertion || !GLOB.typecache_stack[I.type]) && !has_space(material_amount))
|
||||
to_chat(user, "<span class='warning'>[parent] has not enough space. Please remove materials from [parent] in order to insert more.</span>")
|
||||
return
|
||||
user_insert(I, user)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
var/mob/living/owner = parent
|
||||
if(owner.stat != DEAD)
|
||||
START_PROCESSING(SSdcs, src)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/add_event)
|
||||
RegisterSignal(parent, COMSIG_CLEAR_MOOD_EVENT, .proc/clear_event)
|
||||
@@ -40,12 +40,12 @@
|
||||
hud.show_hud(hud.hud_version)
|
||||
|
||||
/datum/component/mood/Destroy()
|
||||
STOP_PROCESSING(SSdcs, src)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
unmodify_hud()
|
||||
return ..()
|
||||
|
||||
/datum/component/mood/proc/stop_processing()
|
||||
STOP_PROCESSING(SSdcs, src)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/component/mood/proc/print_mood(mob/user)
|
||||
var/msg = "<span class='info'>*---------*\n<EM>Your current mood</EM>\n"
|
||||
@@ -138,7 +138,7 @@
|
||||
else
|
||||
screen_obj.icon_state = "mood[mood_level]"
|
||||
|
||||
/datum/component/mood/process() //Called on SSdcs process
|
||||
/datum/component/mood/process() //Called on SSobj process
|
||||
if(QDELETED(parent)) // workaround to an obnoxious sneaky periodical runtime.
|
||||
qdel(src)
|
||||
return
|
||||
@@ -345,7 +345,7 @@
|
||||
|
||||
///Called when parent is revived.
|
||||
/datum/component/mood/proc/on_revive(datum/source, full_heal)
|
||||
START_PROCESSING(SSdcs, src)
|
||||
START_PROCESSING(SSobj, src)
|
||||
if(!full_heal)
|
||||
return
|
||||
remove_temp_moods()
|
||||
|
||||
@@ -62,7 +62,9 @@
|
||||
orbiters[orbiter] = TRUE
|
||||
orbiter.orbiting = src
|
||||
RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, .proc/orbiter_move_react)
|
||||
|
||||
var/matrix/initial_transform = matrix(orbiter.transform)
|
||||
orbiters[orbiter] = initial_transform
|
||||
|
||||
// Head first!
|
||||
if(pre_rotation)
|
||||
@@ -79,8 +81,6 @@
|
||||
|
||||
orbiter.SpinAnimation(rotation_speed, -1, clockwise, rotation_segments, parallel = FALSE)
|
||||
|
||||
//we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
|
||||
orbiter.transform = initial_transform
|
||||
orbiter.forceMove(get_turf(parent))
|
||||
to_chat(orbiter, "<span class='notice'>Now orbiting [parent].</span>")
|
||||
|
||||
@@ -89,6 +89,8 @@
|
||||
return
|
||||
UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED)
|
||||
orbiter.SpinAnimation(0, 0)
|
||||
if(istype(orbiters[orbiter],/matrix)) //This is ugly.
|
||||
orbiter.transform = orbiters[orbiter]
|
||||
orbiters -= orbiter
|
||||
orbiter.stop_orbit(src)
|
||||
orbiter.orbiting = null
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
/obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper,
|
||||
/obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini,
|
||||
/obj/item/firing_pin, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/automatic/magrifle/pistol,
|
||||
/obj/item/toy/plush/snakeplushie
|
||||
/obj/item/toy/plush/snakeplushie, /obj/item/gun/energy/e_gun/mini
|
||||
))
|
||||
|
||||
/datum/component/storage/concrete/pockets/shoes/clown/Initialize()
|
||||
@@ -68,7 +68,7 @@
|
||||
/obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector,
|
||||
/obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper,
|
||||
/obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini,
|
||||
/obj/item/firing_pin, /obj/item/bikehorn, /obj/item/gun/ballistic/automatic/pistol))
|
||||
/obj/item/firing_pin, /obj/item/bikehorn, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/energy/e_gun/mini))
|
||||
|
||||
/datum/component/storage/concrete/pockets/pocketprotector
|
||||
max_items = 3
|
||||
|
||||
@@ -163,24 +163,24 @@
|
||||
if(-4 to -2) // glancing blow at best
|
||||
user.visible_message("<span class='warning'>[user] lands a weak [tackle_word] on [target], briefly knocking [target.p_them()] off-balance!</span>", "<span class='userdanger'>You land a weak [tackle_word] on [target], briefly knocking [target.p_them()] off-balance!</span>", target)
|
||||
to_chat(target, "<span class='userdanger'>[user] lands a weak [tackle_word] on you, briefly knocking you off-balance!</span>")
|
||||
|
||||
user.Knockdown(30)
|
||||
target.adjustStaminaLoss(15)
|
||||
target.apply_status_effect(STATUS_EFFECT_TASED_WEAK, 6 SECONDS)
|
||||
|
||||
if(-1 to 0) // decent hit, both parties are about equally inconvenienced
|
||||
user.visible_message("<span class='warning'>[user] lands a passable [tackle_word] on [target], sending them both tumbling!</span>", "<span class='userdanger'>You land a passable [tackle_word] on [target], sending you both tumbling!</span>", target)
|
||||
to_chat(target, "<span class='userdanger'>[user] lands a passable [tackle_word] on you, sending you both tumbling!</span>")
|
||||
|
||||
target.adjustStaminaLoss(stamina_cost)
|
||||
target.adjustStaminaLoss(stamina_cost * 1.5)
|
||||
target.Paralyze(5)
|
||||
user.Knockdown(20)
|
||||
target.Knockdown(25)
|
||||
target.Knockdown(30)
|
||||
|
||||
if(1 to 2) // solid hit, tackler has a slight advantage
|
||||
user.visible_message("<span class='warning'>[user] lands a solid [tackle_word] on [target], knocking them both down hard!</span>", "<span class='userdanger'>You land a solid [tackle_word] on [target], knocking you both down hard!</span>", target)
|
||||
to_chat(target, "<span class='userdanger'>[user] lands a solid [tackle_word] on you, knocking you both down hard!</span>")
|
||||
|
||||
target.adjustStaminaLoss(30)
|
||||
target.adjustStaminaLoss(40)
|
||||
target.Paralyze(5)
|
||||
user.Knockdown(10)
|
||||
target.Knockdown(20)
|
||||
@@ -192,9 +192,9 @@
|
||||
user.SetKnockdown(0)
|
||||
user.set_resting(FALSE, TRUE, FALSE)
|
||||
user.forceMove(get_turf(target))
|
||||
target.adjustStaminaLoss(40)
|
||||
target.Paralyze(5)
|
||||
target.Knockdown(30)
|
||||
target.adjustStaminaLoss(50)
|
||||
target.Paralyze(3) //Otherwise the victim can just instantly get out of the grab.
|
||||
target.DefaultCombatKnockdown(20) //So they cant get up instantly.
|
||||
if(ishuman(target) && iscarbon(user))
|
||||
target.grabbedby(user)
|
||||
|
||||
@@ -205,9 +205,9 @@
|
||||
user.SetKnockdown(0)
|
||||
user.set_resting(FALSE, TRUE, FALSE)
|
||||
user.forceMove(get_turf(target))
|
||||
target.adjustStaminaLoss(40)
|
||||
target.Paralyze(5)
|
||||
target.Knockdown(30)
|
||||
target.adjustStaminaLoss(65)
|
||||
target.Paralyze(10)
|
||||
target.DefaultCombatKnockdown(20)
|
||||
if(ishuman(target) && iscarbon(user))
|
||||
target.grabbedby(user)
|
||||
target.grippedby(user, instant = TRUE)
|
||||
|
||||
@@ -175,11 +175,6 @@
|
||||
name = "Trooper REAL_NAME"
|
||||
desc = "That's not red paint. That's real corgi blood."
|
||||
|
||||
/datum/dog_fashion/head/colour
|
||||
name = "Stylish REAL_NAME"
|
||||
desc = "From the tips of their paws to the top of their head, they look like a made bed."
|
||||
emote_see = list("tries to tap dances.","looks sadly at others outfits...","barks at bad fashion!")
|
||||
|
||||
/datum/dog_fashion/head/telegram
|
||||
name = "Messenger REAL_NAME"
|
||||
desc = "Dont shoot the messenger..."
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/datum/element/decal
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
id_arg_index = 2
|
||||
var/cleanable
|
||||
var/description
|
||||
var/mutable_appearance/pic
|
||||
var/list/num_decals_per_atom
|
||||
|
||||
var/first_dir // This stores the direction of the decal compared to the parent facing NORTH
|
||||
|
||||
/datum/element/decal/Attach(datum/target, _icon, _icon_state, _dir, _cleanable=CLEAN_GOD, _color, _layer=TURF_LAYER, _description, _alpha=255)
|
||||
. = ..()
|
||||
if(. == ELEMENT_INCOMPATIBLE || !_icon || !_icon_state || !isatom(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
var/atom/A = target
|
||||
if(!pic)
|
||||
// It has to be made from an image or dir breaks because of a byond bug
|
||||
var/temp_image = image(_icon, null, _icon_state, _layer, _dir)
|
||||
pic = new(temp_image)
|
||||
pic.color = _color
|
||||
pic.alpha = _alpha
|
||||
first_dir = _dir
|
||||
description = _description
|
||||
cleanable = _cleanable
|
||||
|
||||
LAZYINITLIST(num_decals_per_atom)
|
||||
|
||||
if(!num_decals_per_atom[A])
|
||||
if(first_dir)
|
||||
RegisterSignal(A, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_react)
|
||||
if(cleanable)
|
||||
RegisterSignal(A, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react)
|
||||
if(description)
|
||||
RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
|
||||
apply(A, TRUE)
|
||||
|
||||
num_decals_per_atom[A]++
|
||||
|
||||
/datum/element/decal/Detach(datum/target)
|
||||
var/atom/A = target
|
||||
remove(A, A.dir)
|
||||
UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE))
|
||||
LAZYREMOVE(num_decals_per_atom, A)
|
||||
return ..()
|
||||
|
||||
/datum/element/decal/proc/remove(atom/target, old_dir)
|
||||
pic.dir = first_dir == NORTH ? target.dir : turn(first_dir, dir2angle(old_dir))
|
||||
for(var/i in 1 to num_decals_per_atom[target])
|
||||
target.cut_overlay(pic, TRUE)
|
||||
if(isitem(target))
|
||||
addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
|
||||
|
||||
/datum/element/decal/proc/apply(atom/target, init = FALSE)
|
||||
pic.dir = first_dir == NORTH ? target.dir : turn(first_dir, dir2angle(target.dir))
|
||||
if(init)
|
||||
target.add_overlay(pic, TRUE)
|
||||
else
|
||||
for(var/i in 1 to num_decals_per_atom[target])
|
||||
target.add_overlay(pic, TRUE)
|
||||
if(isitem(target))
|
||||
addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
|
||||
|
||||
/datum/element/decal/proc/rotate_react(datum/source, old_dir, new_dir)
|
||||
if(old_dir == new_dir)
|
||||
return
|
||||
remove(source, old_dir)
|
||||
apply(source)
|
||||
|
||||
/datum/element/decal/proc/clean_react(datum/source, strength)
|
||||
if(strength >= cleanable)
|
||||
Detach(source)
|
||||
|
||||
/datum/element/decal/proc/examine(datum/source, mob/user, list/examine_list)
|
||||
examine_list += description
|
||||
@@ -4,7 +4,7 @@
|
||||
var/list/user_by_item = list()
|
||||
|
||||
/datum/element/earhealing/New()
|
||||
START_PROCESSING(SSdcs, src)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/element/earhealing/Attach(datum/target)
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/datum/element/photosynthesis
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
id_arg_index = 2
|
||||
///how much brute damage (or integrity, for objects) is healed (taken if positive) at maximum luminosity. (if lum_minus were 0)
|
||||
var/light_bruteheal = -1
|
||||
///how much burn damage is restored/taken at maximum luminosity. Mobs only.
|
||||
var/light_burnheal = -1
|
||||
///how much tox damage is restored/taken at maximum luminosity. Mobs only.
|
||||
var/light_toxheal = -1
|
||||
///how much oxy damage is restored/taken at maximum luminosity. Mobs only.
|
||||
var/light_oxyheal = -1
|
||||
///how nutrition recovery/expenses factor, not affected by bonus_lum and malus_lum. Mobs only.
|
||||
var/light_nutrition_gain = 4
|
||||
///A value subtracted to the lum count, which allows targets to wilt or heal in the darkness.
|
||||
var/lum_minus = 0.5
|
||||
///the minimum lum count over which where the target damage is adjusted.
|
||||
var/bonus_lum = 0.2
|
||||
///the maximum lum count under which the target damage is inversely adjusted.
|
||||
var/malus_lum = 0
|
||||
///List of atoms this element is attached to. Doubles as a multiplier if the same element is attached multiple times to a target multiple times.
|
||||
var/list/attached_atoms
|
||||
|
||||
/datum/element/photosynthesis/Attach(datum/target, brute = -1, burn = -1, tox = -1, oxy = -1, nutri = 4, minus = 0.2, bonus = 0.3, malus = -0.1)
|
||||
. = ..()
|
||||
if(. == ELEMENT_INCOMPATIBLE || !(isliving(target) || (isobj(target) && light_bruteheal)))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
light_bruteheal = brute
|
||||
light_burnheal = burn
|
||||
light_toxheal = tox
|
||||
light_oxyheal = oxy
|
||||
light_nutrition_gain = nutri
|
||||
lum_minus = minus
|
||||
bonus_lum = bonus
|
||||
malus_lum = malus
|
||||
|
||||
if(!attached_atoms)
|
||||
attached_atoms = list()
|
||||
START_PROCESSING(SSobj, src)
|
||||
attached_atoms[target]++
|
||||
|
||||
/datum/element/photosynthesis/Detach(datum/target)
|
||||
attached_atoms[target]--
|
||||
if(!attached_atoms[target])
|
||||
attached_atoms -= target
|
||||
if(!length(attached_atoms))
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
attached_atoms = null
|
||||
return ..()
|
||||
|
||||
/datum/element/photosynthesis/process()
|
||||
for(var/A in attached_atoms)
|
||||
var/atom/movable/AM = A
|
||||
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
|
||||
if(isturf(AM.loc)) //else, there's considered to be no light
|
||||
var/turf/T = AM.loc
|
||||
light_amount = (T.get_lumcount() - lum_minus)
|
||||
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.stat == DEAD)
|
||||
continue
|
||||
if(light_nutrition_gain)
|
||||
L.adjust_nutrition(light_amount * light_nutrition_gain * attached_atoms[AM], NUTRITION_LEVEL_FULL)
|
||||
if(light_amount > bonus_lum || light_amount < malus_lum)
|
||||
var/mult = ((light_amount > bonus_lum) ? 1 : -1) * attached_atoms[AM]
|
||||
if(light_bruteheal)
|
||||
L.adjustBruteLoss(light_bruteheal * mult)
|
||||
if(light_burnheal)
|
||||
L.adjustFireLoss(light_burnheal * mult)
|
||||
if(light_toxheal)
|
||||
L.adjustToxLoss(light_toxheal * mult)
|
||||
if(light_oxyheal)
|
||||
L.adjustOxyLoss(light_oxyheal * mult)
|
||||
|
||||
else if(light_amount > bonus_lum || light_amount < malus_lum)
|
||||
var/obj/O = AM
|
||||
var/damage = light_bruteheal * ((light_amount > bonus_lum) ? 1 : -1) * attached_atoms[AM]
|
||||
if(damage < 0 && O.obj_integrity < O.max_integrity)
|
||||
O.obj_integrity = min(O.obj_integrity + damage, O.max_integrity) //Till we get a obj heal proc...
|
||||
else
|
||||
O.take_damage(damage, BRUTE, FALSE, FALSE, null, 100)
|
||||
+8
-2
@@ -331,14 +331,20 @@
|
||||
|
||||
/datum/mind/proc/enslave_mind_to_creator(mob/living/creator)
|
||||
if(iscultist(creator))
|
||||
SSticker.mode.add_cultist(src)
|
||||
if(iscultist(creator, TRUE))
|
||||
SSticker.mode.add_cultist(src)
|
||||
else
|
||||
src.add_antag_datum(/datum/antagonist/cult/neutered/traitor)
|
||||
|
||||
else if(is_revolutionary(creator))
|
||||
var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE)
|
||||
converter.add_revolutionary(src,FALSE)
|
||||
|
||||
else if(is_servant_of_ratvar(creator))
|
||||
add_servant_of_ratvar(current)
|
||||
if(is_servant_of_ratvar(creator, TRUE))
|
||||
add_servant_of_ratvar(current)
|
||||
else
|
||||
add_servant_of_ratvar(current, FALSE, FALSE, /datum/antagonist/clockcult/neutered/traitor)
|
||||
|
||||
else if(is_nuclear_operative(creator))
|
||||
var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
|
||||
@@ -173,6 +173,11 @@
|
||||
port_id = "snowdin"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/snow_taxi
|
||||
port_id = "snow"
|
||||
can_be_bought = FALSE
|
||||
suffix = "taxi"
|
||||
|
||||
// Shuttles start here:
|
||||
|
||||
/datum/map_template/shuttle/emergency/backup
|
||||
@@ -560,6 +565,10 @@
|
||||
suffix = "cog"
|
||||
name = "arrival shuttle (Cog)"
|
||||
|
||||
/datum/map_template/shuttle/arrival/snaxi
|
||||
suffix = "snaxi"
|
||||
name = "arrival shuttle (Snaxi)"
|
||||
|
||||
/datum/map_template/shuttle/aux_base/default
|
||||
suffix = "default"
|
||||
name = "auxilliary base (Default)"
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
/datum/mind/proc/skill_html_readout()
|
||||
var/list/out = list("<center><h1>Skills</h1></center><hr>")
|
||||
out += "<table style=\"width:100%\"><tr><th><b>Skill</b><th><b>Value</b></tr>"
|
||||
for(var/path in skill_holder.skills|skill_holder.skill_value_mods|skill_holder.skill_level_mods)
|
||||
for(var/path in GLOB.skill_datums)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
var/skill_value = get_skill_value(path)
|
||||
var/skill_level = get_skill_level(path, round = TRUE)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
area_type = /area
|
||||
protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer,
|
||||
/area/ai_monitored/turret_protected/ai, /area/storage/emergency/starboard, /area/storage/emergency/port, /area/shuttle, /area/security/prison, /area/ruin, /area/space/nearstation)
|
||||
/area/ai_monitored/turret_protected/ai, /area/storage/emergency/starboard, /area/storage/emergency/port, /area/shuttle, /area/security/prison, /area/ruin, /area/space/nearstation, /area/icemoon)
|
||||
target_trait = ZTRAIT_STATION
|
||||
|
||||
immunity_type = "rad"
|
||||
|
||||
@@ -200,4 +200,7 @@
|
||||
name = "Tiny Freighter"
|
||||
|
||||
/area/shuttle/caravan/freighter3
|
||||
name = "Tiny Freighter"
|
||||
name = "Tiny Freighter"
|
||||
|
||||
/area/shuttle/snowtaxi
|
||||
name = "Snow Taxi"
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
|
||||
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/dominator/attack_hand(mob/user)
|
||||
if(operating || (stat & BROKEN))
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
targetitem = /obj/item/gun/energy/e_gun/hos
|
||||
difficulty = 10
|
||||
excludefromjob = list("Head Of Security")
|
||||
altitems = list(/obj/item/gun/ballistic/revolver/mws)
|
||||
altitems = list(/obj/item/gun/ballistic/revolver/mws, /obj/item/choice_beacon/hosgun) //We now look for eather the alt verson of the hos gun or the beacon picker.
|
||||
|
||||
/datum/objective_item/steal/handtele
|
||||
name = "a hand teleporter."
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/porta_turret_cover/attacked_by(obj/item/I, mob/user)
|
||||
parent_turret.attacked_by(I, user)
|
||||
return parent_turret.attacked_by(I, user)
|
||||
|
||||
/obj/machinery/porta_turret_cover/attack_alien(mob/living/carbon/alien/humanoid/user)
|
||||
parent_turret.attack_alien(user)
|
||||
|
||||
@@ -100,44 +100,61 @@
|
||||
eat(AM)
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/recycler/proc/eat(atom/AM0, sound=TRUE)
|
||||
/obj/machinery/recycler/proc/eat(atom/AM0)
|
||||
if(stat & (BROKEN|NOPOWER) || safety_mode)
|
||||
return
|
||||
|
||||
var/list/to_eat
|
||||
|
||||
to_eat = AM0.GetAllContentsIgnoring(GLOB.typecache_mob)
|
||||
to_eat = list(AM0)
|
||||
|
||||
var/items_recycled = 0
|
||||
var/buzz = FALSE
|
||||
for(var/i in to_eat)
|
||||
var/atom/movable/AM = i
|
||||
if(QDELETED(AM))
|
||||
continue
|
||||
var/obj/item/bodypart/head/as_head = AM
|
||||
var/obj/item/mmi/as_mmi = AM
|
||||
var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || isbrain(AM) || istype(AM, /obj/item/dullahan_relay)
|
||||
var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /obj/item/dullahan_relay)
|
||||
if(brain_holder)
|
||||
emergency_stop(AM)
|
||||
else if(isliving(AM))
|
||||
if((obj_flags & EMAGGED)||((!allowed(AM))&&(!ishuman(AM))))
|
||||
crush_living(AM)
|
||||
if(obj_flags & EMAGGED)
|
||||
continue
|
||||
else
|
||||
emergency_stop(AM)
|
||||
return
|
||||
else if(isliving(AM))
|
||||
if((obj_flags & EMAGGED)||((!allowed(AM))&&(!ishuman(AM))))
|
||||
to_eat += crush_living(AM)
|
||||
else
|
||||
emergency_stop(AM)
|
||||
return
|
||||
else if(isitem(AM))
|
||||
var/obj/O = AM
|
||||
if(O.resistance_flags & INDESTRUCTIBLE)
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
buzz = TRUE
|
||||
O.forceMove(loc)
|
||||
else
|
||||
recycle_item(AM)
|
||||
to_eat += recycle_item(AM)
|
||||
items_recycled++
|
||||
else
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
buzz = TRUE
|
||||
AM.forceMove(loc)
|
||||
|
||||
if(items_recycled && sound)
|
||||
if(items_recycled)
|
||||
playsound(src, item_recycle_sound, 50, 1)
|
||||
if(buzz)
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
|
||||
/obj/machinery/recycler/proc/recycle_item(obj/item/I)
|
||||
|
||||
. = list()
|
||||
for(var/A in I)
|
||||
var/atom/movable/AM = A
|
||||
AM.forceMove(loc)
|
||||
if(AM.loc == loc)
|
||||
. += AM
|
||||
|
||||
I.forceMove(loc)
|
||||
var/obj/item/grown/log/L = I
|
||||
if(istype(L))
|
||||
@@ -172,6 +189,7 @@
|
||||
|
||||
/obj/machinery/recycler/proc/crush_living(mob/living/L)
|
||||
|
||||
. = list()
|
||||
L.forceMove(loc)
|
||||
|
||||
if(issilicon(L))
|
||||
@@ -193,7 +211,7 @@
|
||||
if(eat_victim_items)
|
||||
for(var/obj/item/I in L.get_equipped_items(TRUE))
|
||||
if(L.dropItemToGround(I))
|
||||
eat(I, sound=FALSE)
|
||||
. += I
|
||||
|
||||
// Instantly lie down, also go unconscious from the pain, before you die.
|
||||
L.Unconscious(100)
|
||||
|
||||
@@ -9,7 +9,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
#define NO_NEW_MESSAGE 0
|
||||
#define NORMAL_MESSAGE_PRIORITY 1
|
||||
#define HIGH_MESSAGE_PRIORITY 2
|
||||
#define EXTREME_MESSAGE_PRIORITY 3 // not implemented, will probably require some hacking... everything needs to have a hidden feature in this game.
|
||||
#define EXTREME_MESSAGE_PRIORITY 3 // is implimented, does require hacking. everything needs to have a hidden feature in this game.
|
||||
|
||||
/obj/machinery/requests_console
|
||||
name = "requests console"
|
||||
@@ -48,9 +48,9 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
var/announceAuth = FALSE //Will be set to 1 when you authenticate yourself for announcements
|
||||
var/msgVerified = "" //Will contain the name of the person who verified it
|
||||
var/msgStamped = "" //If a message is stamped, this will contain the stamp name
|
||||
var/message = "";
|
||||
var/dpt = ""; //the department which will be receiving the message
|
||||
var/priority = -1 ; //Priority of the message being sent
|
||||
var/message = ""
|
||||
var/dpt = "" //the department which will be receiving the message
|
||||
var/priority = NORMAL_MESSAGE_PRIORITY //Priority of the message being sent. why is the default -1??
|
||||
var/obj/item/radio/Radio
|
||||
var/emergency //If an emergency has been called by this device. Acts as both a cooldown and lets the responder know where it the emergency was triggered from
|
||||
var/receive_ore_updates = FALSE //If ore redemption machines will send an update when it receives new ores.
|
||||
@@ -62,16 +62,17 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/requests_console/update_icon_state()
|
||||
if(stat & NOPOWER)
|
||||
if(CHECK_BITFIELD(stat, NOPOWER))
|
||||
set_light(0)
|
||||
else
|
||||
set_light(1.4,0.7,"#34D352")//green light
|
||||
set_light(1.4, 0.7, "#34D352")//green light
|
||||
|
||||
if(open)
|
||||
if(!hackState)
|
||||
icon_state="req_comp_open"
|
||||
else
|
||||
icon_state="req_comp_rewired"
|
||||
else if(stat & NOPOWER)
|
||||
else if(CHECK_BITFIELD(stat, NOPOWER))
|
||||
if(icon_state != "req_comp_off")
|
||||
icon_state = "req_comp_off"
|
||||
else
|
||||
@@ -122,7 +123,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
GLOB.req_console_information += department
|
||||
|
||||
Radio = new /obj/item/radio(src)
|
||||
Radio.listening = 0
|
||||
Radio.listening = FALSE
|
||||
|
||||
/obj/machinery/requests_console/Destroy()
|
||||
QDEL_NULL(Radio)
|
||||
@@ -131,164 +132,173 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
|
||||
/obj/machinery/requests_console/ui_interact(mob/user)
|
||||
. = ..()
|
||||
if(open) //no.
|
||||
return
|
||||
|
||||
var/dat = ""
|
||||
if(!open)
|
||||
switch(screen)
|
||||
if(1) //req. assistance
|
||||
dat += "Which department do you need assistance from?<BR><BR>"
|
||||
dat += "<table width='100%'>"
|
||||
for(var/dpt in GLOB.req_console_assistance)
|
||||
if (dpt != department)
|
||||
dat += "<tr>"
|
||||
dat += "<td width='55%'>[dpt]</td>"
|
||||
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
|
||||
if(hackState)
|
||||
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
|
||||
switch(screen)
|
||||
if(1) //req. assistance
|
||||
dat += "Which department do you need assistance from?<br><br>"
|
||||
dat += "<table width='100%'>"
|
||||
for(var/dpt in GLOB.req_console_assistance)
|
||||
if(dpt == department)
|
||||
continue
|
||||
dat += "<tr>"
|
||||
dat += "<td width='55%'>[dpt]</td>"
|
||||
dat += "<td width='45%'>"
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
|
||||
if(hackState)
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<br><A href='?src=[REF(src)];setScreen=0'><< Back</A><br>"
|
||||
|
||||
if(2) //req. supplies
|
||||
dat += "Which department do you need supplies from?<BR><BR>"
|
||||
dat += "<table width='100%'>"
|
||||
for(var/dpt in GLOB.req_console_supplies)
|
||||
if (dpt != department)
|
||||
dat += "<tr>"
|
||||
dat += "<td width='55%'>[dpt]</td>"
|
||||
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
|
||||
if(hackState)
|
||||
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
|
||||
if(2) //req. supplies
|
||||
dat += "Which department do you need supplies from?<br><br>"
|
||||
dat += "<table width='100%'>"
|
||||
for(var/dpt in GLOB.req_console_supplies)
|
||||
if(dpt == department)
|
||||
continue
|
||||
|
||||
if(3) //relay information
|
||||
dat += "Which department would you like to send information to?<BR><BR>"
|
||||
dat += "<table width='100%'>"
|
||||
for(var/dpt in GLOB.req_console_information)
|
||||
if (dpt != department)
|
||||
dat += "<tr>"
|
||||
dat += "<td width='55%'>[dpt]</td>"
|
||||
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
|
||||
if(hackState)
|
||||
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
|
||||
dat += "<tr>"
|
||||
dat += "<td width='55%'>[dpt]</td>"
|
||||
dat += "<td width='45%'>"
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
|
||||
if(hackState)
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<br><A href='?src=[REF(src)];setScreen=0'><< Back</A><br>"
|
||||
|
||||
if(6) //sent successfully
|
||||
dat += "<span class='good'>Message sent.</span><BR><BR>"
|
||||
dat += "<A href='?src=[REF(src)];setScreen=0'>Continue</A><BR>"
|
||||
if(3) //relay information
|
||||
dat += "Which department would you like to send information to?<br><br>"
|
||||
dat += "<table width='100%'>"
|
||||
for(var/dpt in GLOB.req_console_information)
|
||||
if(dpt == department)
|
||||
continue
|
||||
dat += "<tr>"
|
||||
dat += "<td width='55%'>[dpt]</td>"
|
||||
dat += "<td width='45%'>"
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
|
||||
if(hackState)
|
||||
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back</a><br>"
|
||||
|
||||
if(7) //unsuccessful; not sent
|
||||
dat += "<span class='bad'>An error occurred.</span><BR><BR>"
|
||||
dat += "<A href='?src=[REF(src)];setScreen=0'>Continue</A><BR>"
|
||||
if(6) //sent successfully
|
||||
dat += "<span class='good'>Message sent.</span><br><br>"
|
||||
dat += "<a href='?src=[REF(src)];setScreen=0'>Continue</a><br>"
|
||||
|
||||
if(8) //view messages
|
||||
for (var/obj/machinery/requests_console/Console in GLOB.allConsoles)
|
||||
if (Console.department == department)
|
||||
Console.newmessagepriority = NO_NEW_MESSAGE
|
||||
Console.update_icon()
|
||||
if(7) //unsuccessful; not sent
|
||||
dat += "<span class='bad'>An error occurred.</span><br><br>"
|
||||
dat += "<a href='?src=[REF(src)];setScreen=0'>Continue</a><br>"
|
||||
|
||||
newmessagepriority = NO_NEW_MESSAGE
|
||||
update_icon()
|
||||
var/messageComposite = ""
|
||||
for(var/msg in messages) // This puts more recent messages at the *top*, where they belong.
|
||||
messageComposite = "<div class='block'>[msg]</div>" + messageComposite
|
||||
dat += messageComposite
|
||||
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back to Main Menu</A><BR>"
|
||||
if(8) //view messages
|
||||
for(var/obj/machinery/requests_console/Console in GLOB.allConsoles)
|
||||
if(Console.department == department)
|
||||
Console.newmessagepriority = NO_NEW_MESSAGE
|
||||
Console.update_icon()
|
||||
|
||||
if(9) //authentication before sending
|
||||
dat += "<B>Message Authentication</B><BR><BR>"
|
||||
dat += "<b>Message for [dpt]: </b>[message]<BR><BR>"
|
||||
dat += "<div class='notice'>You may authenticate your message now by scanning your ID or your stamp</div><BR>"
|
||||
dat += "<b>Validated by:</b> [msgVerified ? msgVerified : "<i>Not Validated</i>"]<br>"
|
||||
dat += "<b>Stamped by:</b> [msgStamped ? msgStamped : "<i>Not Stamped</i>"]<br><br>"
|
||||
dat += "<A href='?src=[REF(src)];department=[dpt]'>Send Message</A><BR>"
|
||||
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Discard Message</A><BR>"
|
||||
newmessagepriority = NO_NEW_MESSAGE
|
||||
update_icon()
|
||||
var/messageComposite = ""
|
||||
for(var/msg in messages) // This puts more recent messages at the *top*, where they belong.
|
||||
messageComposite = "<div class='block'>[msg]</div>" + messageComposite
|
||||
dat += messageComposite
|
||||
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back to Main Menu</a><br>"
|
||||
|
||||
if(10) //send announcement
|
||||
dat += "<h3>Station-wide Announcement</h3>"
|
||||
if(announceAuth)
|
||||
dat += "<div class='notice'>Authentication accepted</div><BR>"
|
||||
else
|
||||
dat += "<div class='notice'>Swipe your card to authenticate yourself</div><BR>"
|
||||
dat += "<b>Message: </b>[message ? message : "<i>No Message</i>"]<BR>"
|
||||
dat += "<A href='?src=[REF(src)];writeAnnouncement=1'>[message ? "Edit" : "Write"] Message</A><BR><BR>"
|
||||
if ((announceAuth || IsAdminGhost(user)) && message)
|
||||
dat += "<A href='?src=[REF(src)];sendAnnouncement=1'>Announce Message</A><BR>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Announce Message</span><BR>"
|
||||
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
|
||||
if(9) //authentication before sending
|
||||
dat += "<b>Message Authentication</b> <br><br>"
|
||||
dat += "<b>Message for [dpt]:</b> [message] <br><br>"
|
||||
dat += "<div class='notice'>You may authenticate your message now by scanning your ID or your stamp</div> <br>"
|
||||
|
||||
dat += "<b>Validated by:</b> [msgVerified ? "<span class='good'><b>[msgVerified]</b></span>" : "<i>Not Validated</i>"] <br>"
|
||||
dat += "<b>Stamped by:</b> [msgStamped ? "<span class='boldnotice'>[msgStamped]</span>" : "<i>Not Stamped</i>"] <br><br>"
|
||||
|
||||
dat += "<a href='?src=[REF(src)];department=[dpt]'>Send Message</a> <br><br>"
|
||||
dat += "<a href='?src=[REF(src)];setScreen=0'><< Discard Message</a> <br>"
|
||||
|
||||
else //main menu
|
||||
screen = 0
|
||||
announceAuth = FALSE
|
||||
if (newmessagepriority == NORMAL_MESSAGE_PRIORITY)
|
||||
dat += "<div class='notice'>There are new messages</div><BR>"
|
||||
if (newmessagepriority == HIGH_MESSAGE_PRIORITY)
|
||||
dat += "<div class='notice'>There are new <b>PRIORITY</b> messages</div><BR>"
|
||||
if (newmessagepriority == EXTREME_MESSAGE_PRIORITY)
|
||||
dat += "<div class='notice'>There are new <b>EXTREME PRIORITY</b> messages</div><BR>"
|
||||
dat += "<A href='?src=[REF(src)];setScreen=8'>View Messages</A><BR><BR>"
|
||||
if(10) //send announcement
|
||||
dat += "<h3>Station-wide Announcement</h3>"
|
||||
if(announceAuth)
|
||||
dat += "<div class='notice'>Authentication accepted</div><br>"
|
||||
else
|
||||
dat += "<div class='notice'>Swipe your card to authenticate yourself</div> <br>"
|
||||
dat += "<b>Message: </b>[message ? message : "<i>No Message</i>"] <br>"
|
||||
dat += "<a href='?src=[REF(src)];writeAnnouncement=1'>[message ? "Edit" : "Write"] Message</a> <br><br>"
|
||||
if((announceAuth || IsAdminGhost(user)) && message)
|
||||
dat += "<a href='?src=[REF(src)];sendAnnouncement=1'>Announce Message</a> <br>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Announce Message</span> <br>"
|
||||
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back</a> <br>"
|
||||
|
||||
dat += "<A href='?src=[REF(src)];setScreen=1'>Request Assistance</A><BR>"
|
||||
dat += "<A href='?src=[REF(src)];setScreen=2'>Request Supplies</A><BR>"
|
||||
dat += "<A href='?src=[REF(src)];setScreen=3'>Relay Anonymous Information</A><BR><BR>"
|
||||
else //main menu
|
||||
screen = 0
|
||||
announceAuth = FALSE
|
||||
if(newmessagepriority == NORMAL_MESSAGE_PRIORITY)
|
||||
dat += "<div class='notice'>There are new messages</div><br>"
|
||||
if(newmessagepriority == HIGH_MESSAGE_PRIORITY)
|
||||
dat += "<div class='notice'>There are new <b>PRIORITY</b> messages</div><br>"
|
||||
if(newmessagepriority == EXTREME_MESSAGE_PRIORITY)
|
||||
dat += "<div class='notice'>There are new <b>EXTREME PRIORITY</b> messages</div><br>"
|
||||
|
||||
if(!emergency)
|
||||
dat += "<A href='?src=[REF(src)];emergency=1'>Emergency: Security</A><BR>"
|
||||
dat += "<A href='?src=[REF(src)];emergency=2'>Emergency: Engineering</A><BR>"
|
||||
dat += "<A href='?src=[REF(src)];emergency=3'>Emergency: Medical</A><BR><BR>"
|
||||
else
|
||||
dat += "<B><font color='red'>[emergency] has been dispatched to this location.</font></B><BR><BR>"
|
||||
dat += "<a href='?src=[REF(src)];setScreen=8'>View Messages</a> <br><br>"
|
||||
|
||||
if(announcementConsole)
|
||||
dat += "<A href='?src=[REF(src)];setScreen=10'>Send Station-wide Announcement</A><BR><BR>"
|
||||
if (silent)
|
||||
dat += "Speaker <A href='?src=[REF(src)];setSilent=0'>OFF</A>"
|
||||
else
|
||||
dat += "Speaker <A href='?src=[REF(src)];setSilent=1'>ON</A>"
|
||||
var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
return
|
||||
dat += "<a href='?src=[REF(src)];setScreen=1'>Request Assistance</a> <br>"
|
||||
dat += "<a href='?src=[REF(src)];setScreen=2'>Request Supplies</a> <br>"
|
||||
dat += "<a href='?src=[REF(src)];setScreen=3'>Relay Anonymous Information</a> <br><br>"
|
||||
|
||||
if(!emergency)
|
||||
dat += "<a href='?src=[REF(src)];emergency=1'>Emergency: Security</a> <br>"
|
||||
dat += "<a href='?src=[REF(src)];emergency=2'>Emergency: Engineering</a> <br>"
|
||||
dat += "<a href='?src=[REF(src)];emergency=3'>Emergency: Medical</a> <br><br>"
|
||||
else
|
||||
dat += "<b><div class='bad'>[emergency] has been dispatched to this location.</div></b> <br><br>"
|
||||
|
||||
if(announcementConsole)
|
||||
dat += "<a href='?src=[REF(src)];setScreen=10'>Send Station-wide Announcement</a> <br><br>"
|
||||
if(silent)
|
||||
dat += "Speaker <a href='?src=[REF(src)];setSilent=0'>OFF</a>"
|
||||
else
|
||||
dat += "Speaker <a href='?src=[REF(src)];setSilent=1'>ON</a>"
|
||||
|
||||
var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/requests_console/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
add_fingerprint(usr)
|
||||
|
||||
|
||||
if(href_list["write"])
|
||||
dpt = ckey(reject_bad_text(href_list["write"])) //write contains the string of the receiving department's name
|
||||
var/new_message = stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN)
|
||||
if(new_message)
|
||||
message = new_message
|
||||
screen = 9
|
||||
if (text2num(href_list["priority"]) < 2)
|
||||
priority = -1
|
||||
else
|
||||
priority = text2num(href_list["priority"])
|
||||
priority = text2num(href_list["priority"])
|
||||
else
|
||||
dpt = "";
|
||||
msgVerified = ""
|
||||
msgStamped = ""
|
||||
screen = 0
|
||||
priority = -1
|
||||
priority = NORMAL_MESSAGE_PRIORITY //:salt:
|
||||
|
||||
if(href_list["writeAnnouncement"])
|
||||
var/new_message = reject_bad_text(stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN))
|
||||
if(new_message)
|
||||
message = new_message
|
||||
if (text2num(href_list["priority"]) < 2)
|
||||
priority = -1
|
||||
else
|
||||
priority = text2num(href_list["priority"])
|
||||
priority = text2num(href_list["priority"])
|
||||
else
|
||||
message = ""
|
||||
announceAuth = FALSE
|
||||
@@ -296,106 +306,116 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
|
||||
if(href_list["sendAnnouncement"])
|
||||
if(!announcementConsole)
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(isliving(usr))
|
||||
var/mob/living/L = usr
|
||||
message = L.treat_message(message)
|
||||
minor_announce(message, "[department] Announcement:")
|
||||
GLOB.news_network.SubmitArticle(message, department, "Station Announcements", null)
|
||||
usr.log_talk(message, LOG_SAY, tag="station announcement from [src]")
|
||||
usr.log_talk(message, LOG_SAY, tag = "station announcement from [src]")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] has made a station announcement from [src] at [AREACOORD(usr)].")
|
||||
announceAuth = FALSE
|
||||
message = ""
|
||||
screen = 0
|
||||
|
||||
if(href_list["emergency"])
|
||||
if(!emergency)
|
||||
var/radio_freq
|
||||
switch(text2num(href_list["emergency"]))
|
||||
if(1) //Security
|
||||
radio_freq = FREQ_SECURITY
|
||||
emergency = "Security"
|
||||
if(2) //Engineering
|
||||
radio_freq = FREQ_ENGINEERING
|
||||
emergency = "Engineering"
|
||||
if(3) //Medical
|
||||
radio_freq = FREQ_MEDICAL
|
||||
emergency = "Medical"
|
||||
if(radio_freq)
|
||||
Radio.set_frequency(radio_freq)
|
||||
Radio.talk_into(src,"[emergency] emergency in [department]!!",radio_freq)
|
||||
update_icon()
|
||||
addtimer(CALLBACK(src, .proc/clear_emergency), 3000)
|
||||
if(emergency) //already has an emergency? do not continue
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
if( href_list["department"] && message )
|
||||
var/log_msg = message
|
||||
var/radio_freq
|
||||
switch(text2num(href_list["emergency"]))
|
||||
if(1) //Security
|
||||
radio_freq = FREQ_SECURITY
|
||||
emergency = "Security"
|
||||
if(2) //Engineering
|
||||
radio_freq = FREQ_ENGINEERING
|
||||
emergency = "Engineering"
|
||||
if(3) //Medical
|
||||
radio_freq = FREQ_MEDICAL
|
||||
emergency = "Medical"
|
||||
if(radio_freq)
|
||||
Radio.set_frequency(radio_freq)
|
||||
Radio.talk_into(src, "[emergency] emergency in [department]!!", radio_freq)
|
||||
update_icon()
|
||||
addtimer(CALLBACK(src, .proc/clear_emergency), 5 MINUTES)
|
||||
|
||||
if(href_list["department"] && message)
|
||||
var/sending = message
|
||||
sending += "<br>"
|
||||
if (msgVerified)
|
||||
sending += msgVerified
|
||||
sending += "<br>"
|
||||
if (msgStamped)
|
||||
sending += msgStamped
|
||||
sending += "<br>"
|
||||
screen = 7 //if it's successful, this will get overrwritten (7 = unsufccessfull, 6 = successfull)
|
||||
if (sending)
|
||||
var/pass = FALSE
|
||||
var/datum/data_rc_msg/log = new(href_list["department"], department, log_msg, msgStamped, msgVerified, priority)
|
||||
for (var/obj/machinery/telecomms/message_server/MS in GLOB.telecomms_list)
|
||||
if (MS.toggled)
|
||||
MS.rc_msgs += log
|
||||
pass = TRUE
|
||||
if(msgVerified)
|
||||
sending += "<span class='good'><b>[msgVerified]</b></span> <br>"
|
||||
if(msgStamped)
|
||||
sending += "<span class='boldnotice'>[msgStamped]</span> <br>"
|
||||
//so you're telling me is you cheated, by making fail happen, then quickly replacing it with 6
|
||||
|
||||
if(pass)
|
||||
var/radio_freq = 0
|
||||
switch(href_list["department"])
|
||||
if("bridge")
|
||||
radio_freq = FREQ_COMMAND
|
||||
if("medbay")
|
||||
radio_freq = FREQ_MEDICAL
|
||||
if("science")
|
||||
radio_freq = FREQ_SCIENCE
|
||||
if("engineering")
|
||||
radio_freq = FREQ_ENGINEERING
|
||||
if("security")
|
||||
radio_freq = FREQ_SECURITY
|
||||
if("cargobay" || "mining")
|
||||
radio_freq = FREQ_SUPPLY
|
||||
Radio.set_frequency(radio_freq)
|
||||
var/authentic
|
||||
if(msgVerified || msgStamped)
|
||||
authentic = " (Authenticated)"
|
||||
var/workingServer = FALSE
|
||||
var/datum/data_rc_msg/log = new(href_list["department"], department, message, msgStamped, msgVerified, priority)
|
||||
for(var/obj/machinery/telecomms/message_server/MS in GLOB.telecomms_list)
|
||||
if(MS.on) //on does the calculations. why would this server still work even though the apc is off??
|
||||
LAZYADD(MS.rc_msgs, log)
|
||||
workingServer = TRUE
|
||||
|
||||
var/alert = ""
|
||||
for (var/obj/machinery/requests_console/Console in GLOB.allConsoles)
|
||||
if (ckey(Console.department) == ckey(href_list["department"]))
|
||||
switch(priority)
|
||||
if(2) //High priority
|
||||
alert = "PRIORITY Alert in [department][authentic]"
|
||||
Console.createmessage(src, alert, sending, 2, 1)
|
||||
if(3) // Extreme Priority
|
||||
alert = "EXTREME PRIORITY Alert from [department][authentic]"
|
||||
Console.createmessage(src, alert , sending, 3, 1)
|
||||
else // Normal priority
|
||||
alert = "Message from [department][authentic]"
|
||||
Console.createmessage(src, alert , sending, 1, 1)
|
||||
screen = 6
|
||||
if(!workingServer)
|
||||
screen = 7
|
||||
say("NOTICE: No server detected! Please contact your local engineering team.")
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
if(radio_freq)
|
||||
Radio.talk_into(src, "[alert]: <i>[message]</i>", radio_freq)
|
||||
var/radio_freq = 0
|
||||
switch(href_list["department"])
|
||||
if("bridge")
|
||||
radio_freq = FREQ_COMMAND
|
||||
if("medbay")
|
||||
radio_freq = FREQ_MEDICAL
|
||||
if("science")
|
||||
radio_freq = FREQ_SCIENCE
|
||||
if("engineering")
|
||||
radio_freq = FREQ_ENGINEERING
|
||||
if("security")
|
||||
radio_freq = FREQ_SECURITY
|
||||
if("cargobay" || "mining")
|
||||
radio_freq = FREQ_SUPPLY
|
||||
Radio.set_frequency(radio_freq)
|
||||
|
||||
switch(priority)
|
||||
if(2)
|
||||
messages += "<span class='bad'>High Priority</span><BR><b>To:</b> [dpt]<BR>[sending]"
|
||||
else
|
||||
messages += "<b>To: [dpt]</b><BR>[sending]"
|
||||
var/authentic = ""
|
||||
if(msgVerified || msgStamped)
|
||||
authentic = " (Authenticated)"
|
||||
|
||||
var/alert = ""
|
||||
for(var/obj/machinery/requests_console/C in GLOB.allConsoles)
|
||||
if(ckey(C.department) != ckey(href_list["department"]))
|
||||
continue
|
||||
switch(priority)
|
||||
if(HIGH_MESSAGE_PRIORITY) //High priority
|
||||
alert = "PRIORITY Alert from [department][authentic]"
|
||||
C.createmessage(src, alert, sending, HIGH_MESSAGE_PRIORITY)
|
||||
if(EXTREME_MESSAGE_PRIORITY) // Extreme Priority
|
||||
alert = "EXTREME PRIORITY Alert from [department][authentic]"
|
||||
C.createmessage(src, alert, sending, EXTREME_MESSAGE_PRIORITY)
|
||||
else // Normal priority
|
||||
alert = "Message from [department][authentic]"
|
||||
C.createmessage(src, alert, sending, NORMAL_MESSAGE_PRIORITY)
|
||||
screen = 6 //if it ever gets here that means (c.department == href_ls["dept"])
|
||||
|
||||
if(radio_freq)
|
||||
Radio.talk_into(src, "[alert]: <i>[message]</i>", radio_freq)
|
||||
//log to (this)
|
||||
switch(priority)
|
||||
if(HIGH_MESSAGE_PRIORITY)
|
||||
messages += "<span class='bad'>High Priority</span><br><b>To:</b> [dpt]<br>[sending]"
|
||||
if(EXTREME_MESSAGE_PRIORITY)
|
||||
messages += "<span class='bad'>!!!Extreme Priority!!!</span><br><b>To:</b> [dpt]<br>[sending]"
|
||||
else
|
||||
say("NOTICE: No server detected!")
|
||||
messages += "<b>To:</b> [dpt]<br>[sending]"
|
||||
|
||||
|
||||
//Handle screen switching
|
||||
switch(text2num(href_list["setScreen"]))
|
||||
if(null) //skip
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(1) //req. assistance
|
||||
screen = 1
|
||||
if(2) //req. supplies
|
||||
@@ -423,16 +443,14 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
msgVerified = ""
|
||||
msgStamped = ""
|
||||
message = ""
|
||||
priority = -1
|
||||
priority = NORMAL_MESSAGE_PRIORITY // :salt:
|
||||
screen = 0
|
||||
|
||||
//Handle silencing the console
|
||||
switch( href_list["setSilent"] )
|
||||
if(null) //skip
|
||||
if("1")
|
||||
silent = TRUE
|
||||
else
|
||||
silent = FALSE
|
||||
if(href_list["setSilent"] == "1")
|
||||
silent = TRUE
|
||||
else
|
||||
silent = FALSE
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
@@ -457,31 +475,32 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
linkedsender = source
|
||||
capitalize(title)
|
||||
switch(priority)
|
||||
if(2) //High priority
|
||||
if(HIGH_MESSAGE_PRIORITY) //High priority
|
||||
if(newmessagepriority < HIGH_MESSAGE_PRIORITY)
|
||||
newmessagepriority = HIGH_MESSAGE_PRIORITY
|
||||
update_icon()
|
||||
if(!silent)
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
say(title)
|
||||
messages += "<span class='bad'>High Priority</span><BR><b>From:</b> [linkedsender]<BR>[message]"
|
||||
messages += "<span class='bad'>High Priority</span><br><b>From:</b> [linkedsender]<br>[message]" //the fuck is this not being sent
|
||||
|
||||
if(3) // Extreme Priority
|
||||
if(EXTREME_MESSAGE_PRIORITY) // Extreme Priority
|
||||
if(newmessagepriority < EXTREME_MESSAGE_PRIORITY)
|
||||
newmessagepriority = EXTREME_MESSAGE_PRIORITY
|
||||
update_icon()
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
say(title)
|
||||
messages += "<span class='bad'>!!!Extreme Priority!!!</span><BR><b>From:</b> [linkedsender]<BR>[message]"
|
||||
//we ignore the silent option because this is !!!IMPORTANT!!!
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
say(title)
|
||||
messages += "<span class='bad'><b>!!!Extreme Priority!!!</span></b><br><b>From:</b> [linkedsender]<br>[message]"
|
||||
|
||||
else // Normal priority
|
||||
if(newmessagepriority < NORMAL_MESSAGE_PRIORITY)
|
||||
newmessagepriority = NORMAL_MESSAGE_PRIORITY
|
||||
update_icon()
|
||||
if(!src.silent)
|
||||
if(!silent)
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
say(title)
|
||||
messages += "<b>From:</b> [linkedsender]<BR>[message]"
|
||||
messages += "<b>From:</b> [linkedsender]<br>[message]"
|
||||
|
||||
/obj/machinery/requests_console/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/crowbar))
|
||||
@@ -505,23 +524,26 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
to_chat(user, "<span class='warning'>You must open the maintenance panel first!</span>")
|
||||
return
|
||||
|
||||
var/obj/item/card/id/ID = O.GetID()
|
||||
if(ID)
|
||||
if(istype(O, /obj/item/card/id))
|
||||
var/obj/item/card/id/ID = O.GetID()
|
||||
if(!ID)
|
||||
return
|
||||
if(screen == 9)
|
||||
msgVerified = "<font color='green'><b>Verified by [ID.registered_name] ([ID.assignment])</b></font>"
|
||||
msgVerified = "Verified by [ID.registered_name] ([ID.assignment])"
|
||||
updateUsrDialog()
|
||||
if(screen == 10)
|
||||
if (ACCESS_RC_ANNOUNCE in ID.access)
|
||||
if(ACCESS_RC_ANNOUNCE in ID.access)
|
||||
announceAuth = TRUE
|
||||
else
|
||||
announceAuth = FALSE
|
||||
to_chat(user, "<span class='warning'>You are not authorized to send announcements!</span>")
|
||||
updateUsrDialog()
|
||||
return
|
||||
if (istype(O, /obj/item/stamp))
|
||||
|
||||
if(istype(O, /obj/item/stamp))
|
||||
if(screen == 9)
|
||||
var/obj/item/stamp/T = O
|
||||
msgStamped = "<span class='boldnotice'>Stamped with the [T.name]</span>"
|
||||
msgStamped = "Stamped with the [T.name]"
|
||||
updateUsrDialog()
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -1,215 +1,164 @@
|
||||
|
||||
/*
|
||||
The log console for viewing the entire telecomms
|
||||
network log
|
||||
*/
|
||||
|
||||
/obj/machinery/computer/telecomms/server
|
||||
name = "telecommunications server monitoring console"
|
||||
icon_screen = "comm_logs"
|
||||
desc = "Has full access to all details and record of the telecommunications network it's monitoring."
|
||||
circuit = /obj/item/circuitboard/computer/comm_server
|
||||
req_access = list(ACCESS_TCOMSAT)
|
||||
|
||||
var/screen = 0 // the screen number:
|
||||
var/list/servers = list() // the servers located by the computer
|
||||
var/obj/machinery/telecomms/server/SelectedServer
|
||||
var/list/machinelist = list() // the servers located by the computer
|
||||
var/obj/machinery/telecomms/server/SelectedMachine = null
|
||||
|
||||
var/network = "NULL" // the network to probe
|
||||
var/temp = "" // temporary feedback messages
|
||||
var/notice = ""
|
||||
var/universal_translate = FALSE // set to TRUE(1) if it can translate nonhuman speech
|
||||
|
||||
var/universal_translate = 0 // set to 1 if it can translate nonhuman speech
|
||||
/obj/machinery/computer/telecomms/server/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "tcommsserver", "Telecomms Server Monitor", 575, 400, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
req_access = list(ACCESS_TCOMSAT)
|
||||
circuit = /obj/item/circuitboard/computer/comm_server
|
||||
/obj/machinery/computer/telecomms/server/ui_data(mob/user)
|
||||
var/list/data_out = list()
|
||||
data_out["network"] = network
|
||||
data_out["notice"] = notice
|
||||
|
||||
/obj/machinery/computer/telecomms/server/ui_interact(mob/user)
|
||||
. = ..()
|
||||
var/dat = "<TITLE>Telecommunication Server Monitor</TITLE><center><b>Telecommunications Server Monitor</b></center>"
|
||||
data_out["servers"] = list()
|
||||
for(var/obj/machinery/telecomms/server/T in machinelist)
|
||||
var/list/data = list(
|
||||
name = T.name,
|
||||
id = T.id,
|
||||
ref = REF(T)
|
||||
)
|
||||
data_out["servers"] += list(data)
|
||||
data_out["servers"] = sortList(data_out["servers"]) //a-z sort
|
||||
|
||||
switch(screen)
|
||||
if(!SelectedMachine) //null is bad.
|
||||
data_out["selected"] = null //but in js, null is good.
|
||||
return data_out
|
||||
|
||||
data_out["selected"] = list(
|
||||
name = SelectedMachine.name,
|
||||
id = SelectedMachine.id,
|
||||
status = SelectedMachine.on,
|
||||
traffic = SelectedMachine.totaltraffic, //note: total traffic, not traffic!
|
||||
ref = REF(SelectedMachine)
|
||||
)
|
||||
data_out["selected_logs"] = list()
|
||||
|
||||
// --- Main Menu ---
|
||||
if(!LAZYLEN(SelectedMachine.log_entries))
|
||||
return data_out
|
||||
|
||||
for(var/datum/comm_log_entry/C in SelectedMachine.log_entries)
|
||||
var/list/data = list()
|
||||
data["name"] = C.name //name of the file
|
||||
data["ref"] = REF(C)
|
||||
data["input_type"] = C.input_type //type of input ("Speech File" | "Execution Error").
|
||||
|
||||
if(0)
|
||||
dat += "<br>[temp]<br>"
|
||||
dat += "<br>Current Network: <a href='?src=[REF(src)];network=1'>[network]</a><br>"
|
||||
if(servers.len)
|
||||
dat += "<br>Detected Telecommunication Servers:<ul>"
|
||||
for(var/obj/machinery/telecomms/T in servers)
|
||||
dat += "<li><a href='?src=[REF(src)];viewserver=[T.id]'>[REF(T)] [T.name]</a> ([T.id])</li>"
|
||||
dat += "</ul>"
|
||||
dat += "<br><a href='?src=[REF(src)];operation=release'>\[Flush Buffer\]</a>"
|
||||
if(C.input_type == "Speech File") //there is a reason why this is not a switch.
|
||||
data["source"] = list(
|
||||
name = C.parameters["name"], //name of the mob | obj
|
||||
job = C.parameters["job"] //job of the mob | obj
|
||||
)
|
||||
|
||||
// -- Determine race of orator --
|
||||
var/mobtype = C.parameters["mobtype"]
|
||||
var/race // The actual race of the mob
|
||||
|
||||
if(ispath(mobtype, /mob/living/carbon/human) || ispath(mobtype, /mob/living/brain))
|
||||
race = "Humanoid"
|
||||
else if(ispath(mobtype, /mob/living/simple_animal/slime))
|
||||
race = "Slime" // NT knows a lot about slimes, but not aliens. Can identify slimes
|
||||
else if(ispath(mobtype, /mob/living/carbon/monkey))
|
||||
race = "Monkey"
|
||||
else if(ispath(mobtype, /mob/living/silicon) || C.parameters["job"] == "AI")
|
||||
race = "Artificial Life" // sometimes M gets deleted prematurely for AIs... just check the job
|
||||
else if(isobj(mobtype))
|
||||
race = "Machinery"
|
||||
else if(ispath(mobtype, /mob/living/simple_animal))
|
||||
race = "Domestic Animal"
|
||||
else
|
||||
dat += "<br>No servers detected. Scan for servers: <a href='?src=[REF(src)];operation=scan'>\[Scan\]</a>"
|
||||
race = "Unidentifiable"
|
||||
|
||||
data["race"] = race
|
||||
// based on [/atom/movable/proc/lang_treat]
|
||||
var/message = C.parameters["message"]
|
||||
var/language = C.parameters["language"]
|
||||
|
||||
// --- Viewing Server ---
|
||||
if(universal_translate || user.has_language(language))
|
||||
message = message
|
||||
else if(!user.has_language(language))
|
||||
var/datum/language/D = GLOB.language_datum_instances[language]
|
||||
message = D.scramble(message)
|
||||
else if(language)
|
||||
message = "(unintelligible)"
|
||||
|
||||
if(1)
|
||||
dat += "<br>[temp]<br>"
|
||||
dat += "<center><a href='?src=[REF(src)];operation=mainmenu'>\[Main Menu\]</a> <a href='?src=[REF(src)];operation=refresh'>\[Refresh\]</a></center>"
|
||||
dat += "<br>Current Network: [network]"
|
||||
dat += "<br>Selected Server: [SelectedServer.id]"
|
||||
data["message"] = message
|
||||
|
||||
if(SelectedServer.totaltraffic >= 1024)
|
||||
dat += "<br>Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes<br><br>"
|
||||
else
|
||||
dat += "<br>Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes<br><br>"
|
||||
else if(C.input_type == "Execution Error")
|
||||
data["message"] = C.parameters["message"]
|
||||
else
|
||||
data["message"] = "(unintelligible)"
|
||||
|
||||
data_out["selected_logs"] += list(data)
|
||||
return data_out
|
||||
|
||||
dat += "Stored Logs: <ol>"
|
||||
|
||||
var/i = 0
|
||||
for(var/datum/comm_log_entry/C in SelectedServer.log_entries)
|
||||
i++
|
||||
|
||||
|
||||
// If the log is a speech file
|
||||
if(C.input_type == "Speech File")
|
||||
dat += "<li><font color = #008F00>[C.name]</font> <font color = #FF0000><a href='?src=[REF(src)];delete=[i]'>\[X\]</a></font><br>"
|
||||
|
||||
// -- Determine race of orator --
|
||||
|
||||
var/mobtype = C.parameters["mobtype"]
|
||||
var/race // The actual race of the mob
|
||||
|
||||
if(ispath(mobtype, /mob/living/carbon/human) || ispath(mobtype, /mob/living/brain))
|
||||
race = "Humanoid"
|
||||
|
||||
// NT knows a lot about slimes, but not aliens. Can identify slimes
|
||||
else if(ispath(mobtype, /mob/living/simple_animal/slime))
|
||||
race = "Slime"
|
||||
|
||||
else if(ispath(mobtype, /mob/living/carbon/monkey))
|
||||
race = "Monkey"
|
||||
|
||||
// sometimes M gets deleted prematurely for AIs... just check the job
|
||||
else if(ispath(mobtype, /mob/living/silicon) || C.parameters["job"] == "AI")
|
||||
race = "Artificial Life"
|
||||
|
||||
else if(isobj(mobtype))
|
||||
race = "Machinery"
|
||||
|
||||
else if(ispath(mobtype, /mob/living/simple_animal))
|
||||
race = "Domestic Animal"
|
||||
|
||||
else
|
||||
race = "<i>Unidentifiable</i>"
|
||||
|
||||
dat += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
|
||||
dat += "<u><font color = #18743E>Source</font></u>: [C.parameters["name"]] (Job: [C.parameters["job"]])<br>"
|
||||
dat += "<u><font color = #18743E>Class</font></u>: [race]<br>"
|
||||
var/message = C.parameters["message"]
|
||||
var/language = C.parameters["language"]
|
||||
|
||||
// based on [/atom/movable/proc/lang_treat]
|
||||
if (universal_translate || user.has_language(language))
|
||||
message = "\"[message]\""
|
||||
else if (!user.has_language(language))
|
||||
var/datum/language/D = GLOB.language_datum_instances[language]
|
||||
message = "\"[D.scramble(message)]\""
|
||||
else if (language)
|
||||
message = "<i>(unintelligible)</i>"
|
||||
|
||||
dat += "<u><font color = #18743E>Contents</font></u>: [message]<br>"
|
||||
dat += "</li><br>"
|
||||
|
||||
else if(C.input_type == "Execution Error")
|
||||
dat += "<li><font color = #990000>[C.name]</font> <a href='?src=[REF(src)];delete=[i]'>\[X\]</a><br>"
|
||||
dat += "<u><font color = #787700>Error</font></u>: \"[C.parameters["message"]]\"<br>"
|
||||
dat += "</li><br>"
|
||||
|
||||
else
|
||||
dat += "<li><font color = #000099>[C.name]</font> <a href='?src=[REF(src)];delete=[i]'>\[X\]</a><br>"
|
||||
dat += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
|
||||
dat += "<u><font color = #18743E>Contents</font></u>: <i>(unintelligible)</i><br>"
|
||||
dat += "</li><br>"
|
||||
|
||||
|
||||
dat += "</ol>"
|
||||
|
||||
|
||||
|
||||
user << browse(dat, "window=comm_monitor;size=575x400")
|
||||
onclose(user, "server_control")
|
||||
|
||||
temp = ""
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/computer/telecomms/server/Topic(href, href_list)
|
||||
/obj/machinery/computer/telecomms/server/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
|
||||
add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["viewserver"])
|
||||
screen = 1
|
||||
for(var/obj/machinery/telecomms/T in servers)
|
||||
if(T.id == href_list["viewserver"])
|
||||
SelectedServer = T
|
||||
break
|
||||
|
||||
if(href_list["operation"])
|
||||
switch(href_list["operation"])
|
||||
|
||||
if("release")
|
||||
servers = list()
|
||||
screen = 0
|
||||
|
||||
if("mainmenu")
|
||||
screen = 0
|
||||
|
||||
if("scan")
|
||||
if(servers.len > 0)
|
||||
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font color>"
|
||||
|
||||
else
|
||||
for(var/obj/machinery/telecomms/server/T in urange(25, src))
|
||||
if(T.network == network)
|
||||
servers.Add(T)
|
||||
|
||||
if(!servers.len)
|
||||
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -</font color>"
|
||||
else
|
||||
temp = "<font color = #336699>- [servers.len] SERVERS PROBED & BUFFERED -</font color>"
|
||||
|
||||
screen = 0
|
||||
|
||||
if(href_list["delete"])
|
||||
|
||||
if(!src.allowed(usr) && !(obj_flags & EMAGGED))
|
||||
to_chat(usr, "<span class='danger'>ACCESS DENIED.</span>")
|
||||
switch(action)
|
||||
if("mainmenu")
|
||||
SelectedMachine = null
|
||||
notice = ""
|
||||
return
|
||||
if("release")
|
||||
machinelist = list()
|
||||
notice = ""
|
||||
return
|
||||
if("network") //network change, flush the selected machine and buffer
|
||||
var/newnet = sanitize(sanitize_text(params["value"], network))
|
||||
if(length(newnet) > 15) //i'm looking at you, you href fuckers
|
||||
notice = "FAILED: Network tag string too lengthy"
|
||||
return
|
||||
network = newnet
|
||||
SelectedMachine = null
|
||||
machinelist = list()
|
||||
return
|
||||
if("probe")
|
||||
if(LAZYLEN(machinelist) > 0)
|
||||
notice = "FAILED: Cannot probe when buffer full"
|
||||
return
|
||||
|
||||
for(var/obj/machinery/telecomms/T in GLOB.telecomms_list) //telecomms just went global!
|
||||
if(T.network == network)
|
||||
LAZYADD(machinelist, T)
|
||||
|
||||
if(SelectedServer)
|
||||
if(!LAZYLEN(machinelist))
|
||||
notice = "FAILED: Unable to locate network entities in \[[network]\]"
|
||||
return
|
||||
if("viewmachine")
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
if(T.id == params["value"])
|
||||
SelectedMachine = T
|
||||
break
|
||||
if("delete")
|
||||
if(!src.allowed(usr) && !CHECK_BITFIELD(obj_flags, EMAGGED))
|
||||
to_chat(usr, "<span class='danger'>ACCESS DENIED.</span>")
|
||||
return
|
||||
|
||||
var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])]
|
||||
|
||||
temp = "<font color = #336699>- DELETED ENTRY: [D.name] -</font color>"
|
||||
|
||||
SelectedServer.log_entries.Remove(D)
|
||||
if(!SelectedMachine)
|
||||
notice = "ALERT: No server detected. Server may be nonresponsive."
|
||||
return
|
||||
var/datum/comm_log_entry/D = locate(params["value"])
|
||||
if(!istype(D))
|
||||
notice = "NOTICE: Object not found"
|
||||
return
|
||||
notice = "Deleted entry: [D.name]"
|
||||
LAZYREMOVE(SelectedMachine.log_entries, D)
|
||||
qdel(D)
|
||||
|
||||
else
|
||||
temp = "<font color = #D70B00>- FAILED: NO SELECTED MACHINE -</font color>"
|
||||
|
||||
if(href_list["network"])
|
||||
|
||||
var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network)
|
||||
|
||||
if(newnet && ((usr in range(1, src)) || hasSiliconAccessInArea(usr)))
|
||||
if(length(newnet) > 15)
|
||||
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font color>"
|
||||
|
||||
else
|
||||
|
||||
network = newnet
|
||||
screen = 0
|
||||
servers = list()
|
||||
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font color>"
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/telecomms/server/attackby()
|
||||
. = ..()
|
||||
updateUsrDialog()
|
||||
@@ -3,241 +3,360 @@
|
||||
Lets you read PDA and request console messages.
|
||||
*/
|
||||
|
||||
#define LINKED_SERVER_NONRESPONSIVE (!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN)))
|
||||
|
||||
// The monitor itself.
|
||||
/obj/machinery/computer/message_monitor
|
||||
name = "message monitor console"
|
||||
desc = "Used to monitor the crew's PDA messages, as well as request console messages."
|
||||
icon_screen = "comm_logs"
|
||||
circuit = /obj/item/circuitboard/computer/message_monitor
|
||||
//Server linked to.
|
||||
|
||||
//Servers, and server linked to.
|
||||
var/network = "tcommsat" // the network to probe
|
||||
var/list/machinelist = list() // the servers located by the computer
|
||||
var/obj/machinery/telecomms/message_server/linkedServer = null
|
||||
|
||||
//Sparks effect - For emag
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
|
||||
|
||||
//Messages - Saves me time if I want to change something.
|
||||
var/noserver = "<span class='alert'>ALERT: No server detected.</span>"
|
||||
var/incorrectkey = "<span class='warning'>ALERT: Incorrect decryption key!</span>"
|
||||
var/defaultmsg = "<span class='notice'>Welcome. Please select an option.</span>"
|
||||
var/rebootmsg = "<span class='warning'>%$&(�: Critical %$$@ Error // !RestArting! <lOadiNg backUp iNput ouTput> - ?pLeaSe wAit!</span>"
|
||||
var/noserver = "ALERT: No server detected. Server may be nonresponsive."
|
||||
var/incorrectkey = "ALERT: Incorrect decryption key!"
|
||||
var/rebootmsg = "%$�(�:SYS&EM INTRN@L ACfES VIOL�TIa█ DEtE₡TED! Ree3ARcinG A█ BAaKUP RdST�RE PbINT \[0xcff32ca/ - PLfASE aAIT"
|
||||
|
||||
//Computer properties
|
||||
var/screen = 0 // 0 = Main menu, 1 = Message Logs, 2 = Hacked screen, 3 = Custom Message
|
||||
var/hacking = FALSE // Is it being hacked into by the AI/Cyborg
|
||||
var/message = "<span class='notice'>System bootup complete. Please select an option.</span>" // The message that shows on the main menu.
|
||||
var/auth = FALSE // Are they authenticated?
|
||||
var/optioncount = 7
|
||||
var/message = "" // The message that shows on the main menu.
|
||||
var/auth = FALSE // Are they authenticated?
|
||||
|
||||
// Custom Message Properties
|
||||
var/customsender = "System Administrator"
|
||||
var/obj/item/pda/customrecepient = null
|
||||
var/customsender = "System Administrator"
|
||||
var/customjob = "Admin"
|
||||
var/custommessage = "This is a test, please ignore."
|
||||
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
|
||||
/obj/machinery/computer/message_monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "telepdalog", name, 727, 510, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/message_monitor/ui_static_data(mob/user)
|
||||
var/list/data_out = list()
|
||||
|
||||
if(!linkedServer || !auth) // no need building this if the usr isn't authenticated
|
||||
return data_out
|
||||
|
||||
data_out["recon_logs"] = list()
|
||||
var/i1 = 0
|
||||
for(var/datum/data_rc_msg/rc in linkedServer.rc_msgs)
|
||||
i1++
|
||||
if(i1 > 3000)
|
||||
break
|
||||
var/list/data = list(
|
||||
sender = rc.send_dpt,
|
||||
recipient = rc.rec_dpt,
|
||||
message = rc.message,
|
||||
stamp = rc.stamp,
|
||||
auth = rc.id_auth,
|
||||
priority = rc.priority,
|
||||
ref = REF(rc)
|
||||
)
|
||||
data_out["recon_logs"] += list(data)
|
||||
|
||||
data_out["message_logs"] = list()
|
||||
var/i2 = 0
|
||||
for(var/datum/data_pda_msg/pda in linkedServer.pda_msgs)
|
||||
i2++
|
||||
if(i2 > 3000)
|
||||
break
|
||||
var/list/data = list(
|
||||
sender = pda.sender,
|
||||
recipient = pda.recipient,
|
||||
message = pda.message,
|
||||
picture = pda.picture ? TRUE : FALSE,
|
||||
ref = REF(pda)
|
||||
)
|
||||
data_out["message_logs"] += list(data)
|
||||
|
||||
return data_out
|
||||
|
||||
/obj/machinery/computer/message_monitor/ui_data(mob/user)
|
||||
var/list/data_out = list()
|
||||
|
||||
data_out["notice"] = message
|
||||
data_out["authenticated"] = auth
|
||||
data_out["network"] = network
|
||||
|
||||
var/mob/living/silicon/S = user
|
||||
if(istype(S) && S.hack_software)
|
||||
data_out["canhack"] = TRUE
|
||||
|
||||
data_out["hacking"] = (hacking || CHECK_BITFIELD(obj_flags, EMAGGED))
|
||||
if(hacking)
|
||||
data_out["borg"] = ((isAI(user) || iscyborg(user)) && !CHECK_BITFIELD(obj_flags, EMAGGED)) //even borgs can't read emag
|
||||
return data_out
|
||||
|
||||
data_out["servers"] = list()
|
||||
for(var/obj/machinery/telecomms/message_server/T in machinelist)
|
||||
var/list/data = list(
|
||||
name = T.name,
|
||||
id = T.id,
|
||||
ref = REF(T)
|
||||
)
|
||||
data_out["servers"] += list(data) // This /might/ cause an oom. Too bad!
|
||||
data_out["servers"] = sortList(data_out["servers"]) //a-z sort
|
||||
|
||||
data_out["fake_message"] = list(
|
||||
sender = customsender,
|
||||
job = customjob,
|
||||
message = custommessage,
|
||||
recepient = (customrecepient ? "[customrecepient.owner] ([customrecepient.ownjob])" : null)
|
||||
)
|
||||
|
||||
if(!linkedServer)
|
||||
data_out["selected"] = null
|
||||
return data_out
|
||||
|
||||
data_out["selected"] = list(
|
||||
name = linkedServer.name,
|
||||
id = linkedServer.id,
|
||||
ref = REF(linkedServer),
|
||||
status = (linkedServer.on && (linkedServer.toggled != FALSE)) // returns true if server is running
|
||||
)
|
||||
return data_out
|
||||
|
||||
/obj/machinery/computer/message_monitor/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("mainmenu") //deselect
|
||||
linkedServer = null
|
||||
auth = FALSE
|
||||
message = ""
|
||||
return
|
||||
if("release") //release server listing
|
||||
machinelist = list()
|
||||
message = ""
|
||||
return
|
||||
if("network") //network change, flush the selected machine and buffer, and de-auth them, if blank, return default
|
||||
var/newnet = sanitize(sanitize_text(params["value"], network))
|
||||
if(length(newnet) > 15) //i'm looking at you, you href fuckers
|
||||
message = "FAILED: Network tag string too lengthy"
|
||||
return
|
||||
network = newnet
|
||||
linkedServer = null
|
||||
machinelist = list()
|
||||
auth = FALSE
|
||||
message = "NOTICE: Network change detected. Server disconnected, please re-authenticate."
|
||||
return
|
||||
if("probe") //probe network for the pda serbs
|
||||
if(LAZYLEN(machinelist) > 0)
|
||||
message = "FAILED: Cannot probe when buffer full"
|
||||
return
|
||||
|
||||
for(var/obj/machinery/telecomms/message_server/T in GLOB.telecomms_list)
|
||||
if(T.network == network)
|
||||
LAZYADD(machinelist, T)
|
||||
|
||||
if(!LAZYLEN(machinelist))
|
||||
message = "FAILED: Unable to locate network entities in \[[network]\]"
|
||||
return
|
||||
if("viewmachine") //selected but not authorized
|
||||
for(var/obj/machinery/telecomms/message_server/T in machinelist)
|
||||
if(T.id == params["value"])
|
||||
linkedServer = T
|
||||
break
|
||||
|
||||
if("auth")
|
||||
if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
|
||||
message = noserver
|
||||
return
|
||||
if(auth)
|
||||
auth = FALSE
|
||||
update_static_data(usr) //make sure it's cleared!
|
||||
return
|
||||
var/dkey = stripped_input(usr, "Please enter the decryption key.")
|
||||
if(dkey && dkey == "")
|
||||
return
|
||||
if(linkedServer.decryptkey == dkey)
|
||||
auth = TRUE
|
||||
else
|
||||
message = incorrectkey
|
||||
update_static_data(usr)
|
||||
if("change_auth")
|
||||
if(!auth)
|
||||
message = "WARNING: Auth failed! Please log in to change the password!"
|
||||
return
|
||||
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
|
||||
message = noserver
|
||||
return
|
||||
|
||||
var/dkey = stripped_input(usr, "Please enter the old decryption key.")
|
||||
if(dkey && dkey != "")
|
||||
if(linkedServer.decryptkey == dkey)
|
||||
var/newkey = stripped_input(usr, "Please enter the new key (3 - 20 characters max):")
|
||||
if(!ISINRANGE(length(newkey), 3, 20))
|
||||
message = "NOTICE: Decryption key length too long/short!"
|
||||
return
|
||||
if(newkey && newkey != "")
|
||||
linkedServer.decryptkey = newkey
|
||||
message = "NOTICE: Decryption key set."
|
||||
return
|
||||
message = incorrectkey
|
||||
|
||||
if("hack")
|
||||
if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
|
||||
message = noserver
|
||||
return
|
||||
|
||||
var/mob/living/silicon/S = usr
|
||||
if(istype(S) && S.hack_software)
|
||||
hacking = TRUE
|
||||
//Time it takes to bruteforce is dependant on the password length.
|
||||
addtimer(CALLBACK(src, .proc/BruteForce, usr), (10 SECONDS) * length(linkedServer.decryptkey))
|
||||
|
||||
if("del_log")
|
||||
if(!auth)
|
||||
message = "WARNING: Auth failed! Delete aborted!"
|
||||
return
|
||||
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
|
||||
message = noserver
|
||||
return
|
||||
|
||||
var/datum/data_ref = locate(params["ref"])
|
||||
if(istype(data_ref, /datum/data_rc_msg))
|
||||
LAZYREMOVE(linkedServer.rc_msgs, data_ref)
|
||||
message = "NOTICE: Log Deleted!"
|
||||
else if(istype(data_ref, /datum/data_pda_msg))
|
||||
LAZYREMOVE(linkedServer.pda_msgs, data_ref)
|
||||
message = "NOTICE: Log Deleted!"
|
||||
else
|
||||
message = "NOTICE: Log not found! It may have already been deleted"
|
||||
update_static_data(usr)
|
||||
|
||||
if("clear_log")
|
||||
if(!auth)
|
||||
message = "WARNING: Auth failed! Delete aborted!"
|
||||
return
|
||||
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
|
||||
message = noserver
|
||||
return
|
||||
|
||||
var/what = params["value"]
|
||||
if(what == "pda_logs")
|
||||
linkedServer.pda_msgs = list()
|
||||
if(what == "rc_msgs")
|
||||
linkedServer.rc_msgs = list()
|
||||
update_static_data(usr)
|
||||
if("fake")
|
||||
if(!auth)
|
||||
message = "WARNING: Auth failed!"
|
||||
return
|
||||
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
|
||||
message = noserver
|
||||
return
|
||||
|
||||
if("reset" in params)
|
||||
ResetMessage()
|
||||
return
|
||||
if("send" in params)
|
||||
if(isnull(customrecepient))
|
||||
message = "NOTICE: No recepient selected!"
|
||||
return
|
||||
if(length(custommessage) <= 0 || custommessage == "")
|
||||
message = "NOTICE: No message entered!"
|
||||
return
|
||||
if(length(customjob) <= 0 || customjob == "")
|
||||
customjob = "Admin"
|
||||
return
|
||||
if(length(customsender) <= 0 || customsender == "")
|
||||
customsender = "UNKNOWN"
|
||||
//sanitize text!!!
|
||||
var/datum/signal/subspace/pda/signal = new(src, list(
|
||||
"name" = sanitize(customsender),
|
||||
"job" = sanitize(customjob),
|
||||
"message" = sanitize(custommessage),
|
||||
"emojis" = TRUE,
|
||||
"targets" = list("[customrecepient.owner] ([customrecepient.ownjob])")
|
||||
))
|
||||
// this will log the signal and transmit it to the target
|
||||
linkedServer.receive_information(signal, null)
|
||||
usr.log_message("(PDA: [name] | [usr.real_name]) sent \"[sanitize(custommessage)]\" to [signal.format_target()]", LOG_PDA)
|
||||
message = ""
|
||||
return
|
||||
// Do not check if it's blank yet
|
||||
// But do check if it's above our set limit (for people who manualy send hrefs at us!)
|
||||
if("sender" in params)
|
||||
var/S = params["sender"]
|
||||
if(length(S) > MAX_NAME_LEN)
|
||||
message = "FAILED: Job string too lengthy"
|
||||
return
|
||||
customsender = S
|
||||
return
|
||||
if("job" in params)
|
||||
var/J = params["job"]
|
||||
if(length(J) > 100)
|
||||
message = "FAILED: Job string too lengthy"
|
||||
return
|
||||
|
||||
customjob = J
|
||||
return
|
||||
if("message" in params)
|
||||
var/M = params["message"]
|
||||
if(length(M) > MAX_MESSAGE_LEN)
|
||||
message = "FAILED: Message string too lengthy"
|
||||
return
|
||||
custommessage = M
|
||||
return
|
||||
|
||||
if("recepient" in params)
|
||||
// Get out list of viable PDAs
|
||||
var/list/obj/item/pda/sendPDAs = get_viewable_pdas()
|
||||
if(GLOB.PDAs && LAZYLEN(GLOB.PDAs) > 0)
|
||||
customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortNames(sendPDAs)
|
||||
else
|
||||
customrecepient = null
|
||||
return
|
||||
if("refresh")
|
||||
update_static_data(usr)
|
||||
|
||||
/obj/machinery/computer/message_monitor/attackby(obj/item/O, mob/living/user, params)
|
||||
if(istype(O, /obj/item/screwdriver) && (obj_flags & EMAGGED))
|
||||
//Stops people from just unscrewing the monitor and putting it back to get the console working again.
|
||||
if(istype(O, /obj/item/screwdriver) && CHECK_BITFIELD(obj_flags, EMAGGED))
|
||||
//Stops people from just unscrewing the monitor and putting it back to get the console working again.
|
||||
//Why this though, you should make it emag to a board level. (i wont do it)
|
||||
to_chat(user, "<span class='warning'>It is too hot to mess with!</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/message_monitor/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(obj_flags & EMAGGED)
|
||||
if(CHECK_BITFIELD(obj_flags, EMAGGED))
|
||||
return
|
||||
if(isnull(linkedServer))
|
||||
to_chat(user, "<span class='notice'>A no server error appears on the screen.</span>")
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
screen = 2
|
||||
ENABLE_BITFIELD(obj_flags, EMAGGED)
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.start()
|
||||
var/obj/item/paper/monitorkey/MK = new(loc, linkedServer)
|
||||
// Will help make emagging the console not so easy to get away with.
|
||||
MK.info += "<br><br><font color='red'>�%@%(*$%&(�&?*(%&�/{}</font>"
|
||||
var/time = 100 * length(linkedServer.decryptkey)
|
||||
addtimer(CALLBACK(src, .proc/UnmagConsole), time)
|
||||
message = rebootmsg
|
||||
addtimer(CALLBACK(src, .proc/UnmagConsole), (10 SECONDS) * length(linkedServer.decryptkey))
|
||||
//message = rebootmsg
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/message_monitor/New()
|
||||
. = ..()
|
||||
GLOB.telecomms_list += src
|
||||
|
||||
/obj/machinery/computer/message_monitor/Initialize()
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/machinery/computer/message_monitor/LateInitialize()
|
||||
//Is the server isn't linked to a server, and there's a server available, default it to the first one in the list.
|
||||
if(!linkedServer)
|
||||
for(var/obj/machinery/telecomms/message_server/S in GLOB.telecomms_list)
|
||||
linkedServer = S
|
||||
break
|
||||
|
||||
/obj/machinery/computer/message_monitor/Destroy()
|
||||
GLOB.telecomms_list -= src
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/computer/message_monitor/ui_interact(mob/living/user)
|
||||
. = ..()
|
||||
//If the computer is being hacked or is emagged, display the reboot message.
|
||||
if(hacking || (obj_flags & EMAGGED))
|
||||
message = rebootmsg
|
||||
var/dat = "<center><font color='blue'[message]</font></center>"
|
||||
|
||||
if(auth)
|
||||
dat += "<h4><dd><A href='?src=[REF(src)];auth=1'>	<font color='green'>\[Authenticated\]</font></a>	/"
|
||||
dat += " Server Power: <A href='?src=[REF(src)];active=1'>[linkedServer && linkedServer.toggled ? "<font color='green'>\[On\]</font>":"<font color='red'>\[Off\]</font>"]</a></h4>"
|
||||
else
|
||||
dat += "<h4><dd><A href='?src=[REF(src)];auth=1'>	<font color='red'>\[Unauthenticated\]</font></a>	/"
|
||||
dat += " Server Power: <u>[linkedServer && linkedServer.toggled ? "<font color='green'>\[On\]</font>":"<font color='red'>\[Off\]</font>"]</u></h4>"
|
||||
|
||||
if(hacking || (obj_flags & EMAGGED))
|
||||
screen = 2
|
||||
else if(!auth || LINKED_SERVER_NONRESPONSIVE)
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
screen = 0
|
||||
|
||||
switch(screen)
|
||||
//Main menu
|
||||
if(0)
|
||||
//	 = TAB
|
||||
var/i = 0
|
||||
dat += "<dd><A href='?src=[REF(src)];find=1'>	[++i]. Link To A Server</a></dd>"
|
||||
if(auth)
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
dat += "<dd><A>	ERROR: Server not found!</A><br></dd>"
|
||||
else
|
||||
dat += "<dd><A href='?src=[REF(src)];view_logs=1'>	[++i]. View Message Logs </a><br></dd>"
|
||||
dat += "<dd><A href='?src=[REF(src)];view_requests=1'>	[++i]. View Request Console Logs </a></br></dd>"
|
||||
dat += "<dd><A href='?src=[REF(src)];clear_logs=1'>	[++i]. Clear Message Logs</a><br></dd>"
|
||||
dat += "<dd><A href='?src=[REF(src)];clear_requests=1'>	[++i]. Clear Request Console Logs</a><br></dd>"
|
||||
dat += "<dd><A href='?src=[REF(src)];pass=1'>	[++i]. Set Custom Key</a><br></dd>"
|
||||
dat += "<dd><A href='?src=[REF(src)];msg=1'>	[++i]. Send Admin Message</a><br></dd>"
|
||||
else
|
||||
for(var/n = ++i; n <= optioncount; n++)
|
||||
dat += "<dd><font color='blue'>	[n]. ---------------</font><br></dd>"
|
||||
var/mob/living/silicon/S = usr
|
||||
if(istype(S) && S.hack_software)
|
||||
//Malf/Traitor AIs can bruteforce into the system to gain the Key.
|
||||
dat += "<dd><A href='?src=[REF(src)];hack=1'><i><font color='Red'>*&@#. Bruteforce Key</font></i></font></a><br></dd>"
|
||||
else
|
||||
dat += "<br>"
|
||||
|
||||
//Bottom message
|
||||
if(!auth)
|
||||
dat += "<br><hr><dd><span class='notice'>Please authenticate with the server in order to show additional options.</span>"
|
||||
else
|
||||
dat += "<br><hr><dd><span class='warning'>Reg, #514 forbids sending messages to a Head of Staff containing Erotic Rendering Properties.</span>"
|
||||
|
||||
//Message Logs
|
||||
if(1)
|
||||
var/index = 0
|
||||
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];refresh=1'>Refresh</a></center><hr>"
|
||||
dat += "<table border='1' width='100%'><tr><th width = '5%'>X</th><th width='15%'>Sender</th><th width='15%'>Recipient</th><th width='300px' word-wrap: break-word>Message</th></tr>"
|
||||
for(var/datum/data_pda_msg/pda in linkedServer.pda_msgs)
|
||||
index++
|
||||
if(index > 3000)
|
||||
break
|
||||
// Del - Sender - Recepient - Message
|
||||
// X - Al Green - Your Mom - WHAT UP!?
|
||||
dat += "<tr><td width = '5%'><center><A href='?src=[REF(src)];delete_logs=[REF(pda)]' style='color: rgb(255,0,0)'>X</a></center></td><td width='15%'>[pda.sender]</td><td width='15%'>[pda.recipient]</td><td width='300px'>[pda.message][pda.picture ? " <a href='byond://?src=[REF(pda)];photo=1'>(Photo)</a>":""]</td></tr>"
|
||||
dat += "</table>"
|
||||
//Hacking screen.
|
||||
if(2)
|
||||
if(isAI(user) || iscyborg(user))
|
||||
dat += "Brute-forcing for server key.<br> It will take 20 seconds for every character that the password has."
|
||||
dat += "In the meantime, this console can reveal your true intentions if you let someone access it. Make sure no humans enter the room during that time."
|
||||
else
|
||||
//It's the same message as the one above but in binary. Because robots understand binary and humans don't... well I thought it was clever.
|
||||
dat += {"01000010011100100111010101110100011001010010110<br>
|
||||
10110011001101111011100100110001101101001011011100110011<br>
|
||||
10010000001100110011011110111001000100000011100110110010<br>
|
||||
10111001001110110011001010111001000100000011010110110010<br>
|
||||
10111100100101110001000000100100101110100001000000111011<br>
|
||||
10110100101101100011011000010000001110100011000010110101<br>
|
||||
10110010100100000001100100011000000100000011100110110010<br>
|
||||
10110001101101111011011100110010001110011001000000110011<br>
|
||||
00110111101110010001000000110010101110110011001010111001<br>
|
||||
00111100100100000011000110110100001100001011100100110000<br>
|
||||
10110001101110100011001010111001000100000011101000110100<br>
|
||||
00110000101110100001000000111010001101000011001010010000<br>
|
||||
00111000001100001011100110111001101110111011011110111001<br>
|
||||
00110010000100000011010000110000101110011001011100010000<br>
|
||||
00100100101101110001000000111010001101000011001010010000<br>
|
||||
00110110101100101011000010110111001110100011010010110110<br>
|
||||
10110010100101100001000000111010001101000011010010111001<br>
|
||||
10010000001100011011011110110111001110011011011110110110<br>
|
||||
00110010100100000011000110110000101101110001000000111001<br>
|
||||
00110010101110110011001010110000101101100001000000111100<br>
|
||||
10110111101110101011100100010000001110100011100100111010<br>
|
||||
10110010100100000011010010110111001110100011001010110111<br>
|
||||
00111010001101001011011110110111001110011001000000110100<br>
|
||||
10110011000100000011110010110111101110101001000000110110<br>
|
||||
00110010101110100001000000111001101101111011011010110010<br>
|
||||
10110111101101110011001010010000001100001011000110110001<br>
|
||||
10110010101110011011100110010000001101001011101000010111<br>
|
||||
00010000001001101011000010110101101100101001000000111001<br>
|
||||
10111010101110010011001010010000001101110011011110010000<br>
|
||||
00110100001110101011011010110000101101110011100110010000<br>
|
||||
00110010101101110011101000110010101110010001000000111010<br>
|
||||
00110100001100101001000000111001001101111011011110110110<br>
|
||||
10010000001100100011101010111001001101001011011100110011<br>
|
||||
10010000001110100011010000110000101110100001000000111010<br>
|
||||
001101001011011010110010100101110"}
|
||||
|
||||
//Fake messages
|
||||
if(3)
|
||||
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];Reset=1'>Reset</a></center><hr>"
|
||||
|
||||
dat += {"<table border='1' width='100%'>
|
||||
<tr><td width='20%'><A href='?src=[REF(src)];select=Sender'>Sender</a></td>
|
||||
<td width='20%'><A href='?src=[REF(src)];select=RecJob'>Sender's Job</a></td>
|
||||
<td width='20%'><A href='?src=[REF(src)];select=Recepient'>Recipient</a></td>
|
||||
<td width='300px' word-wrap: break-word><A href='?src=[REF(src)];select=Message'>Message</a></td></tr>"}
|
||||
//Sender - Sender's Job - Recepient - Message
|
||||
//Al Green- Your Dad - Your Mom - WHAT UP!?
|
||||
|
||||
dat += {"<tr><td width='20%'>[customsender]</td>
|
||||
<td width='20%'>[customjob]</td>
|
||||
<td width='20%'>[customrecepient ? customrecepient.owner : "NONE"]</td>
|
||||
<td width='300px'>[custommessage]</td></tr>"}
|
||||
dat += "</table><br><center><A href='?src=[REF(src)];select=Send'>Send</a>"
|
||||
|
||||
//Request Console Logs
|
||||
if(4)
|
||||
|
||||
var/index = 0
|
||||
/* data_rc_msg
|
||||
X - 5%
|
||||
var/rec_dpt = "Unspecified" //name of the person - 15%
|
||||
var/send_dpt = "Unspecified" //name of the sender- 15%
|
||||
var/message = "Blank" //transferred message - 300px
|
||||
var/stamp = "Unstamped" - 15%
|
||||
var/id_auth = "Unauthenticated" - 15%
|
||||
var/priority = "Normal" - 10%
|
||||
*/
|
||||
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];refresh=1'>Refresh</a></center><hr>"
|
||||
dat += {"<table border='1' width='100%'><tr><th width = '5%'>X</th><th width='15%'>Sending Dep.</th><th width='15%'>Receiving Dep.</th>
|
||||
<th width='300px' word-wrap: break-word>Message</th><th width='15%'>Stamp</th><th width='15%'>ID Auth.</th><th width='15%'>Priority.</th></tr>"}
|
||||
for(var/datum/data_rc_msg/rc in linkedServer.rc_msgs)
|
||||
index++
|
||||
if(index > 3000)
|
||||
break
|
||||
// Del - Sender - Recepient - Message
|
||||
// X - Al Green - Your Mom - WHAT UP!?
|
||||
dat += {"<tr><td width = '5%'><center><A href='?src=[REF(src)];delete_requests=[REF(rc)]' style='color: rgb(255,0,0)'>X</a></center></td><td width='15%'>[rc.send_dpt]</td>
|
||||
<td width='15%'>[rc.rec_dpt]</td><td width='300px'>[rc.message]</td><td width='15%'>[rc.stamp]</td><td width='15%'>[rc.id_auth]</td><td width='15%'>[rc.priority]</td></tr>"}
|
||||
dat += "</table>"
|
||||
|
||||
message = defaultmsg
|
||||
var/datum/browser/popup = new(user, "hologram_console", name, 700, 700)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/message_monitor/proc/BruteForce(mob/user)
|
||||
if(isnull(linkedServer))
|
||||
to_chat(user, "<span class='warning'>Could not complete brute-force: Linked Server Disconnected!</span>")
|
||||
@@ -245,10 +364,11 @@
|
||||
var/currentKey = linkedServer.decryptkey
|
||||
to_chat(user, "<span class='warning'>Brute-force completed! The key is '[currentKey]'.</span>")
|
||||
hacking = FALSE
|
||||
screen = 0 // Return the screen back to normal
|
||||
message = ""
|
||||
|
||||
/obj/machinery/computer/message_monitor/proc/UnmagConsole()
|
||||
obj_flags &= ~EMAGGED
|
||||
DISABLE_BITFIELD(obj_flags, EMAGGED)
|
||||
message = ""
|
||||
|
||||
/obj/machinery/computer/message_monitor/proc/ResetMessage()
|
||||
customsender = "System Administrator"
|
||||
@@ -256,199 +376,12 @@
|
||||
custommessage = "This is a test, please ignore."
|
||||
customjob = "Admin"
|
||||
|
||||
/obj/machinery/computer/message_monitor/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || hasSiliconAccessInArea(usr))
|
||||
//Authenticate
|
||||
if (href_list["auth"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else if(auth)
|
||||
auth = FALSE
|
||||
screen = 0
|
||||
else
|
||||
var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
|
||||
if(dkey && dkey != "")
|
||||
if(linkedServer.decryptkey == dkey)
|
||||
auth = TRUE
|
||||
else
|
||||
message = incorrectkey
|
||||
|
||||
//Turn the server on/off.
|
||||
if (href_list["active"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else if(auth)
|
||||
linkedServer.toggled = !linkedServer.toggled
|
||||
//Find a server
|
||||
if (href_list["find"])
|
||||
var/list/message_servers = list()
|
||||
for (var/obj/machinery/telecomms/message_server/M in GLOB.telecomms_list)
|
||||
message_servers += M
|
||||
|
||||
if(message_servers.len > 1)
|
||||
linkedServer = input(usr, "Please select a server.", "Select a server.", null) as null|anything in message_servers
|
||||
message = "<span class='alert'>NOTICE: Server selected.</span>"
|
||||
else if(message_servers.len > 0)
|
||||
linkedServer = message_servers[1]
|
||||
message = "<span class='notice'>NOTICE: Only Single Server Detected - Server selected.</span>"
|
||||
else
|
||||
message = noserver
|
||||
|
||||
//View the logs - KEY REQUIRED
|
||||
if (href_list["view_logs"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else if(auth)
|
||||
screen = 1
|
||||
|
||||
//Clears the logs - KEY REQUIRED
|
||||
if (href_list["clear_logs"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else if(auth)
|
||||
linkedServer.pda_msgs = list()
|
||||
message = "<span class='notice'>NOTICE: Logs cleared.</span>"
|
||||
//Clears the request console logs - KEY REQUIRED
|
||||
if (href_list["clear_requests"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else if(auth)
|
||||
linkedServer.rc_msgs = list()
|
||||
message = "<span class='notice'>NOTICE: Logs cleared.</span>"
|
||||
//Change the password - KEY REQUIRED
|
||||
if (href_list["pass"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else if(auth)
|
||||
var/dkey = stripped_input(usr, "Please enter the decryption key.")
|
||||
if(dkey && dkey != "")
|
||||
if(linkedServer.decryptkey == dkey)
|
||||
var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):"))
|
||||
if(length(newkey) <= 3)
|
||||
message = "<span class='notice'>NOTICE: Decryption key too short!</span>"
|
||||
else if(length(newkey) > 16)
|
||||
message = "<span class='notice'>NOTICE: Decryption key too long!</span>"
|
||||
else if(newkey && newkey != "")
|
||||
linkedServer.decryptkey = newkey
|
||||
message = "<span class='notice'>NOTICE: Decryption key set.</span>"
|
||||
else
|
||||
message = incorrectkey
|
||||
|
||||
//Hack the Console to get the password
|
||||
if (href_list["hack"])
|
||||
var/mob/living/silicon/S = usr
|
||||
if(istype(S) && S.hack_software)
|
||||
hacking = TRUE
|
||||
screen = 2
|
||||
//Time it takes to bruteforce is dependant on the password length.
|
||||
spawn(100*length(linkedServer.decryptkey))
|
||||
if(src && linkedServer && usr)
|
||||
BruteForce(usr)
|
||||
//Delete the log.
|
||||
if (href_list["delete_logs"])
|
||||
//Are they on the view logs screen?
|
||||
if(screen == 1)
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else //if(istype(href_list["delete_logs"], /datum/data_pda_msg))
|
||||
linkedServer.pda_msgs -= locate(href_list["delete_logs"])
|
||||
message = "<span class='notice'>NOTICE: Log Deleted!</span>"
|
||||
//Delete the request console log.
|
||||
if (href_list["delete_requests"])
|
||||
//Are they on the view logs screen?
|
||||
if(screen == 4)
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else //if(istype(href_list["delete_logs"], /datum/data_pda_msg))
|
||||
linkedServer.rc_msgs -= locate(href_list["delete_requests"])
|
||||
message = "<span class='notice'>NOTICE: Log Deleted!</span>"
|
||||
//Create a custom message
|
||||
if (href_list["msg"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else if(auth)
|
||||
screen = 3
|
||||
//Fake messaging selection - KEY REQUIRED
|
||||
if (href_list["select"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
screen = 0
|
||||
else
|
||||
switch(href_list["select"])
|
||||
|
||||
//Reset
|
||||
if("Reset")
|
||||
ResetMessage()
|
||||
|
||||
//Select Your Name
|
||||
if("Sender")
|
||||
customsender = stripped_input(usr, "Please enter the sender's name.") || customsender
|
||||
|
||||
//Select Receiver
|
||||
if("Recepient")
|
||||
//Get out list of viable PDAs
|
||||
var/list/obj/item/pda/sendPDAs = get_viewable_pdas()
|
||||
if(GLOB.PDAs && GLOB.PDAs.len > 0)
|
||||
customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortNames(sendPDAs)
|
||||
else
|
||||
customrecepient = null
|
||||
|
||||
//Enter custom job
|
||||
if("RecJob")
|
||||
customjob = stripped_input(usr, "Please enter the sender's job.") || customjob
|
||||
|
||||
//Enter message
|
||||
if("Message")
|
||||
custommessage = stripped_input(usr, "Please enter your message.") || custommessage
|
||||
|
||||
//Send message
|
||||
if("Send")
|
||||
if(isnull(customsender) || customsender == "")
|
||||
customsender = "UNKNOWN"
|
||||
|
||||
if(isnull(customrecepient))
|
||||
message = "<span class='notice'>NOTICE: No recepient selected!</span>"
|
||||
return attack_hand(usr)
|
||||
|
||||
if(isnull(custommessage) || custommessage == "")
|
||||
message = "<span class='notice'>NOTICE: No message entered!</span>"
|
||||
return attack_hand(usr)
|
||||
|
||||
var/datum/signal/subspace/pda/signal = new(src, list(
|
||||
"name" = "[customsender]",
|
||||
"job" = "[customjob]",
|
||||
"message" = custommessage,
|
||||
"emojis" = TRUE,
|
||||
"targets" = list("[customrecepient.owner] ([customrecepient.ownjob])")
|
||||
))
|
||||
// this will log the signal and transmit it to the target
|
||||
linkedServer.receive_information(signal, null)
|
||||
usr.log_message("(PDA: [name] | [usr.real_name]) sent \"[custommessage]\" to [signal.format_target()]", LOG_PDA)
|
||||
|
||||
|
||||
//Request Console Logs - KEY REQUIRED
|
||||
if(href_list["view_requests"])
|
||||
if(LINKED_SERVER_NONRESPONSIVE)
|
||||
message = noserver
|
||||
else if(auth)
|
||||
screen = 4
|
||||
|
||||
if (href_list["back"])
|
||||
screen = 0
|
||||
|
||||
return attack_hand(usr)
|
||||
|
||||
#undef LINKED_SERVER_NONRESPONSIVE
|
||||
|
||||
/obj/item/paper/monitorkey
|
||||
name = "monitor decryption key"
|
||||
|
||||
/obj/item/paper/monitorkey/Initialize(mapload, obj/machinery/telecomms/message_server/server)
|
||||
..()
|
||||
if (server)
|
||||
if(server)
|
||||
print(server)
|
||||
return INITIALIZE_HINT_NORMAL
|
||||
else
|
||||
@@ -459,7 +392,7 @@
|
||||
add_overlay("paper_words")
|
||||
|
||||
/obj/item/paper/monitorkey/LateInitialize()
|
||||
for (var/obj/machinery/telecomms/message_server/server in GLOB.telecomms_list)
|
||||
if (server.decryptkey)
|
||||
for(var/obj/machinery/telecomms/message_server/server in GLOB.telecomms_list)
|
||||
if(server.decryptkey)
|
||||
print(server)
|
||||
break
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
Telecomms monitor tracks the overall trafficing of a telecommunications network
|
||||
and displays a heirarchy of linked machines.
|
||||
@@ -10,117 +9,98 @@
|
||||
icon_screen = "comm_monitor"
|
||||
desc = "Monitors the details of the telecommunications network it's synced with."
|
||||
|
||||
var/screen = 0 // the screen number:
|
||||
var/list/machinelist = list() // the machines located by the computer
|
||||
var/obj/machinery/telecomms/SelectedMachine
|
||||
var/obj/machinery/telecomms/SelectedMachine = null
|
||||
|
||||
var/network = "NULL" // the network to probe
|
||||
var/notice = ""
|
||||
|
||||
var/temp = "" // temporary feedback messages
|
||||
circuit = /obj/item/circuitboard/computer/comm_monitor
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user)
|
||||
. = ..()
|
||||
var/dat = "<TITLE>Telecommunications Monitor</TITLE><center><b>Telecommunications Monitor</b></center>"
|
||||
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
|
||||
switch(screen)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "telemonitor", name, 575, 400, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/ui_data(mob/user)
|
||||
var/list/data_out = list()
|
||||
data_out["network"] = network
|
||||
data_out["notice"] = notice
|
||||
|
||||
// --- Main Menu ---
|
||||
data_out["servers"] = list()
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
var/list/data = list(
|
||||
name = T.name,
|
||||
id = T.id,
|
||||
ref = REF(T)
|
||||
)
|
||||
data_out["servers"] += list(data)
|
||||
data_out["servers"] = sortList(data_out["servers"])
|
||||
|
||||
if(0)
|
||||
dat += "<br>[temp]<br><br>"
|
||||
dat += "<br>Current Network: <a href='?src=[REF(src)];network=1'>[network]</a><br>"
|
||||
if(machinelist.len)
|
||||
dat += "<br>Detected Network Entities:<ul>"
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
dat += "<li><a href='?src=[REF(src)];viewmachine=[T.id]'>[REF(T)] [T.name]</a> ([T.id])</li>"
|
||||
dat += "</ul>"
|
||||
dat += "<br><a href='?src=[REF(src)];operation=release'>\[Flush Buffer\]</a>"
|
||||
else
|
||||
dat += "<a href='?src=[REF(src)];operation=probe'>\[Probe Network\]</a>"
|
||||
if(!SelectedMachine) //null is bad.
|
||||
data_out["selected"] = null //but in js, null is good.
|
||||
return data_out
|
||||
|
||||
data_out["selected"] = list(
|
||||
name = SelectedMachine.name,
|
||||
id = SelectedMachine.id,
|
||||
status = SelectedMachine.on,
|
||||
traffic = SelectedMachine.traffic,
|
||||
netspeed = SelectedMachine.netspeed,
|
||||
freq_listening = SelectedMachine.freq_listening,
|
||||
long_range_link = SelectedMachine.long_range_link,
|
||||
ref = REF(SelectedMachine)
|
||||
)
|
||||
data_out["selected_servers"] = list()
|
||||
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
|
||||
if(!T.hide)
|
||||
var/list/data = list(
|
||||
name = T.name,
|
||||
id = T.id,
|
||||
ref = REF(T)
|
||||
)
|
||||
data_out["selected_servers"] += list(data)
|
||||
|
||||
return data_out
|
||||
|
||||
// --- Viewing Machine ---
|
||||
|
||||
if(1)
|
||||
dat += "<br>[temp]<br>"
|
||||
dat += "<center><a href='?src=[REF(src)];operation=mainmenu'>\[Main Menu\]</a></center>"
|
||||
dat += "<br>Current Network: [network]<br>"
|
||||
dat += "Selected Network Entity: [SelectedMachine.name] ([SelectedMachine.id])<br>"
|
||||
dat += "Linked Entities: <ol>"
|
||||
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
|
||||
if(!T.hide)
|
||||
dat += "<li><a href='?src=[REF(src)];viewmachine=[T.id]'>[REF(T.id)] [T.name]</a> ([T.id])</li>"
|
||||
dat += "</ol>"
|
||||
|
||||
|
||||
|
||||
user << browse(dat, "window=comm_monitor;size=575x400")
|
||||
onclose(user, "server_control")
|
||||
|
||||
temp = ""
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/Topic(href, href_list)
|
||||
/obj/machinery/computer/telecomms/monitor/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("mainmenu")
|
||||
SelectedMachine = null
|
||||
notice = ""
|
||||
return
|
||||
if("release")
|
||||
machinelist = list()
|
||||
notice = ""
|
||||
return
|
||||
if("network") //network change, flush the selected machine and buffer
|
||||
var/newnet = sanitize(sanitize_text(params["value"], network))
|
||||
if(length(newnet) > 15) //i'm looking at you, you href fuckers
|
||||
notice = "FAILED: Network tag string too lengthy"
|
||||
return
|
||||
network = newnet
|
||||
SelectedMachine = null
|
||||
machinelist = list()
|
||||
return
|
||||
if("probe")
|
||||
if(LAZYLEN(machinelist) > 0)
|
||||
notice = "FAILED: Cannot probe when buffer full"
|
||||
return
|
||||
|
||||
for(var/obj/machinery/telecomms/T in GLOB.telecomms_list)
|
||||
if(T.network == network)
|
||||
LAZYADD(machinelist, T)
|
||||
|
||||
|
||||
add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["viewmachine"])
|
||||
screen = 1
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
if(T.id == href_list["viewmachine"])
|
||||
SelectedMachine = T
|
||||
break
|
||||
|
||||
if(href_list["operation"])
|
||||
switch(href_list["operation"])
|
||||
|
||||
if("release")
|
||||
machinelist = list()
|
||||
screen = 0
|
||||
|
||||
if("mainmenu")
|
||||
screen = 0
|
||||
|
||||
if("probe")
|
||||
if(machinelist.len > 0)
|
||||
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font color>"
|
||||
|
||||
else
|
||||
for(var/obj/machinery/telecomms/T in urange(25, src))
|
||||
if(T.network == network)
|
||||
machinelist.Add(T)
|
||||
|
||||
if(!machinelist.len)
|
||||
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\] -</font color>"
|
||||
else
|
||||
temp = "<font color = #336699>- [machinelist.len] ENTITIES LOCATED & BUFFERED -</font color>"
|
||||
|
||||
screen = 0
|
||||
|
||||
|
||||
if(href_list["network"])
|
||||
|
||||
var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network)
|
||||
if(newnet && ((usr in range(1, src)) || hasSiliconAccessInArea(usr)))
|
||||
if(length(newnet) > 15)
|
||||
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font color>"
|
||||
|
||||
else
|
||||
network = newnet
|
||||
screen = 0
|
||||
machinelist = list()
|
||||
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font color>"
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/attackby()
|
||||
. = ..()
|
||||
updateUsrDialog()
|
||||
if(!LAZYLEN(machinelist))
|
||||
notice = "FAILED: Unable to locate network entities in \[[network]\]"
|
||||
return
|
||||
if("viewmachine")
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
if(T.id == params["value"])
|
||||
SelectedMachine = T
|
||||
break
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
var/temp = "" // output message
|
||||
|
||||
/obj/machinery/telecomms/attackby(obj/item/P, mob/user, params)
|
||||
|
||||
var/icon_closed = initial(icon_state)
|
||||
var/icon_open = "[initial(icon_state)]_o"
|
||||
|
||||
if(!on)
|
||||
icon_closed = "[initial(icon_state)]_off"
|
||||
icon_open = "[initial(icon_state)]_o_off"
|
||||
@@ -27,78 +27,240 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/ui_interact(mob/user)
|
||||
. = ..()
|
||||
// You need a multitool to use this, or be silicon
|
||||
if(!hasSiliconAccessInArea(user))
|
||||
// istype returns false if the value is null
|
||||
if(!istype(user.get_active_held_item(), /obj/item/multitool))
|
||||
return
|
||||
/obj/machinery/telecomms/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
if(!canInteract(user))
|
||||
if(ui)
|
||||
ui.close() //haha no.
|
||||
return
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "teleinteract", "[name] Access", 520, 500, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/telecomms/ui_data(mob/user)
|
||||
. = list() //cpypaste from the vending bus
|
||||
.["notice"] = temp
|
||||
.["multitool"] = FALSE
|
||||
var/obj/item/multitool/P = get_multitool(user)
|
||||
var/dat
|
||||
dat = "<font face = \"Courier\"><HEAD><TITLE>[name]</TITLE></HEAD><center><H3>[name] Access</H3></center>"
|
||||
dat += "<br>[temp]<br>"
|
||||
dat += "<br>Power Status: <a href='?src=[REF(src)];input=toggle'>[toggled ? "On" : "Off"]</a>"
|
||||
if(on && toggled)
|
||||
if(id != "" && id)
|
||||
dat += "<br>Identification String: <a href='?src=[REF(src)];input=id'>[id]</a>"
|
||||
else
|
||||
dat += "<br>Identification String: <a href='?src=[REF(src)];input=id'>NULL</a>"
|
||||
dat += "<br>Network: <a href='?src=[REF(src)];input=network'>[network]</a>"
|
||||
dat += "<br>Prefabrication: [autolinkers.len ? "TRUE" : "FALSE"]"
|
||||
if(hide)
|
||||
dat += "<br>Shadow Link: ACTIVE</a>"
|
||||
if(P)
|
||||
.["multitool"] = TRUE
|
||||
.["multitool_buf"] = null //to clean the list!
|
||||
var/obj/machinery/telecomms/T = P.buffer
|
||||
if(istype(T))
|
||||
.["multitool_buf"] = list(
|
||||
name = T.name,
|
||||
id = T.id
|
||||
)
|
||||
|
||||
//Show additional options for certain machines.
|
||||
dat += Options_Menu()
|
||||
.["machine"] = list()
|
||||
.["machine"]["power"] = toggled
|
||||
.["machine"]["id"] = id
|
||||
.["machine"]["network"] = network
|
||||
.["machine"]["prefab"] = LAZYLEN(autolinkers) ? TRUE : FALSE
|
||||
.["machine"]["hidden"] = hide
|
||||
|
||||
dat += "<br>Linked Network Entities: <ol>"
|
||||
.["links"] = list()
|
||||
for(var/obj/machinery/telecomms/T in links)
|
||||
if(T.hide && !hide)
|
||||
continue
|
||||
var/list/data = list(
|
||||
name = T.name,
|
||||
id = T.id,
|
||||
ref = REF(T)
|
||||
)
|
||||
.["links"] += list(data)
|
||||
|
||||
var/i = 0
|
||||
for(var/obj/machinery/telecomms/T in links)
|
||||
i++
|
||||
if(T.hide && !hide)
|
||||
continue
|
||||
dat += "<li>[REF(T)] [T.name] ([T.id]) <a href='?src=[REF(src)];unlink=[i]'>\[X\]</a></li>"
|
||||
dat += "</ol>"
|
||||
.["freq_listening"] = freq_listening
|
||||
|
||||
dat += "<br>Filtering Frequencies: "
|
||||
/obj/machinery/telecomms/relay/ui_data(mob/user)
|
||||
. = ..()
|
||||
.["machine"]["isrelay"] = TRUE
|
||||
.["machine"]["broadcast"] = broadcasting
|
||||
.["machine"]["receiving"] = receiving
|
||||
|
||||
i = 0
|
||||
if(length(freq_listening))
|
||||
for(var/x in freq_listening)
|
||||
i++
|
||||
if(i < length(freq_listening))
|
||||
dat += "[format_frequency(x)] GHz<a href='?src=[REF(src)];delete=[x]'>\[X\]</a>; "
|
||||
else
|
||||
dat += "[format_frequency(x)] GHz<a href='?src=[REF(src)];delete=[x]'>\[X\]</a>"
|
||||
else
|
||||
dat += "NONE"
|
||||
/obj/machinery/telecomms/bus/ui_data(mob/user)
|
||||
. = ..()
|
||||
.["machine"]["isbus"] = TRUE
|
||||
.["machine"]["chang_frequency"] = change_frequency
|
||||
.["machine"]["chang_freq_value"] = change_freq_value
|
||||
|
||||
dat += "<br> <a href='?src=[REF(src)];input=freq'>\[Add Filter\]</a>"
|
||||
dat += "<hr>"
|
||||
|
||||
if(P)
|
||||
var/obj/machinery/telecomms/T = P.buffer
|
||||
if(istype(T))
|
||||
dat += "<br><br>MULTITOOL BUFFER: [T] ([T.id]) <a href='?src=[REF(src)];link=1'>\[Link\]</a> <a href='?src=[REF(src)];flush=1'>\[Flush\]"
|
||||
else
|
||||
dat += "<br><br>MULTITOOL BUFFER: <a href='?src=[REF(src)];buffer=1'>\[Add Machine\]</a>"
|
||||
|
||||
dat += "</font>"
|
||||
/obj/machinery/telecomms/ui_act(action, params, datum/tgui/ui)
|
||||
if(!canInteract(usr))
|
||||
if(ui)
|
||||
ui.close() //haha no.
|
||||
return
|
||||
temp = ""
|
||||
user << browse(dat, "window=tcommachine;size=520x500;can_resize=0")
|
||||
onclose(user, "tcommachine")
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("toggle")
|
||||
toggled = !toggled
|
||||
temp = "-% [src.name] has been [toggled ? "activated" : "deactivated"]. %-"
|
||||
update_power()
|
||||
return
|
||||
if("machine")
|
||||
if("id" in params)
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
//if the text is blank, return the id it was using
|
||||
var/newid = sanitize_text(reject_bad_text(params["id"]), id) // reject_bad_text can return null!
|
||||
if(length(newid) > 255)
|
||||
temp = "-% Too many characters in new id tag. %-"
|
||||
return
|
||||
temp = "-% New ID assigned: \"[newid]\". %-"
|
||||
id = newid
|
||||
return
|
||||
if("network" in params)
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
var/newnet = sanitize(sanitize_text(params["network"], network))
|
||||
if(length(newnet) > 15)
|
||||
temp = "-% Too many characters in new network tag. %-"
|
||||
return
|
||||
network = newnet
|
||||
links = list()
|
||||
temp = "-% New network tag assigned: \"[network]\" %-"
|
||||
return
|
||||
if("multitool")
|
||||
var/obj/item/multitool/P = get_multitool(usr)
|
||||
if("Link" in params)
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
if(!istype(P))
|
||||
temp = "-% Unable to acquire buffer %-"
|
||||
return
|
||||
|
||||
var/obj/machinery/telecomms/T = P.buffer
|
||||
if(!istype(T) || T == src)
|
||||
temp = "-% Unable to acquire buffer %-"
|
||||
return
|
||||
|
||||
if(!(src in T.links))
|
||||
LAZYADD(T.links, src)
|
||||
|
||||
if(!(T in links))
|
||||
LAZYADD(links, T)
|
||||
temp = "-% Successfully linked with [REF(T)] [T.name] %-"
|
||||
|
||||
if("Flush" in params)
|
||||
if(!istype(P))
|
||||
temp = "-% Unable to acquire multitool %-"
|
||||
return
|
||||
|
||||
temp = "-% Buffer successfully flushed. %-"
|
||||
P.buffer = null
|
||||
|
||||
if("Add" in params)
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
if(!istype(P))
|
||||
temp = "-% Unable to acquire multitool %-"
|
||||
return
|
||||
|
||||
P.buffer = src
|
||||
temp = "% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-"
|
||||
|
||||
if("unlink")
|
||||
var/obj/machinery/telecomms/T = locate(params["value"])
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
if(!istype(T))
|
||||
temp = "-% Unable to locate machine to unlink from, try again. %-"
|
||||
return
|
||||
|
||||
temp = "-% Removed [REF(T)] [T.name] from linked entities. %-"
|
||||
if(T.links) //lazyrem makes blank list null, which is good but some might cause runtime ee's
|
||||
T.links.Remove(src)
|
||||
links.Remove(T)
|
||||
if("freq")
|
||||
if("add" in params)
|
||||
var/newfreq = input("Specify a new frequency to filter (GHz). Decimals assigned automatically.", src.name, null) as null|num
|
||||
if(!canAccess(usr) || !newfreq || isnull(newfreq))
|
||||
return
|
||||
|
||||
if(findtext(num2text(newfreq), ".")) // did they not read the text?
|
||||
newfreq *= 10 // shift the decimal one place
|
||||
|
||||
newfreq = sanitize_frequency(newfreq, TRUE) //sanitize
|
||||
if(newfreq == FREQ_SYNDICATE)
|
||||
temp = "-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-"
|
||||
return
|
||||
if(newfreq in freq_listening)
|
||||
temp = "-% Error: Frequency already filtered %-"
|
||||
return
|
||||
|
||||
LAZYADD(freq_listening, newfreq)
|
||||
temp = "-% New frequency filter assigned: \"[newfreq] GHz\" %-"
|
||||
|
||||
if("remove" in params)
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
var/x = text2num(params["remove"])
|
||||
temp = "-% Removed frequency filter [x] %-"
|
||||
freq_listening.Remove(x)
|
||||
|
||||
/obj/machinery/telecomms/relay/ui_act(action, params)
|
||||
..()
|
||||
switch(action)
|
||||
if("relay")
|
||||
if("broadcast" in params)
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
broadcasting = !broadcasting
|
||||
temp = "-% Broadcasting mode changed. %-"
|
||||
return
|
||||
if("receiving" in params)
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
receiving = !receiving
|
||||
temp = "-% Receiving mode changed. %-"
|
||||
|
||||
/obj/machinery/telecomms/bus/ui_act(action, params)
|
||||
..()
|
||||
switch(action)
|
||||
if("frequency")
|
||||
if("toggle" in params)
|
||||
if(!canAccess(usr))
|
||||
return
|
||||
change_frequency = !change_frequency
|
||||
return
|
||||
if("adjust" in params)
|
||||
var/newfreq = text2num(params["adjust"])
|
||||
if(!canAccess(usr) || !newfreq)
|
||||
return
|
||||
// this should return true, unless the href is handcrafted
|
||||
if(findtext(num2text(newfreq), "."))
|
||||
newfreq *= 10 // shift the decimal one place
|
||||
|
||||
newfreq = sanitize_frequency(newfreq, TRUE)
|
||||
if(newfreq == FREQ_SYNDICATE)
|
||||
temp = "-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-"
|
||||
return
|
||||
|
||||
change_freq_value = newfreq
|
||||
temp = "-% New frequency to change to assigned: \"[newfreq] GHz\" %-"
|
||||
return
|
||||
|
||||
// Check if the user can use it.
|
||||
/obj/machinery/telecomms/proc/canInteract(mob/user)
|
||||
if(hasSiliconAccessInArea(user) || istype(user.get_active_held_item(), /obj/item/multitool))
|
||||
return TRUE
|
||||
return FALSE
|
||||
// Check if the user is nearby and has a multitool.
|
||||
/obj/machinery/telecomms/proc/canAccess(mob/user)
|
||||
if((canInteract(user) && in_range(user, src)) || hasSiliconAccessInArea(user))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Returns a multitool from a user depending on their mobtype.
|
||||
|
||||
/obj/machinery/telecomms/proc/get_multitool(mob/user)
|
||||
|
||||
var/obj/item/multitool/P = null
|
||||
// Let's double check
|
||||
if(!hasSiliconAccessInArea(user) && istype(user.get_active_held_item(), /obj/item/multitool))
|
||||
P = user.get_active_held_item()
|
||||
if(!canInteract(user))
|
||||
return null
|
||||
var/obj/item/multitool/P = user.get_active_held_item()
|
||||
// Is the ref not a null? and is it the actual type?
|
||||
if(istype(P))
|
||||
return P
|
||||
else if(isAI(user))
|
||||
var/mob/living/silicon/ai/U = user
|
||||
P = U.aiMulti
|
||||
@@ -106,170 +268,3 @@
|
||||
if(istype(user.get_active_held_item(), /obj/item/multitool))
|
||||
P = user.get_active_held_item()
|
||||
return P
|
||||
|
||||
// Additional Options for certain machines. Use this when you want to add an option to a specific machine.
|
||||
// Example of how to use below.
|
||||
|
||||
/obj/machinery/telecomms/proc/Options_Menu()
|
||||
return ""
|
||||
|
||||
// The topic for Additional Options. Use this for checking href links for your specific option.
|
||||
// Example of how to use below.
|
||||
/obj/machinery/telecomms/proc/Options_Topic(href, href_list)
|
||||
return
|
||||
|
||||
// RELAY
|
||||
|
||||
/obj/machinery/telecomms/relay/Options_Menu()
|
||||
var/dat = ""
|
||||
dat += "<br>Broadcasting: <A href='?src=[REF(src)];broadcast=1'>[broadcasting ? "YES" : "NO"]</a>"
|
||||
dat += "<br>Receiving: <A href='?src=[REF(src)];receive=1'>[receiving ? "YES" : "NO"]</a>"
|
||||
return dat
|
||||
|
||||
/obj/machinery/telecomms/relay/Options_Topic(href, href_list)
|
||||
|
||||
if(href_list["receive"])
|
||||
receiving = !receiving
|
||||
temp = "<font color = #666633>-% Receiving mode changed. %-</font color>"
|
||||
if(href_list["broadcast"])
|
||||
broadcasting = !broadcasting
|
||||
temp = "<font color = #666633>-% Broadcasting mode changed. %-</font color>"
|
||||
|
||||
// BUS
|
||||
|
||||
/obj/machinery/telecomms/bus/Options_Menu()
|
||||
var/dat = "<br>Change Signal Frequency: <A href='?src=[REF(src)];change_freq=1'>[change_frequency ? "YES ([change_frequency])" : "NO"]</a>"
|
||||
return dat
|
||||
|
||||
/obj/machinery/telecomms/bus/Options_Topic(href, href_list)
|
||||
|
||||
if(href_list["change_freq"])
|
||||
|
||||
var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null|num
|
||||
if(canAccess(usr))
|
||||
if(newfreq)
|
||||
if(findtext(num2text(newfreq), "."))
|
||||
newfreq *= 10 // shift the decimal one place
|
||||
if(newfreq < 10000)
|
||||
change_frequency = newfreq
|
||||
temp = "<font color = #666633>-% New frequency to change to assigned: \"[newfreq] GHz\" %-</font color>"
|
||||
else
|
||||
change_frequency = 0
|
||||
temp = "<font color = #666633>-% Frequency changing deactivated %-</font color>"
|
||||
|
||||
|
||||
/obj/machinery/telecomms/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(!hasSiliconAccessInArea(usr))
|
||||
if(!istype(usr.get_active_held_item(), /obj/item/multitool))
|
||||
return
|
||||
|
||||
var/obj/item/multitool/P = get_multitool(usr)
|
||||
|
||||
if(href_list["input"])
|
||||
switch(href_list["input"])
|
||||
|
||||
if("toggle")
|
||||
|
||||
toggled = !toggled
|
||||
temp = "<font color = #666633>-% [src] has been [toggled ? "activated" : "deactivated"].</font color>"
|
||||
update_power()
|
||||
|
||||
|
||||
if("id")
|
||||
var/newid = reject_bad_text(stripped_input(usr, "Specify the new ID for this machine", src, id, MAX_MESSAGE_LEN))
|
||||
if(newid && canAccess(usr))
|
||||
id = newid
|
||||
temp = "<font color = #666633>-% New ID assigned: \"[id]\" %-</font color>"
|
||||
|
||||
if("network")
|
||||
var/newnet = stripped_input(usr, "Specify the new network for this machine. This will break all current links.", src, network)
|
||||
if(newnet && canAccess(usr))
|
||||
|
||||
if(length(newnet) > 15)
|
||||
temp = "<font color = #666633>-% Too many characters in new network tag %-</font color>"
|
||||
|
||||
else
|
||||
for(var/obj/machinery/telecomms/T in links)
|
||||
T.links.Remove(src)
|
||||
|
||||
network = newnet
|
||||
links = list()
|
||||
temp = "<font color = #666633>-% New network tag assigned: \"[network]\" %-</font color>"
|
||||
|
||||
|
||||
if("freq")
|
||||
var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null|num
|
||||
if(newfreq && canAccess(usr))
|
||||
if(findtext(num2text(newfreq), "."))
|
||||
newfreq *= 10 // shift the decimal one place
|
||||
if(newfreq == FREQ_SYNDICATE)
|
||||
temp = "<font color = #FF0000>-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-</font color>"
|
||||
else
|
||||
if(!(newfreq in freq_listening) && newfreq < 10000)
|
||||
freq_listening.Add(newfreq)
|
||||
temp = "<font color = #666633>-% New frequency filter assigned: \"[newfreq] GHz\" %-</font color>"
|
||||
|
||||
if(href_list["delete"])
|
||||
|
||||
// changed the layout about to workaround a pesky runtime -- Doohl
|
||||
|
||||
var/x = text2num(href_list["delete"])
|
||||
temp = "<font color = #666633>-% Removed frequency filter [x] %-</font color>"
|
||||
freq_listening.Remove(x)
|
||||
|
||||
if(href_list["unlink"])
|
||||
|
||||
if(text2num(href_list["unlink"]) <= length(links))
|
||||
var/obj/machinery/telecomms/T = links[text2num(href_list["unlink"])]
|
||||
if(T)
|
||||
temp = "<font color = #666633>-% Removed [REF(T)] [T.name] from linked entities. %-</font color>"
|
||||
|
||||
// Remove link entries from both T and src.
|
||||
|
||||
if(T.links)
|
||||
T.links.Remove(src)
|
||||
links.Remove(T)
|
||||
|
||||
else
|
||||
temp = "<font color = #666633>-% Unable to locate machine to unlink from, try again. %-</font color>"
|
||||
|
||||
if(href_list["link"])
|
||||
|
||||
if(P)
|
||||
var/obj/machinery/telecomms/T = P.buffer
|
||||
if(istype(T) && T != src)
|
||||
if(!(src in T.links))
|
||||
T.links += src
|
||||
|
||||
if(!(T in links))
|
||||
links += T
|
||||
|
||||
temp = "<font color = #666633>-% Successfully linked with [REF(T)] [T.name] %-</font color>"
|
||||
|
||||
else
|
||||
temp = "<font color = #666633>-% Unable to acquire buffer %-</font color>"
|
||||
|
||||
if(href_list["buffer"])
|
||||
|
||||
P.buffer = src
|
||||
temp = "<font color = #666633>-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-</font color>"
|
||||
|
||||
|
||||
if(href_list["flush"])
|
||||
|
||||
temp = "<font color = #666633>-% Buffer successfully flushed. %-</font color>"
|
||||
P.buffer = null
|
||||
|
||||
Options_Topic(href, href_list)
|
||||
|
||||
usr.set_machine(src)
|
||||
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/telecomms/proc/canAccess(mob/user)
|
||||
if(hasSiliconAccessInArea(user) || in_range(user, src))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
idle_power_usage = 50
|
||||
netspeed = 40
|
||||
circuit = /obj/item/circuitboard/machine/telecomms/bus
|
||||
var/change_frequency = 0
|
||||
var/change_frequency = FALSE
|
||||
var/change_freq_value = 0
|
||||
|
||||
/obj/machinery/telecomms/bus/RefreshParts()
|
||||
idle_power_usage = 50
|
||||
@@ -28,8 +29,8 @@
|
||||
if(!istype(signal) || !is_freq_listening(signal))
|
||||
return
|
||||
|
||||
if(change_frequency && signal.frequency != FREQ_SYNDICATE)
|
||||
signal.frequency = change_frequency
|
||||
if(change_frequency && (change_freq_value && signal.frequency != FREQ_SYNDICATE))
|
||||
signal.frequency = change_freq_value
|
||||
|
||||
if(!istype(machine_from, /obj/machinery/telecomms/processor) && machine_from != src) // Signal must be ready (stupid assuming machine), let's send it
|
||||
// send to one linked processor unit
|
||||
|
||||
@@ -140,11 +140,16 @@
|
||||
..()
|
||||
if(href_list["photo"])
|
||||
var/mob/M = usr
|
||||
M << browse_rsc(picture.picture_image, "pda_photo.png")
|
||||
M << browse("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>PDA Photo</title></head>" \
|
||||
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
|
||||
+ "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />" \
|
||||
+ "</body></html>", "window=pdaphoto;size=[picture.psize_x]x[picture.psize_y];can-close=true")
|
||||
|
||||
M << browse_rsc(picture.picture_image, "pda_photo.png")
|
||||
|
||||
var/dat = "<div style='overflow: hidden; margin :0; text-align: center'>"
|
||||
dat += "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />"
|
||||
dat += "</div>"
|
||||
|
||||
var/datum/browser/popup = new(M, "pdaphoto", "PDA Photo", picture.psize_x, picture.psize_y)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
onclose(M, "pdaphoto")
|
||||
|
||||
/datum/data_rc_msg
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
totaltraffic += traffic // add current traffic to total traffic
|
||||
|
||||
// Delete particularly old logs
|
||||
if (log_entries.len >= 400)
|
||||
if(LAZYLEN(log_entries) >= 400) //[list].len is not safe
|
||||
log_entries.Cut(1, 2)
|
||||
|
||||
var/datum/comm_log_entry/log = new
|
||||
|
||||
@@ -117,9 +117,9 @@ GLOBAL_LIST_EMPTY(telecomms_list)
|
||||
icon_state = "[initial(icon_state)]_off"
|
||||
|
||||
/obj/machinery/telecomms/proc/update_power()
|
||||
|
||||
if(toggled)
|
||||
if(stat & (BROKEN|NOPOWER|EMPED)) // if powered, on. if not powered, off. if too damaged, off
|
||||
// if powered, on. if not powered, off. if too damaged, off
|
||||
if(CHECK_BITFIELD(stat, (BROKEN | NOPOWER | EMPED)))
|
||||
on = FALSE
|
||||
else
|
||||
on = TRUE
|
||||
@@ -137,11 +137,11 @@ GLOBAL_LIST_EMPTY(telecomms_list)
|
||||
|
||||
/obj/machinery/telecomms/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
if(CHECK_BITFIELD(., EMP_PROTECT_SELF))
|
||||
return
|
||||
if(prob(100/severity))
|
||||
if(!(stat & EMPED))
|
||||
stat |= EMPED
|
||||
var/duration = (300 * 10)/severity
|
||||
if(prob(100 / severity))
|
||||
if(!CHECK_BITFIELD(stat, EMPED))
|
||||
ENABLE_BITFIELD(stat, EMPED)
|
||||
var/duration = (300 * 10) / severity
|
||||
spawn(rand(duration - 20, duration + 20)) // Takes a long time for the machines to reboot.
|
||||
stat &= ~EMPED
|
||||
DISABLE_BITFIELD(stat, EMPED)
|
||||
|
||||
@@ -5,44 +5,42 @@
|
||||
var/base_icon
|
||||
var/looky_helpy = TRUE
|
||||
|
||||
/datum/component/construction/mecha/examine(mob/user)
|
||||
/datum/component/construction/mecha/examine(datum/source, mob/user, list/examine_list)
|
||||
. = ..()
|
||||
if(looky_helpy)
|
||||
switch(steps[index]["key"])
|
||||
if(TOOL_WRENCH)
|
||||
. += "<span class='notice'>The mech could be <b>wrenched</b> into place.</span>"
|
||||
examine_list += "<span class='notice'>The mech could be <b>wrenched</b> into place.</span>"
|
||||
if(TOOL_SCREWDRIVER)
|
||||
. += "<span class='notice'>The mech could be <b>screwed</b> into place.</span>"
|
||||
examine_list += "<span class='notice'>The mech could be <b>screwed</b> into place.</span>"
|
||||
if(TOOL_WIRECUTTER)
|
||||
. += "<span class='notice'>The mech wires could be <b>trimmed</b> into place.</span>"
|
||||
examine_list += "<span class='notice'>The mech wires could be <b>trimmed</b> into place.</span>"
|
||||
if(/obj/item/stack/cable_coil)
|
||||
. += "<span class='notice'>The mech could use some <b>wiring</b>.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use some <b>wiring</b>.</span>"
|
||||
if(/obj/item/circuitboard)
|
||||
. += "<span class='notice'>The mech could use a type of<b>circuitboard</b>.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use a type of<b>circuitboard</b>.</span>"
|
||||
if(/obj/item/stock_parts/scanning_module)
|
||||
. += "<span class='notice'>The mech could use a <b>scanning stock part</b>.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use a <b>scanning stock part</b>.</span>"
|
||||
if(/obj/item/stock_parts/capacitor)
|
||||
. += "<span class='notice'>The mech could use a <b>power based stock part</b>.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use a <b>power based stock part</b>.</span>"
|
||||
if(/obj/item/stock_parts/cell)
|
||||
. += "<span class='notice'>The mech could use a <b>power source</b>.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use a <b>power source</b>.</span>"
|
||||
if(/obj/item/stack/sheet/metal)
|
||||
. += "<span class='notice'>The mech could use some <b>sheets of metal</b>.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use some <b>sheets of metal</b>.</span>"
|
||||
if(/obj/item/stack/sheet/plasteel)
|
||||
. += "<span class='notice'>The mech could use some <b>sheets of strong steel</b>.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use some <b>sheets of strong steel</b>.</span>"
|
||||
if(/obj/item/bikehorn)
|
||||
. += "<span class='notice'>HONK IT!.</span>"
|
||||
examine_list += "<span class='notice'>HONK IT!.</span>"
|
||||
if(/obj/item/clothing/mask/gas/clown_hat)
|
||||
. += "<span class='notice'>GIVE IT CLOWN MAKEUP HONK!.</span>"
|
||||
examine_list += "<span class='notice'>GIVE IT CLOWN MAKEUP HONK!.</span>"
|
||||
if(/obj/item/clothing/shoes/clown_shoes)
|
||||
. += "<span class='notice'>GIVE IT GOOFY SHOES HONK HONK!.</span>"
|
||||
examine_list += "<span class='notice'>GIVE IT GOOFY SHOES HONK HONK!.</span>"
|
||||
if(/obj/item/mecha_parts/part)
|
||||
. += "<span class='notice'>The mech could use a mech <b>part</b>.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use a mech <b>part</b>.</span>"
|
||||
if(/obj/item/stack/ore/bluespace_crystal)
|
||||
. += "<span class='notice'>The mech could use a <b>crystal</b> of sorts.</span>"
|
||||
examine_list += "<span class='notice'>The mech could use a <b>crystal</b> of sorts.</span>"
|
||||
if(/obj/item/assembly/signaler/anomaly)
|
||||
. += "<span class='notice'>The mech could use a <b>anomaly</b> of sorts.</span>"
|
||||
else
|
||||
return
|
||||
examine_list += "<span class='notice'>The mech could use a <b>anomaly</b> of sorts.</span>"
|
||||
|
||||
/datum/component/construction/mecha/spawn_result()
|
||||
if(!result)
|
||||
|
||||
@@ -284,7 +284,7 @@
|
||||
|
||||
/obj/mecha/attacked_by(obj/item/I, mob/living/user)
|
||||
mecha_log_message("Attacked by [I]. Attacker - [user]")
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/mecha/proc/mech_toxin_damage(mob/living/target)
|
||||
playsound(src, 'sound/effects/spray2.ogg', 50, 1)
|
||||
|
||||
@@ -46,4 +46,4 @@
|
||||
var/turf/T = loc
|
||||
if(!istype(T)) //you know this will happen somehow
|
||||
CRASH("Turf decal initialized in an object/nullspace")
|
||||
T.AddComponent(/datum/component/decal, icon, icon_state, dir, CLEAN_GOD, color, null, null, alpha)
|
||||
T.AddElement(/datum/element/decal, icon, icon_state, turn(dir, -dir2angle(T.dir)), CLEAN_GOD, color, null, null, alpha)
|
||||
|
||||
@@ -95,6 +95,56 @@
|
||||
icon_state = "warden_gaze"
|
||||
duration = 3
|
||||
|
||||
/obj/effect/temp_visual/ratvar/volt_hit
|
||||
name = "volt blast"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
duration = 8
|
||||
icon_state = "volt_hit"
|
||||
light_range = 1.5
|
||||
light_power = 2
|
||||
light_color = LIGHT_COLOR_ORANGE
|
||||
var/mob/user
|
||||
var/damage = 20
|
||||
|
||||
/obj/effect/temp_visual/ratvar/volt_hit/Initialize(mapload, caster)
|
||||
. = ..()
|
||||
user = caster
|
||||
if(user)
|
||||
var/matrix/M = new
|
||||
M.Turn(Get_Angle(src, user))
|
||||
transform = M
|
||||
INVOKE_ASYNC(src, .proc/volthit)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/volt_hit/proc/volthit()
|
||||
if(user)
|
||||
Beam(get_turf(user), "volt_ray", time=duration, maxdistance=8, beam_type=/obj/effect/ebeam/volt_ray)
|
||||
var/hit_amount = 0
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/mob/living/L in T)
|
||||
if(is_servant_of_ratvar(L))
|
||||
continue
|
||||
var/obj/item/I = L.anti_magic_check()
|
||||
if(I)
|
||||
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
|
||||
continue
|
||||
L.visible_message("<span class='warning'>[L] is struck by a [name]!</span>", "<span class='userdanger'>You're struck by a [name]!</span>")
|
||||
L.apply_damage(damage, BURN, "chest", L.run_armor_check("chest", "laser", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 0, "Your armor was penetrated by [src]!"))
|
||||
log_combat(user, L, "struck with a volt blast")
|
||||
hit_amount++
|
||||
for(var/obj/mecha/M in T)
|
||||
if(M.occupant)
|
||||
if(is_servant_of_ratvar(M.occupant))
|
||||
continue
|
||||
to_chat(M.occupant, "<span class='userdanger'>Your [M.name] is struck by a [name]!</span>")
|
||||
M.visible_message("<span class='warning'>[M] is struck by a [name]!</span>")
|
||||
M.take_damage(damage, BURN, 0, 0)
|
||||
hit_amount++
|
||||
if(hit_amount)
|
||||
playsound(src, 'sound/machines/defib_zap.ogg', damage*hit_amount, 1, -1)
|
||||
else
|
||||
playsound(src, "sparks", 50, 1)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/ocular_warden/Initialize()
|
||||
. = ..()
|
||||
pixel_x = rand(-8, 8)
|
||||
|
||||
@@ -55,6 +55,15 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
/// How long, in deciseconds, this staggers for, if null it will autocalculate from w_class and force. Unlike total mass this supports 0 and negatives.
|
||||
var/stagger_force
|
||||
|
||||
/**
|
||||
* Set FALSE and then checked at the end of on mob/living/attackby(), set TRUE on living/pre_attacked_by().
|
||||
* Should it be FALSE by the end of the item/attack(), that means the item overrode the standard attack behaviour
|
||||
* and the user still needs the delay applied. We can't be using return values since that'll stop afterattack() from being triggered.
|
||||
*/
|
||||
var/attack_delay_done = FALSE
|
||||
///next_move click/attack delay of this item.
|
||||
var/click_delay = CLICK_CD_MELEE
|
||||
|
||||
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
|
||||
pass_flags = PASSTABLE
|
||||
pressure_resistance = 4
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
to_chat(user, "<span class='notice'>You need to get closer!</span>")
|
||||
return
|
||||
if(use_paint(user) && isturf(F))
|
||||
F.AddComponent(/datum/component/decal, 'icons/turf/decals.dmi', stored_decal_total, stored_dir, CLEAN_STRONG, color, null, null, alpha)
|
||||
F.AddElement(/datum/element/decal, 'icons/turf/decals.dmi', stored_decal_total, turn(stored_dir, -dir2angle(F.dir)), CLEAN_STRONG, color, null, null, alpha)
|
||||
|
||||
/obj/item/airlock_painter/decal/attack_self(mob/user)
|
||||
if((ink) && (ink.charges >= 1))
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
. = ..()
|
||||
AddElement(/datum/element/update_icon_blocker)
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(field)
|
||||
field_disconnect(field)
|
||||
..()
|
||||
|
||||
@@ -293,6 +293,10 @@
|
||||
name = "Mining Shuttle (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/mining
|
||||
|
||||
/obj/item/circuitboard/computer/snow_taxi
|
||||
name = "Snow Taxi (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/snow_taxi
|
||||
|
||||
/obj/item/circuitboard/computer/white_ship
|
||||
name = "White Ship (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/white_ship
|
||||
|
||||
@@ -273,6 +273,10 @@
|
||||
light_color = "#37FFF7"
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/melee/transforming/energy/sword/cx/Initialize()
|
||||
icon_state_on = icon_state
|
||||
return ..()
|
||||
|
||||
/obj/item/melee/transforming/energy/sword/cx/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
@@ -290,6 +294,7 @@
|
||||
if(!supress_message_text)
|
||||
to_chat(user, "<span class='notice'>[src] [active ? "is now active":"can now be concealed"].</span>")
|
||||
|
||||
|
||||
/obj/item/melee/transforming/energy/sword/cx/update_overlays()
|
||||
. = ..()
|
||||
var/mutable_appearance/blade_overlay = mutable_appearance(icon, "cxsword_blade")
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = NEEDS_PERMIT | NO_COMBAT_MODE_FORCE_MODIFIER //To avoid ambushing and oneshotting healthy crewmembers on force setting 3.
|
||||
attack_verb = list("whacked", "fisted", "power-punched")
|
||||
force = 20
|
||||
throwforce = 10
|
||||
@@ -13,7 +14,7 @@
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 40)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/click_delay = 1.5
|
||||
click_delay = CLICK_CD_MELEE * 1.5
|
||||
var/fisto_setting = 1
|
||||
var/gasperfist = 3
|
||||
var/obj/item/tank/internals/tank = null //Tank used for the gauntlet's piston-ram.
|
||||
@@ -70,42 +71,46 @@
|
||||
|
||||
|
||||
/obj/item/melee/powerfist/attack(mob/living/target, mob/living/user)
|
||||
if(!tank)
|
||||
to_chat(user, "<span class='warning'>\The [src] can't operate without a source of gas!</span>")
|
||||
return
|
||||
var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting)
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return
|
||||
T.assume_air(gasused)
|
||||
T.air_update_turf()
|
||||
if(!gasused)
|
||||
to_chat(user, "<span class='warning'>\The [src]'s tank is empty!</span>")
|
||||
target.apply_damage((force / 5), BRUTE)
|
||||
playsound(loc, 'sound/weapons/punch1.ogg', 50, 1)
|
||||
target.visible_message("<span class='danger'>[user]'s powerfist lets out a dull thunk as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
|
||||
"<span class='userdanger'>[user]'s punches you!</span>")
|
||||
return
|
||||
if(gasused.total_moles() < gasperfist * fisto_setting)
|
||||
to_chat(user, "<span class='warning'>\The [src]'s piston-ram lets out a weak hiss, it needs more gas!</span>")
|
||||
playsound(loc, 'sound/weapons/punch4.ogg', 50, 1)
|
||||
target.apply_damage((force / 2), BRUTE)
|
||||
target.visible_message("<span class='danger'>[user]'s powerfist lets out a weak hiss as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
|
||||
"<span class='userdanger'>[user]'s punch strikes with force!</span>")
|
||||
return
|
||||
target.apply_damage(force * fisto_setting, BRUTE)
|
||||
target.visible_message("<span class='danger'>[user]'s powerfist lets out a loud hiss as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
|
||||
"<span class='userdanger'>You cry out in pain as [user]'s punch flings you backwards!</span>")
|
||||
new /obj/effect/temp_visual/kinetic_blast(target.loc)
|
||||
playsound(loc, 'sound/weapons/resonator_blast.ogg', 50, 1)
|
||||
playsound(loc, 'sound/weapons/genhit2.ogg', 50, 1)
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
|
||||
return FALSE
|
||||
if(!tank)
|
||||
to_chat(user, "<span class='warning'>\The [src] can't operate without a source of gas!</span>")
|
||||
return FALSE
|
||||
var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting)
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return FALSE
|
||||
var/totalitemdamage = target.pre_attacked_by(src, user)
|
||||
T.assume_air(gasused)
|
||||
T.air_update_turf()
|
||||
if(!gasused)
|
||||
to_chat(user, "<span class='warning'>\The [src]'s tank is empty!</span>")
|
||||
target.apply_damage((totalitemdamage / 5), BRUTE)
|
||||
playsound(loc, 'sound/weapons/punch1.ogg', 50, 1)
|
||||
target.visible_message("<span class='danger'>[user]'s powerfist lets out a dull thunk as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
|
||||
"<span class='userdanger'>[user]'s punches you!</span>")
|
||||
return
|
||||
if(gasused.total_moles() < gasperfist * fisto_setting)
|
||||
to_chat(user, "<span class='warning'>\The [src]'s piston-ram lets out a weak hiss, it needs more gas!</span>")
|
||||
playsound(loc, 'sound/weapons/punch4.ogg', 50, 1)
|
||||
target.apply_damage((totalitemdamage / 2), BRUTE)
|
||||
target.visible_message("<span class='danger'>[user]'s powerfist lets out a weak hiss as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
|
||||
"<span class='userdanger'>[user]'s punch strikes with force!</span>")
|
||||
return
|
||||
target.apply_damage(totalitemdamage * fisto_setting, BRUTE)
|
||||
target.visible_message("<span class='danger'>[user]'s powerfist lets out a loud hiss as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
|
||||
"<span class='userdanger'>You cry out in pain as [user]'s punch flings you backwards!</span>")
|
||||
new /obj/effect/temp_visual/kinetic_blast(target.loc)
|
||||
playsound(loc, 'sound/weapons/resonator_blast.ogg', 50, 1)
|
||||
playsound(loc, 'sound/weapons/genhit2.ogg', 50, 1)
|
||||
|
||||
var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
|
||||
var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
|
||||
target.throw_at(throw_target, 5 * fisto_setting, 0.5 + (fisto_setting / 2))
|
||||
|
||||
target.throw_at(throw_target, 5 * fisto_setting, 0.5 + (fisto_setting / 2))
|
||||
log_combat(user, target, "power fisted", src)
|
||||
|
||||
log_combat(user, target, "power fisted", src)
|
||||
|
||||
user.changeNext_move(CLICK_CD_MELEE * click_delay)
|
||||
|
||||
return
|
||||
var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT)
|
||||
if(weight)
|
||||
user.adjustStaminaLossBuffered(weight)
|
||||
return TRUE
|
||||
|
||||
@@ -215,8 +215,9 @@
|
||||
/obj/item/clothing/head/helmet/plate/crusader/prophet
|
||||
name = "Prophet's Hat"
|
||||
desc = "A religious-looking hat."
|
||||
icon_state = "prophet"
|
||||
mob_overlay_icon = 'icons/mob/large-worn-icons/64x64/head.dmi'
|
||||
flags_1 = 0
|
||||
flags_1 = NONE
|
||||
armor = list("melee" = 60, "bullet" = 60, "laser" = 60, "energy" = 50, "bomb" = 70, "bio" = 50, "rad" = 50, "fire" = 60, "acid" = 60) //religion protects you from disease and radiation, honk.
|
||||
worn_x_dimension = 64
|
||||
worn_y_dimension = 64
|
||||
|
||||
@@ -382,14 +382,14 @@
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "bag"
|
||||
desc = "A bag for storing pills, patches, and bottles."
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_POCKET
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/storage/bag/chemistry/ComponentInitialize()
|
||||
. = ..()
|
||||
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
|
||||
STR.max_combined_w_class = 200
|
||||
STR.max_items = 50
|
||||
STR.storage_flags = STORAGE_FLAGS_VOLUME_DEFAULT
|
||||
STR.max_volume = STORAGE_VOLUME_CHEMISTRY_BAG
|
||||
STR.insert_preposition = "in"
|
||||
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart))
|
||||
|
||||
@@ -402,7 +402,7 @@
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "biobag"
|
||||
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_POCKET
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/storage/bag/bio/ComponentInitialize()
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
. = ..()
|
||||
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
|
||||
STR.storage_flags = STORAGE_FLAGS_VOLUME_DEFAULT
|
||||
STR.max_volume = 14
|
||||
STR.max_volume = STORAGE_VOLUME_PILL_BOTTLE
|
||||
STR.allow_quick_gather = TRUE
|
||||
STR.click_gather = TRUE
|
||||
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice))
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
name = "\improper X-01 Multiphase energy gun box"
|
||||
desc = "A storage case for a high-tech energy firearm."
|
||||
|
||||
/obj/item/storage/secure/briefcase/mws_pack_hos/PopulateContents()
|
||||
/obj/item/storage/secure/briefcase/hos/multiphase_box/PopulateContents()
|
||||
new /obj/item/gun/energy/e_gun/hos(src)
|
||||
|
||||
// -----------------------------
|
||||
@@ -212,4 +212,4 @@
|
||||
return attack_self(user)
|
||||
|
||||
/obj/item/storage/secure/safe/HoS
|
||||
name = "head of security's safe"
|
||||
name = "head of security's safe"
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user)
|
||||
var/interrupt = common_baton_melee(M, user, FALSE)
|
||||
if(!interrupt)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/item/melee/baton/alt_pre_attack(atom/A, mob/living/user, params)
|
||||
. = common_baton_melee(A, user, TRUE) //return true (attackchain interrupt) if this also returns true. no harm-disarming.
|
||||
@@ -154,7 +154,7 @@
|
||||
if(turned_on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
|
||||
clowning_around(user)
|
||||
if(IS_STAMCRIT(user)) //CIT CHANGE - makes it impossible to baton in stamina softcrit
|
||||
to_chat(user, "<span class='danger'>You're too exhausted for that.</span>")
|
||||
to_chat(user, "<span class='danger'>You're too exhausted to use [src] properly.</span>")
|
||||
return TRUE
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/L = M
|
||||
|
||||
@@ -93,11 +93,13 @@
|
||||
F.update_icon()
|
||||
else
|
||||
return ..()
|
||||
//Makes empty oxygen tanks spawn without gas
|
||||
/obj/item/tank/internals/plasma/empty/populate_gas()
|
||||
return
|
||||
|
||||
/obj/item/tank/internals/plasma/full/populate_gas()
|
||||
air_contents.gases[/datum/gas/plasma] = (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
|
||||
|
||||
|
||||
/*
|
||||
* Plasmaman Plasma Tank
|
||||
*/
|
||||
@@ -130,6 +132,7 @@
|
||||
air_contents.gases[/datum/gas/plasma] = (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
|
||||
return
|
||||
|
||||
//makes empty plasma tanks spawn without gas.
|
||||
/obj/item/tank/internals/plasmaman/belt/empty/populate_gas()
|
||||
return
|
||||
|
||||
|
||||
@@ -835,11 +835,11 @@
|
||||
|
||||
/obj/item/toy/cards/deck/update_icon_state()
|
||||
switch(cards.len)
|
||||
if(INFINITY to original_size/2)
|
||||
if(original_size*0.5 to INFINITY)
|
||||
icon_state = "deck_[deckstyle]_full"
|
||||
if(original_size/2 to original_size/4)
|
||||
if(original_size*0.25 to original_size*0.5)
|
||||
icon_state = "deck_[deckstyle]_half"
|
||||
if(original_size/4 to 1)
|
||||
if(1 to original_size*0.25)
|
||||
icon_state = "deck_[deckstyle]_low"
|
||||
else
|
||||
icon_state = "deck_[deckstyle]_empty"
|
||||
|
||||
@@ -582,7 +582,7 @@
|
||||
force_wielded = 18
|
||||
throwforce = 20
|
||||
throw_speed = 4
|
||||
embedding = list("embedded_impact_pain_multiplier" = 3, "embed_chance" = 90)
|
||||
embedding = list("embedded_impact_pain_multiplier" = 1.5, "embed_chance" = 65)
|
||||
armour_penetration = 10
|
||||
custom_materials = list(/datum/material/iron=1150, /datum/material/glass=2075)
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
@@ -667,6 +667,7 @@
|
||||
force_wielded = 19
|
||||
force_unwielded = 11
|
||||
throwforce = 21
|
||||
embedding = getEmbeddingBehavior(embed_chance = 75, embedded_pain_multiplier = 1.5) //plasmaglass spears are sharper
|
||||
icon_prefix = "spearplasma"
|
||||
qdel(tip)
|
||||
var/obj/item/twohanded/spear/S = locate() in parts_list
|
||||
@@ -681,6 +682,7 @@
|
||||
if(G)
|
||||
explosive = G
|
||||
name = "explosive lance"
|
||||
embedding = getEmbeddingBehavior(embed_chance = 0, embedded_pain_multiplier = 1)//elances should not be embeddable
|
||||
desc = "A makeshift spear with [G] attached to it."
|
||||
update_icon()
|
||||
|
||||
@@ -1174,14 +1176,13 @@
|
||||
|
||||
/obj/item/twohanded/electrostaff/attack(mob/living/target, mob/living/user)
|
||||
if(IS_STAMCRIT(user))//CIT CHANGE - makes it impossible to baton in stamina softcrit
|
||||
to_chat(user, "<span class='danger'>You're too exhausted for that.</span>")//CIT CHANGE - ditto
|
||||
to_chat(user, "<span class='danger'>You're too exhausted to use [src] properly.</span>")//CIT CHANGE - ditto
|
||||
return //CIT CHANGE - ditto
|
||||
if(on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
|
||||
clowning_around(user) //ouch!
|
||||
return
|
||||
if(iscyborg(target))
|
||||
..()
|
||||
return
|
||||
return ..()
|
||||
if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; run_block() handles that
|
||||
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
return FALSE
|
||||
|
||||
@@ -675,7 +675,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
to_chat(user, "<span class='warning'>You easily land a critical blow on the [target].</span>")
|
||||
if(istype(target, /mob/living/))
|
||||
var/mob/living/bug = target
|
||||
bug.adjustBruteLoss(-35) //What kinda mad man would go into melee with a spider?!
|
||||
bug.adjustBruteLoss(35) //What kinda mad man would go into melee with a spider?!
|
||||
else
|
||||
qdel(target)
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ LINEN BINS
|
||||
return
|
||||
|
||||
/obj/item/bedsheet/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/wirecutters) || I.get_sharpness())
|
||||
if(!(flags_1 & HOLOGRAM_1) && (istype(I, /obj/item/wirecutters) || I.get_sharpness()))
|
||||
var/obj/item/stack/sheet/cloth/C = new (get_turf(src), 3)
|
||||
transfer_fingerprints_to(C)
|
||||
C.add_fingerprint(user)
|
||||
@@ -369,4 +369,4 @@ LINEN BINS
|
||||
/obj/structure/bedsheetbin/color
|
||||
sheet_types = list(/obj/item/bedsheet, /obj/item/bedsheet/blue, /obj/item/bedsheet/green, /obj/item/bedsheet/orange, \
|
||||
/obj/item/bedsheet/purple, /obj/item/bedsheet/red, /obj/item/bedsheet/yellow, /obj/item/bedsheet/brown, \
|
||||
/obj/item/bedsheet/black)
|
||||
/obj/item/bedsheet/black)
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
new /obj/item/storage/backpack/satchel/leather/withwallet( src )
|
||||
new /obj/item/instrument/piano_synth(src)
|
||||
new /obj/item/radio/headset( src )
|
||||
new /obj/item/clothing/head/colour(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/personal/attackby(obj/item/W, mob/user, params)
|
||||
var/obj/item/card/id/I = W.GetID()
|
||||
|
||||
@@ -694,15 +694,12 @@
|
||||
..()
|
||||
var/suited = !preference_source || preference_source.prefs.jumpsuit_style == PREF_SUIT
|
||||
if (CONFIG_GET(flag/grey_assistants))
|
||||
if(suited)
|
||||
uniform = /obj/item/clothing/under/color/grey
|
||||
else
|
||||
uniform = /obj/item/clothing/under/color/jumpskirt/grey
|
||||
uniform = suited ? /obj/item/clothing/under/color/grey : /obj/item/clothing/under/color/jumpskirt/grey
|
||||
else
|
||||
if(suited)
|
||||
uniform = /obj/item/clothing/under/color/random
|
||||
if(SSevents.holidays && SSevents.holidays[PRIDE_MONTH])
|
||||
uniform = suited ? /obj/item/clothing/under/color/rainbow : /obj/item/clothing/under/color/jumpskirt/rainbow
|
||||
else
|
||||
uniform = /obj/item/clothing/under/color/jumpskirt/random
|
||||
uniform = suited ? /obj/item/clothing/under/color/random : /obj/item/clothing/under/color/jumpskirt/random
|
||||
|
||||
/obj/item/storage/box/syndie_kit/chameleon/ghostcafe
|
||||
name = "ghost cafe costuming kit"
|
||||
|
||||
@@ -185,3 +185,16 @@
|
||||
desc = "A wall made out of a strange metal. The squares on it pulse in a predictable pattern."
|
||||
icon = 'icons/turf/walls/hierophant_wall.dmi'
|
||||
icon_state = "wall"
|
||||
|
||||
/turf/closed/indestructible/rock/glacierrock
|
||||
name = "unaturally hard ice wall"
|
||||
desc = "Ice, hardened over thousands of years, you're not breaking through this."
|
||||
icon = 'icons/turf/walls.dmi'
|
||||
icon_state = "snow_rock"
|
||||
|
||||
/turf/closed/indestructible/rock/glacierrock/blue
|
||||
name = "blue ice wall"
|
||||
desc = "The incredible compressive forces that formed this sturdy ice wall gave it a blue color."
|
||||
icon = 'icons/turf/walls.dmi'
|
||||
icon_state = "ice"
|
||||
canSmoothWith = list(/turf/closed/indestructible/rock/glacierrock/blue)
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
planetary_atmos = TRUE
|
||||
floor_tile = null
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
slowdown = 2
|
||||
slowdown = 1.5 //So digging it out paths are usefull.
|
||||
bullet_sizzle = TRUE
|
||||
footstep = FOOTSTEP_SAND
|
||||
barefootstep = FOOTSTEP_SAND
|
||||
|
||||
@@ -146,95 +146,3 @@
|
||||
|
||||
/turf/open/floor/plasteel/sepia
|
||||
icon_state = "sepia"
|
||||
|
||||
///////////////////////////////
|
||||
// Pre-Applied Decal Floors //
|
||||
//////////////////////////////
|
||||
|
||||
// Neutral
|
||||
/turf/open/floor/plasteel/neutral
|
||||
icon_state = "neutral_full"
|
||||
/turf/open/floor/plasteel/neutral/side
|
||||
icon_state = "neutral"
|
||||
/turf/open/floor/plasteel/neutral/corner
|
||||
icon_state = "neutral_corner"
|
||||
|
||||
// Dark Neutral
|
||||
/turf/open/floor/plasteel/dark/neutral
|
||||
icon_state = "dark_neutral_full"
|
||||
/turf/open/floor/plasteel/dark/neutral/checker
|
||||
icon_state = "dark_neutral_checker"
|
||||
/turf/open/floor/plasteel/dark/neutral/side
|
||||
icon_state = "dark_neutral"
|
||||
/turf/open/floor/plasteel/dark/neutral/corner
|
||||
icon_state = "dark_neutral_corner"
|
||||
|
||||
// Dark Security
|
||||
/turf/open/floor/plasteel/dark/security
|
||||
icon_state = "dark_red_full"
|
||||
/turf/open/floor/plasteel/dark/security/checker
|
||||
icon_state = "dark_red_checker"
|
||||
/turf/open/floor/plasteel/dark/security/side
|
||||
icon_state = "dark_red"
|
||||
/turf/open/floor/plasteel/dark/security/corner
|
||||
icon_state = "dark_red_corner"
|
||||
|
||||
// Engineering
|
||||
/turf/open/floor/plasteel/engineering
|
||||
icon_state = "engineering_full"
|
||||
/turf/open/floor/plasteel/engineering/side
|
||||
icon_state = "engineering"
|
||||
/turf/open/floor/plasteel/engineering/corner
|
||||
icon_state = "engineering_corner"
|
||||
|
||||
// Atmospherics
|
||||
/turf/open/floor/plasteel/atmospherics
|
||||
icon_state = "atmospherics_full"
|
||||
/turf/open/floor/plasteel/atmospherics/side
|
||||
icon_state = "atmospherics"
|
||||
/turf/open/floor/plasteel/atmospherics/corner
|
||||
icon_state = "atmospherics_corner"
|
||||
|
||||
// Command
|
||||
/turf/open/floor/plasteel/command
|
||||
icon_state = "command_full"
|
||||
/turf/open/floor/plasteel/command/side
|
||||
icon_state = "command"
|
||||
/turf/open/floor/plasteel/command/corner
|
||||
icon_state = "command_corner"
|
||||
|
||||
// Medical
|
||||
/turf/open/floor/plasteel/medical
|
||||
icon_state = "medical_full"
|
||||
/turf/open/floor/plasteel/medical/alt
|
||||
icon_state = "medical_alt"
|
||||
/turf/open/floor/plasteel/medical/side
|
||||
icon_state = "medical"
|
||||
/turf/open/floor/plasteel/medical/corner
|
||||
icon_state = "medical_corner"
|
||||
|
||||
// Security
|
||||
/turf/open/floor/plasteel/security
|
||||
icon_state = "security_full"
|
||||
/turf/open/floor/plasteel/security/side
|
||||
icon_state = "security"
|
||||
/turf/open/floor/plasteel/security/corner
|
||||
icon_state = "security_corner"
|
||||
|
||||
// Cargo
|
||||
/turf/open/floor/plasteel/cargo
|
||||
icon_state = "cargo_full"
|
||||
/turf/open/floor/plasteel/cargo/side
|
||||
icon_state = "cargo"
|
||||
/turf/open/floor/plasteel/cargo/corner
|
||||
icon_state = "cargo_corner"
|
||||
|
||||
// Misc
|
||||
/turf/open/floor/plasteel/showroomfloor/shower
|
||||
icon_state = "shower"
|
||||
/turf/open/floor/plasteel/goonplaque/alien
|
||||
icon_state = "plaque1"
|
||||
desc = "\"This is a plaque is a collaboration of iconography celebrating the peaceful collaboration between the people of Earth and distant alien species."
|
||||
/turf/open/floor/plasteel/goonplaque/charter
|
||||
icon_state = "plaque2"
|
||||
desc = "\"A golden plaque. Etched into it is the introductory article for a cross-species interplanetary constitution, guaranteeing equal rights between species that Nanotrasen relunctantly agreed to."
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
|
||||
/// Get displayed variable in VV variable list
|
||||
/proc/debug_variable(name, value, level, datum/D, sanitize = TRUE) //if D is a list, name will be index, and value will be assoc value.
|
||||
var/header
|
||||
if(D)
|
||||
@@ -35,6 +36,19 @@
|
||||
else if (isfile(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
|
||||
|
||||
else if(istype(value, /matrix)) // Needs to be before datum
|
||||
var/matrix/M = value
|
||||
item = {"[VV_HTML_ENCODE(name)] = <span class='value'>
|
||||
<table class='matrixbrak'><tbody><tr>
|
||||
<td class='lbrak'> </td>
|
||||
<td><table class='matrix'><tbody>
|
||||
<tr><td>[M.a]</td><td>[M.d]</td><td>0</td></tr>
|
||||
<tr><td>[M.b]</td><td>[M.e]</td><td>0</td></tr>
|
||||
<tr><td>[M.c]</td><td>[M.f]</td><td>1</td></tr>
|
||||
</tbody></table></td>
|
||||
<td class='rbrak'> </td>
|
||||
</tr></tbody></table></span>"} //TODO link to modify_transform wrapper for all matrices
|
||||
|
||||
else if (istype(value, /datum))
|
||||
var/datum/DV = value
|
||||
if ("[DV]" != "[DV.type]") //if the thing as a name var, lets use it.
|
||||
|
||||
@@ -96,16 +96,7 @@
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
|
||||
<title>[title]</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Verdana, sans-serif;
|
||||
font-size: 9pt;
|
||||
}
|
||||
.value {
|
||||
font-family: "Courier New", monospace;
|
||||
font-size: 8pt;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="view_variables.css">
|
||||
</head>
|
||||
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
B.organ_flags |= ORGAN_VITAL
|
||||
B.decoy_override = FALSE
|
||||
remove_changeling_powers()
|
||||
owner.special_role = null
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/changeling/proc/remove_clownmut()
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
/atom/movable/proc/power_drain(clockcult_user)
|
||||
/atom/movable/proc/power_drain(clockcult_user, drain_weapons = FALSE) //This proc as of now is only in use for void volt
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user)
|
||||
return 0
|
||||
return 0 //Returns 0 instead of FALSE to symbolise it returning the power amount in other cases, not TRUE aka 1
|
||||
|
||||
/obj/item/melee/baton/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
/obj/item/melee/baton/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
/obj/item/gun/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(!cell)
|
||||
return 0
|
||||
if(cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4) //Done snowflakey because guns have far smaller cells than batons / other equipment
|
||||
cell.use(.)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user)
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(cell && cell.charge)
|
||||
playsound(src, "sparks", 50, 1)
|
||||
flick("apc-spark", src)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*3)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.) //Better than a power sink!
|
||||
if(!cell.charge && !shorted)
|
||||
shorted = 1
|
||||
@@ -23,9 +33,9 @@
|
||||
update()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user)
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*3)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*4)
|
||||
charge -= . * 50
|
||||
if(!charge && !panel_open)
|
||||
panel_open = TRUE
|
||||
@@ -34,19 +44,19 @@
|
||||
visible_message("<span class='warning'>[src]'s panel flies open with a flurry of sparks!</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user)
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*3)
|
||||
charge = use(.)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER * 4) //Done like this because normal cells are usually quite a bit bigger than the ones used in guns / APCs
|
||||
use(min(charge, . * 10)) //Usually cell-powered equipment that is not a gun has at least ten times the capacity of a gun / 5 times the amount of an APC. This adjusts the drain to account for that.
|
||||
update_icon()
|
||||
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user)
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
|
||||
/obj/mecha/power_drain(clockcult_user)
|
||||
/obj/mecha/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if((!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
|
||||
@@ -135,6 +135,29 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Volt Void scripture, fires a ray of energy at a target location
|
||||
/obj/effect/proc_holder/slab/volt
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/volt/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(target == slab || ..()) //we can't cancel
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
successful = TRUE
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user] fires a ray of energy at [target]!</span>", "<span class='nzcrentr'>You fire a volt ray at [target].</span>")
|
||||
playsound(ranged_ability_user, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
T = get_turf(target)
|
||||
new/obj/effect/temp_visual/ratvar/volt_hit(T, ranged_ability_user)
|
||||
log_combat(ranged_ability_user, T, "fired a volt ray")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Kindle scripture; stuns and mutes a target non-servant.
|
||||
/obj/effect/proc_holder/slab/kindle
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
@@ -203,6 +203,10 @@ Applications: 8 servants, 3 caches, and 100 CV
|
||||
if(!do_after(invoker, chant_interval, target = invoker, extra_checks = CALLBACK(src, .proc/can_recite)))
|
||||
break
|
||||
clockwork_say(invoker, text2ratvar(pick(chant_invocations)), whispered)
|
||||
if(multiple_invokers_used)
|
||||
for(var/mob/living/L in range(1, get_turf(invoker)))
|
||||
if(can_recite_scripture(L) && L != invoker)
|
||||
clockwork_say(L, text2ratvar(pick(chant_invocations)), whispered)
|
||||
if(!chant_effects(i))
|
||||
break
|
||||
if(invoker && slab)
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 5
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Ratvarian shield, which can absorb energy from attacks for use in powerful bashes."
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear. You will need to wait for 30 seconds before resummoning it."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 6
|
||||
sort_priority = 7
|
||||
important = TRUE
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
|
||||
@@ -231,7 +231,7 @@
|
||||
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 7
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
|
||||
|
||||
@@ -263,3 +263,227 @@
|
||||
duration = max(duration, 100)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
|
||||
|
||||
//Mending Mantra: Channeled for up to ten times over twenty seconds to repair structures and heal allies
|
||||
/datum/clockwork_scripture/channeled/mending_mantra
|
||||
descname = "Channeled, Area Healing and Repair"
|
||||
name = "Mending Mantra"
|
||||
desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed. Channeled every two seconds for a maximum of twenty seconds."
|
||||
chant_invocations = list("Mend our dents!", "Heal our scratches!", "Repair our gears!")
|
||||
chant_amount = 10
|
||||
chant_interval = 20
|
||||
power_cost = 400
|
||||
usage_tip = "This is a very effective way to rapidly reinforce a base after an attack."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 8
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed.<br><b>Maximum 10 chants.</b>"
|
||||
var/heal_attempts = 4
|
||||
var/heal_amount = 2.5
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
|
||||
var/static/list/heal_finish_messages = list("There, all mended!", "Try not to get too damaged.", "No more dents and scratches for you!", "Champions never die.", "All patched up.", \
|
||||
"Ah, child, it's okay now.", "Pain is temporary.", "What you do for the Justiciar is eternal.", "Bear this for me.", "Be strong, child.", "Please, be careful!", \
|
||||
"If you die, you will be remembered.")
|
||||
var/static/list/heal_target_typecache = typecacheof(list(
|
||||
/obj/structure/destructible/clockwork,
|
||||
/obj/machinery/door/airlock/clockwork,
|
||||
/obj/machinery/door/window/clockwork,
|
||||
/obj/structure/window/reinforced/clockwork,
|
||||
/obj/structure/table/reinforced/brass))
|
||||
var/static/list/ratvarian_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/armor/clockwork,
|
||||
/obj/item/clothing/head/helmet/clockwork,
|
||||
/obj/item/clothing/gloves/clockwork,
|
||||
/obj/item/clothing/shoes/clockwork))
|
||||
|
||||
/datum/clockwork_scripture/channeled/mending_mantra/chant_effects(chant_number)
|
||||
var/turf/T
|
||||
for(var/atom/movable/M in range(7, invoker))
|
||||
if(isliving(M))
|
||||
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
|
||||
var/mob/living/simple_animal/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD)
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
S.adjustHealth(-heal_amount)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_attempts && S.health >= S.maxHealth) //we finished healing on the last tick, give them the message
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(issilicon(M))
|
||||
var/mob/living/silicon/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
S.heal_ordered_damage(heal_amount, damage_heal_order)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_attempts && S.health >= S.maxHealth)
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.health == H.maxHealth || H.stat == DEAD || !is_servant_of_ratvar(H))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
var/heal_ticks = 0 //one heal tick for each piece of ratvarian armor worn
|
||||
var/obj/item/I = H.get_item_by_slot(SLOT_WEAR_SUIT)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_HEAD)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_GLOVES)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_SHOES)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
if(heal_ticks)
|
||||
for(var/i in 1 to heal_ticks)
|
||||
if(H.health < H.maxHealth)
|
||||
H.heal_ordered_damage(heal_amount, damage_heal_order)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_ticks && H.health >= H.maxHealth)
|
||||
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(is_type_in_typecache(M, heal_target_typecache))
|
||||
var/obj/structure/destructible/clockwork/C = M
|
||||
if(C.obj_integrity == C.max_integrity || (istype(C) && !C.can_be_repaired))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(C.obj_integrity < C.max_integrity)
|
||||
C.obj_integrity = min(C.obj_integrity + 5, C.max_integrity)
|
||||
C.update_icon()
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
else
|
||||
break
|
||||
new /obj/effect/temp_visual/ratvar/mending_mantra(get_turf(invoker))
|
||||
return TRUE
|
||||
|
||||
//Volt Blaster: Channeled for up to five times over ten seconds to fire up to five rays of energy at target locations.
|
||||
/datum/clockwork_scripture/channeled/volt_blaster
|
||||
descname = "Channeled, Targeted Energy Blasts"
|
||||
name = "Volt Blaster"
|
||||
desc = "Allows you to fire five energy rays at target locations. Channeled every fourth of a second for a maximum of ten seconds."
|
||||
channel_time = 30
|
||||
invocations = list("Amperage...", "...grant me your power!")
|
||||
chant_invocations = list("Use charge to kill!", "Slay with power!", "Hunt with energy!")
|
||||
chant_amount = 5
|
||||
chant_interval = 4
|
||||
power_cost = 500
|
||||
usage_tip = "Though it requires you to stand still, this scripture can do massive damage."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to fire energy rays at target locations.<br><b>Maximum 5 chants.</b>"
|
||||
var/static/list/nzcrentr_insults = list("You're not very good at aiming.", "You hunt badly.", "What a waste of energy.", "Almost funny to watch.",
|
||||
"Boss says </span><span class='heavy_brass'>\"Click something, you idiot!\"</span><span class='nzcrentr'>.", "Stop wasting power if you can't aim.")
|
||||
|
||||
/datum/clockwork_scripture/channeled/volt_blaster/chant_effects(chant_number)
|
||||
slab.busy = null
|
||||
var/datum/clockwork_scripture/ranged_ability/volt_ray/ray = new
|
||||
ray.slab = slab
|
||||
ray.invoker = invoker
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!ray.run_scripture() && slab && invoker)
|
||||
if(can_recite() && T == get_turf(invoker))
|
||||
to_chat(invoker, "<span class='nzcrentr'>\"[text2ratvar(pick(nzcrentr_insults))]\"</span>")
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/ebeam/volt_ray
|
||||
name = "volt_ray"
|
||||
layer = LYING_MOB_LAYER
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/volt_ray
|
||||
name = "Volt Ray"
|
||||
slab_overlay = "volt"
|
||||
allow_mobility = FALSE
|
||||
ranged_type = /obj/effect/proc_holder/slab/volt
|
||||
ranged_message = "<span class='nzcrentr_small'><i>You charge the clockwork slab with shocking might.</i>\n\
|
||||
<b>Left-click a target to fire, quickly!</b></span>"
|
||||
timeout_time = 20
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt
|
||||
descname = "Channeled, Power Drain"
|
||||
name = "Void Volt"
|
||||
desc = "A channeled spell that quickly drains any powercells in a radius of eight tiles, but burns the invoker. \
|
||||
Can be channeled with more cultists to increase range and split the caused damage evenly over all invokers. \
|
||||
Also charges clockwork power by a small percentage of the drained power amount, which can help offset this scriptures powercost."
|
||||
invocations = list("Channel their energy through my body... ", "... so it may fuel Engine!")
|
||||
chant_invocations = list("Make their lights fall dark!", "They shall be powerless!", "Rob them of their power!")
|
||||
chant_amount = 20
|
||||
chant_interval = 10 //100KW drain per pulse for guns / APCs / 1MW for other cells = 10 chants / 100ds / 10s to drain a charged weapon or a baton with a nonupgraded cell
|
||||
channel_time = 50
|
||||
power_cost = 300
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
usage_tip = "It may be useful to end channelling early if the burning becomes too much to handle.."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Quickly drains power in an area around the invoker, causing burns proportional to the amount of energy drained.<br><b>Maximum of 20 chants.</b>"
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/scripture_effects()
|
||||
invoker.visible_message("<span class='warning'>[invoker] glows in a brilliant golden light!</span>")
|
||||
invoker.add_atom_colour("#FFD700", ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 2
|
||||
invoker.light_range = 4
|
||||
invoker.light_color = LIGHT_COLOR_FIRE
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_effects(chant_number)
|
||||
var/power_drained = 0
|
||||
var/power_mod = 0.005 //Amount of power drained (generally) is multiplied with this, and subsequently dealt in damage to the invoker, then 15 times that is added to the clockwork cult's power reserves.
|
||||
var/drain_range = 8
|
||||
var/additional_chanters = 0
|
||||
var/list/chanters = list()
|
||||
chanters += invoker
|
||||
for(var/mob/living/L in range(1, invoker))
|
||||
if(!L.stat && is_servant_of_ratvar(L))
|
||||
additional_chanters++
|
||||
chanters += L
|
||||
drain_range = min(drain_range + 2 * additional_chanters, drain_range * 2) //s u c c
|
||||
for(var/t in spiral_range_turfs(drain_range, invoker))
|
||||
var/turf/T = t
|
||||
for(var/M in T)
|
||||
var/atom/movable/A = M
|
||||
power_drained += A.power_drain(TRUE, TRUE) //Yes, this absolutely does drain weaponry. 10 pulses to drain guns / batons, though of course they can just be recharged.
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(invoker.loc, 1 + (power_drained * power_mod))
|
||||
var/datum/effect_system/spark_spread/S = new
|
||||
S.set_up(round(1 + (power_drained * power_mod), 1), 0, get_turf(invoker))
|
||||
S.start()
|
||||
adjust_clockwork_power(power_drained * power_mod * 15)
|
||||
for(var/mob/living/L in chanters)
|
||||
L.adjustFireLoss(round(clamp(power_drained * power_mod / (1 + additional_chanters), 0, 20), 0.1)) //No you won't just immediately melt if you do this in a very power-rich area
|
||||
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_end_effects()
|
||||
invoker.visible_message("<span class='warning'>[invoker] stops glowing...</span>")
|
||||
invoker.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 0
|
||||
invoker.light_range = 0
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "disintegrate"
|
||||
item_state = null
|
||||
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL | NO_ATTACK_CHAIN_SOFT_STAMCRIT
|
||||
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL
|
||||
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
throwforce = 0
|
||||
|
||||
@@ -118,22 +118,10 @@
|
||||
|
||||
|
||||
/mob/living/carbon/true_devil/attacked_by(obj/item/I, mob/living/user, def_zone)
|
||||
var/weakness = check_weakness(I, user)
|
||||
apply_damage(I.force * weakness, I.damtype, def_zone)
|
||||
var/message_verb = ""
|
||||
if(I.attack_verb && I.attack_verb.len)
|
||||
message_verb = "[pick(I.attack_verb)]"
|
||||
else if(I.force)
|
||||
message_verb = "attacked"
|
||||
|
||||
var/attack_message = "[src] has been [message_verb] with [I]."
|
||||
if(user)
|
||||
user.do_attack_animation(src)
|
||||
if(user in viewers(src, null))
|
||||
attack_message = "[user] has [message_verb] [src] with [I]!"
|
||||
if(message_verb)
|
||||
visible_message("<span class='danger'>[attack_message]</span>",
|
||||
"<span class='userdanger'>[attack_message]</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
var/totitemdamage = pre_attacked_by(I, user)
|
||||
totitemdamage *= check_weakness(I, user)
|
||||
apply_damage(totitemdamage, I.damtype, def_zone)
|
||||
send_item_attack_message(I, user, null, totitemdamage)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/true_devil/singularity_act()
|
||||
|
||||
@@ -171,10 +171,10 @@
|
||||
var/worth = 10
|
||||
var/gases = C.air_contents.gases
|
||||
|
||||
worth += gases[/datum/gas/bz]*4
|
||||
worth += gases[/datum/gas/bz]*3
|
||||
worth += gases[/datum/gas/stimulum]*25
|
||||
worth += gases[/datum/gas/hypernoblium]*1000
|
||||
worth += gases[/datum/gas/miasma]*4
|
||||
worth += gases[/datum/gas/miasma]*2
|
||||
worth += gases[/datum/gas/tritium]*7
|
||||
worth += gases[/datum/gas/pluoxium]*6
|
||||
worth += gases[/datum/gas/nitryl]*30
|
||||
|
||||
@@ -66,6 +66,16 @@
|
||||
crate_name = "shaft miner starter kit"
|
||||
crate_type = /obj/structure/closet/crate/secure
|
||||
|
||||
/datum/supply_pack/service/snowmobile
|
||||
name = "Snowmobile kit"
|
||||
desc = "trapped on a frigid wasteland? need to get around fast? purchase a refurbished snowmobile, with a FREE 10 microsecond warranty!"
|
||||
cost = 1500 // 1000 points cheaper than ATV
|
||||
contains = list(/obj/vehicle/ridden/atv/snowmobile = 1,
|
||||
/obj/item/key = 1,
|
||||
/obj/item/clothing/mask/gas/explorer = 1)
|
||||
crate_name = "Snowmobile kit"
|
||||
crate_type = /obj/structure/closet/crate/large
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////// Chef, Botanist, Bartender ////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
|
||||
Make a datum at the bottom of this file with your assets for your thing.
|
||||
The simple subsystem will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
|
||||
You can set verify to TRUE if you want send() to sleep until the client has the assets.
|
||||
*/
|
||||
|
||||
|
||||
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
|
||||
// This is doubled for the first asset, then added per asset after
|
||||
#define ASSET_CACHE_SEND_TIMEOUT 7
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
//When passively preloading assets, how many to send at once? Too high creates noticable lag where as too low can flood the client's cache with "verify" files
|
||||
#define ASSET_CACHE_PRELOAD_CONCURRENT 3
|
||||
|
||||
/client
|
||||
var/list/cache = list() // List of all assets sent to this client by the asset cache.
|
||||
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
|
||||
var/list/sending = list()
|
||||
var/last_asset_job = 0 // Last job done.
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(client/client, asset_name, verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
|
||||
return 0
|
||||
|
||||
client << browse_rsc(SSassets.cache[asset_name], asset_name)
|
||||
if(!verify)
|
||||
client.cache += asset_name
|
||||
return 1
|
||||
|
||||
client.sending |= asset_name
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
stoplag(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= asset_name
|
||||
client.cache |= asset_name
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset_list(client/client, list/asset_list, verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
var/list/unreceived = asset_list - (client.cache + client.sending)
|
||||
if(!unreceived || !unreceived.len)
|
||||
return 0
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "Sending Resources...")
|
||||
for(var/asset in unreceived)
|
||||
if (asset in SSassets.cache)
|
||||
client << browse_rsc(SSassets.cache[asset], asset)
|
||||
|
||||
if(!verify) // Can't access the asset cache browser, rip.
|
||||
client.cache += unreceived
|
||||
return 1
|
||||
|
||||
client.sending |= unreceived
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
stoplag(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= unreceived
|
||||
client.cache |= unreceived
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(client/client, list/files, register_asset = TRUE)
|
||||
var/concurrent_tracker = 1
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file, files[file])
|
||||
if (concurrent_tracker >= ASSET_CACHE_PRELOAD_CONCURRENT)
|
||||
concurrent_tracker = 1
|
||||
send_asset(client, file)
|
||||
else
|
||||
concurrent_tracker++
|
||||
send_asset(client, file, verify=FALSE)
|
||||
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//if it's an icon or something be careful, you'll have to copy it before further use.
|
||||
/proc/register_asset(asset_name, asset)
|
||||
SSassets.cache[asset_name] = asset
|
||||
|
||||
//Generated names do not include file extention.
|
||||
//Used mainly for code that deals with assets in a generic way
|
||||
//The same asset will always lead to the same asset name
|
||||
/proc/generate_asset_name(file)
|
||||
return "asset.[md5(fcopy_rsc(file))]"
|
||||
|
||||
|
||||
//These datums are used to populate the asset cache, the proc "register()" does this.
|
||||
|
||||
//all of our asset datums, used for referring to these later
|
||||
GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
//get an assetdatum or make a new one
|
||||
/proc/get_asset_datum(type)
|
||||
return GLOB.asset_datums[type] || new type()
|
||||
|
||||
/datum/asset
|
||||
var/_abstract = /datum/asset
|
||||
|
||||
/datum/asset/New()
|
||||
GLOB.asset_datums[type] = src
|
||||
register()
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
/datum/asset/proc/send(client)
|
||||
return
|
||||
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
_abstract = /datum/asset/simple
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/simple/send(client)
|
||||
send_asset_list(client,assets,verify)
|
||||
|
||||
|
||||
// For registering or sending multiple others at once
|
||||
/datum/asset/group
|
||||
_abstract = /datum/asset/group
|
||||
var/list/children
|
||||
|
||||
/datum/asset/group/register()
|
||||
for(var/type in children)
|
||||
get_asset_datum(type)
|
||||
|
||||
/datum/asset/group/send(client/C)
|
||||
for(var/type in children)
|
||||
var/datum/asset/A = get_asset_datum(type)
|
||||
A.send(C)
|
||||
|
||||
|
||||
// spritesheet implementation - coalesces various icons into a single .png file
|
||||
// and uses CSS to select icons out of that file - saves on transferring some
|
||||
// 1400-odd individual PNG files
|
||||
#define SPR_SIZE 1
|
||||
#define SPR_IDX 2
|
||||
#define SPRSZ_COUNT 1
|
||||
#define SPRSZ_ICON 2
|
||||
#define SPRSZ_STRIPPED 3
|
||||
|
||||
/datum/asset/spritesheet
|
||||
_abstract = /datum/asset/spritesheet
|
||||
var/name
|
||||
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
|
||||
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/spritesheet/register()
|
||||
if (!name)
|
||||
CRASH("spritesheet [type] cannot register without a name")
|
||||
ensure_stripped()
|
||||
|
||||
var/res_name = "spritesheet_[name].css"
|
||||
var/fname = "data/spritesheets/[res_name]"
|
||||
fdel(fname)
|
||||
text2file(generate_css(), fname)
|
||||
register_asset(res_name, fcopy_rsc(fname))
|
||||
fdel(fname)
|
||||
|
||||
for(var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
|
||||
/datum/asset/spritesheet/send(client/C)
|
||||
if (!name)
|
||||
return
|
||||
var/all = list("spritesheet_[name].css")
|
||||
for(var/size_id in sizes)
|
||||
all += "[name]_[size_id].png"
|
||||
send_asset_list(C, all, verify)
|
||||
|
||||
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
|
||||
for(var/size_id in sizes_to_strip)
|
||||
var/size = sizes[size_id]
|
||||
if (size[SPRSZ_STRIPPED])
|
||||
continue
|
||||
|
||||
// save flattened version
|
||||
var/fname = "data/spritesheets/[name]_[size_id].png"
|
||||
fcopy(size[SPRSZ_ICON], fname)
|
||||
var/error = rustg_dmi_strip_metadata(fname)
|
||||
if(length(error))
|
||||
stack_trace("Failed to strip [name]_[size_id].png: [error]")
|
||||
size[SPRSZ_STRIPPED] = icon(fname)
|
||||
fdel(fname)
|
||||
|
||||
/datum/asset/spritesheet/proc/generate_css()
|
||||
var/list/out = list()
|
||||
|
||||
for (var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
|
||||
|
||||
for (var/sprite_id in sprites)
|
||||
var/sprite = sprites[sprite_id]
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
var/idx = sprite[SPR_IDX]
|
||||
var/size = sizes[size_id]
|
||||
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
var/icon/big = size[SPRSZ_STRIPPED]
|
||||
var/per_line = big.Width() / tiny.Width()
|
||||
var/x = (idx % per_line) * tiny.Width()
|
||||
var/y = round(idx / per_line) * tiny.Height()
|
||||
|
||||
out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
|
||||
|
||||
return out.Join("\n")
|
||||
|
||||
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
||||
I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
|
||||
if (!I || !length(icon_states(I))) // that direction or state doesn't exist
|
||||
return
|
||||
var/size_id = "[I.Width()]x[I.Height()]"
|
||||
var/size = sizes[size_id]
|
||||
|
||||
if (sprites[sprite_name])
|
||||
CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
|
||||
|
||||
if (size)
|
||||
var/position = size[SPRSZ_COUNT]++
|
||||
var/icon/sheet = size[SPRSZ_ICON]
|
||||
size[SPRSZ_STRIPPED] = null
|
||||
sheet.Insert(I, icon_state=sprite_name)
|
||||
sprites[sprite_name] = list(size_id, position)
|
||||
else
|
||||
sizes[size_id] = size = list(1, I, null)
|
||||
sprites[sprite_name] = list(size_id, 0)
|
||||
|
||||
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
|
||||
if (length(prefix))
|
||||
prefix = "[prefix]-"
|
||||
|
||||
if (!directions)
|
||||
directions = list(SOUTH)
|
||||
|
||||
for (var/icon_state_name in icon_states(I))
|
||||
for (var/direction in directions)
|
||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
|
||||
Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
|
||||
|
||||
/datum/asset/spritesheet/proc/css_tag()
|
||||
return {"<link rel="stylesheet" href="spritesheet_[name].css" />"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"<span class="[name][size_id] [sprite_name]"></span>"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"[name][size_id] [sprite_name]"}
|
||||
|
||||
#undef SPR_SIZE
|
||||
#undef SPR_IDX
|
||||
#undef SPRSZ_COUNT
|
||||
#undef SPRSZ_ICON
|
||||
#undef SPRSZ_STRIPPED
|
||||
|
||||
|
||||
/datum/asset/spritesheet/simple
|
||||
_abstract = /datum/asset/spritesheet/simple
|
||||
var/list/assets
|
||||
|
||||
/datum/asset/spritesheet/simple/register()
|
||||
for (var/key in assets)
|
||||
Insert(key, assets[key])
|
||||
..()
|
||||
|
||||
//Generates assets based on iconstates of a single icon
|
||||
/datum/asset/simple/icon_states
|
||||
_abstract = /datum/asset/simple/icon_states
|
||||
var/icon
|
||||
var/list/directions = list(SOUTH)
|
||||
var/frame = 1
|
||||
var/movement_states = FALSE
|
||||
|
||||
var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png"
|
||||
var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format
|
||||
|
||||
verify = FALSE
|
||||
|
||||
/datum/asset/simple/icon_states/register(_icon = icon)
|
||||
for(var/icon_state_name in icon_states(_icon))
|
||||
for(var/direction in directions)
|
||||
var/asset = icon(_icon, icon_state_name, direction, frame, movement_states)
|
||||
if (!asset)
|
||||
continue
|
||||
asset = fcopy_rsc(asset) //dedupe
|
||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
|
||||
var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
|
||||
if (generic_icon_names)
|
||||
asset_name = "[generate_asset_name(asset)].png"
|
||||
|
||||
register_asset(asset_name, asset)
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons
|
||||
_abstract = /datum/asset/simple/icon_states/multiple_icons
|
||||
var/list/icons
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons/register()
|
||||
for(var/i in icons)
|
||||
..(i)
|
||||
|
||||
|
||||
//DEFINITIONS FOR ASSET DATUMS START HERE.
|
||||
|
||||
/datum/asset/simple/tgui
|
||||
assets = list(
|
||||
// tgui
|
||||
"tgui.css" = 'tgui/assets/tgui.css',
|
||||
"tgui.js" = 'tgui/assets/tgui.js',
|
||||
// tgui-next
|
||||
"tgui-main.html" = 'tgui-next/packages/tgui/public/tgui-main.html',
|
||||
"tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html',
|
||||
"tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js',
|
||||
"tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css',
|
||||
"shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js',
|
||||
"shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js',
|
||||
"shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js',
|
||||
"shim-css-om.js" = 'tgui-next/packages/tgui/public/shim-css-om.js',
|
||||
)
|
||||
|
||||
/datum/asset/group/tgui
|
||||
children = list(
|
||||
/datum/asset/simple/tgui,
|
||||
/datum/asset/simple/fontawesome
|
||||
)
|
||||
|
||||
/datum/asset/simple/headers
|
||||
assets = list(
|
||||
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
|
||||
"alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
|
||||
"batt_5.gif" = 'icons/program_icons/batt_5.gif',
|
||||
"batt_20.gif" = 'icons/program_icons/batt_20.gif',
|
||||
"batt_40.gif" = 'icons/program_icons/batt_40.gif',
|
||||
"batt_60.gif" = 'icons/program_icons/batt_60.gif',
|
||||
"batt_80.gif" = 'icons/program_icons/batt_80.gif',
|
||||
"batt_100.gif" = 'icons/program_icons/batt_100.gif',
|
||||
"charging.gif" = 'icons/program_icons/charging.gif',
|
||||
"downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
|
||||
"downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
|
||||
"ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
|
||||
"ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
|
||||
"power_norm.gif" = 'icons/program_icons/power_norm.gif',
|
||||
"power_warn.gif" = 'icons/program_icons/power_warn.gif',
|
||||
"sig_high.gif" = 'icons/program_icons/sig_high.gif',
|
||||
"sig_low.gif" = 'icons/program_icons/sig_low.gif',
|
||||
"sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
|
||||
"sig_none.gif" = 'icons/program_icons/sig_none.gif',
|
||||
"smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
|
||||
"smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
|
||||
"smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
|
||||
"smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
|
||||
"smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
|
||||
"smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
|
||||
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/pda
|
||||
name = "pda"
|
||||
assets = list(
|
||||
"atmos" = 'icons/pda_icons/pda_atmos.png',
|
||||
"back" = 'icons/pda_icons/pda_back.png',
|
||||
"bell" = 'icons/pda_icons/pda_bell.png',
|
||||
"blank" = 'icons/pda_icons/pda_blank.png',
|
||||
"boom" = 'icons/pda_icons/pda_boom.png',
|
||||
"bucket" = 'icons/pda_icons/pda_bucket.png',
|
||||
"medbot" = 'icons/pda_icons/pda_medbot.png',
|
||||
"floorbot" = 'icons/pda_icons/pda_floorbot.png',
|
||||
"cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
|
||||
"crate" = 'icons/pda_icons/pda_crate.png',
|
||||
"cuffs" = 'icons/pda_icons/pda_cuffs.png',
|
||||
"eject" = 'icons/pda_icons/pda_eject.png',
|
||||
"flashlight" = 'icons/pda_icons/pda_flashlight.png',
|
||||
"honk" = 'icons/pda_icons/pda_honk.png',
|
||||
"mail" = 'icons/pda_icons/pda_mail.png',
|
||||
"medical" = 'icons/pda_icons/pda_medical.png',
|
||||
"menu" = 'icons/pda_icons/pda_menu.png',
|
||||
"mule" = 'icons/pda_icons/pda_mule.png',
|
||||
"notes" = 'icons/pda_icons/pda_notes.png',
|
||||
"power" = 'icons/pda_icons/pda_power.png',
|
||||
"rdoor" = 'icons/pda_icons/pda_rdoor.png',
|
||||
"reagent" = 'icons/pda_icons/pda_reagent.png',
|
||||
"refresh" = 'icons/pda_icons/pda_refresh.png',
|
||||
"scanner" = 'icons/pda_icons/pda_scanner.png',
|
||||
"signaler" = 'icons/pda_icons/pda_signaler.png',
|
||||
"status" = 'icons/pda_icons/pda_status.png',
|
||||
"dronephone" = 'icons/pda_icons/pda_dronephone.png',
|
||||
"emoji" = 'icons/pda_icons/pda_emoji.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/paper
|
||||
name = "paper"
|
||||
assets = list(
|
||||
"stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
|
||||
"stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png',
|
||||
"stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png',
|
||||
"stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png',
|
||||
"stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png',
|
||||
"stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png',
|
||||
"stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png',
|
||||
"stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png',
|
||||
"stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
|
||||
"stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
|
||||
"stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/minesweeper
|
||||
name = "minesweeper"
|
||||
assets = list(
|
||||
"1" = 'icons/UI_Icons/minesweeper_tiles/one.png',
|
||||
"2" = 'icons/UI_Icons/minesweeper_tiles/two.png',
|
||||
"3" = 'icons/UI_Icons/minesweeper_tiles/three.png',
|
||||
"4" = 'icons/UI_Icons/minesweeper_tiles/four.png',
|
||||
"5" = 'icons/UI_Icons/minesweeper_tiles/five.png',
|
||||
"6" = 'icons/UI_Icons/minesweeper_tiles/six.png',
|
||||
"7" = 'icons/UI_Icons/minesweeper_tiles/seven.png',
|
||||
"8" = 'icons/UI_Icons/minesweeper_tiles/eight.png',
|
||||
"empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png',
|
||||
"flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png',
|
||||
"hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png',
|
||||
"mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png',
|
||||
"minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/pills
|
||||
name = "pills"
|
||||
assets = list(
|
||||
"pill1" = 'icons/UI_Icons/Pills/pill1.png',
|
||||
"pill2" = 'icons/UI_Icons/Pills/pill2.png',
|
||||
"pill3" = 'icons/UI_Icons/Pills/pill3.png',
|
||||
"pill4" = 'icons/UI_Icons/Pills/pill4.png',
|
||||
"pill5" = 'icons/UI_Icons/Pills/pill5.png',
|
||||
"pill6" = 'icons/UI_Icons/Pills/pill6.png',
|
||||
"pill7" = 'icons/UI_Icons/Pills/pill7.png',
|
||||
"pill8" = 'icons/UI_Icons/Pills/pill8.png',
|
||||
"pill9" = 'icons/UI_Icons/Pills/pill9.png',
|
||||
"pill10" = 'icons/UI_Icons/Pills/pill10.png',
|
||||
"pill11" = 'icons/UI_Icons/Pills/pill11.png',
|
||||
"pill12" = 'icons/UI_Icons/Pills/pill12.png',
|
||||
"pill13" = 'icons/UI_Icons/Pills/pill13.png',
|
||||
"pill14" = 'icons/UI_Icons/Pills/pill14.png',
|
||||
"pill15" = 'icons/UI_Icons/Pills/pill15.png',
|
||||
"pill16" = 'icons/UI_Icons/Pills/pill16.png',
|
||||
"pill17" = 'icons/UI_Icons/Pills/pill17.png',
|
||||
"pill18" = 'icons/UI_Icons/Pills/pill18.png',
|
||||
"pill19" = 'icons/UI_Icons/Pills/pill19.png',
|
||||
"pill20" = 'icons/UI_Icons/Pills/pill20.png',
|
||||
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
|
||||
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
|
||||
)
|
||||
|
||||
/datum/asset/simple/IRV
|
||||
assets = list(
|
||||
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
|
||||
)
|
||||
|
||||
/datum/asset/group/IRV
|
||||
children = list(
|
||||
/datum/asset/simple/jquery,
|
||||
/datum/asset/simple/IRV
|
||||
)
|
||||
|
||||
/datum/asset/simple/changelog
|
||||
assets = list(
|
||||
"88x31.png" = 'html/88x31.png',
|
||||
"bug-minus.png" = 'html/bug-minus.png',
|
||||
"cross-circle.png" = 'html/cross-circle.png',
|
||||
"hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
|
||||
"image-minus.png" = 'html/image-minus.png',
|
||||
"image-plus.png" = 'html/image-plus.png',
|
||||
"music-minus.png" = 'html/music-minus.png',
|
||||
"music-plus.png" = 'html/music-plus.png',
|
||||
"tick-circle.png" = 'html/tick-circle.png',
|
||||
"wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
|
||||
"spell-check.png" = 'html/spell-check.png',
|
||||
"burn-exclamation.png" = 'html/burn-exclamation.png',
|
||||
"chevron.png" = 'html/chevron.png',
|
||||
"chevron-expand.png" = 'html/chevron-expand.png',
|
||||
"scales.png" = 'html/scales.png',
|
||||
"coding.png" = 'html/coding.png',
|
||||
"ban.png" = 'html/ban.png',
|
||||
"chrome-wrench.png" = 'html/chrome-wrench.png',
|
||||
"changelog.css" = 'html/changelog.css'
|
||||
)
|
||||
|
||||
/datum/asset/group/goonchat
|
||||
children = list(
|
||||
/datum/asset/simple/jquery,
|
||||
/datum/asset/simple/goonchat,
|
||||
/datum/asset/spritesheet/goonchat,
|
||||
/datum/asset/simple/fontawesome
|
||||
)
|
||||
|
||||
/datum/asset/simple/jquery
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
|
||||
)
|
||||
|
||||
/datum/asset/simple/goonchat
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
|
||||
"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
|
||||
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
|
||||
"browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css',
|
||||
"browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css'
|
||||
)
|
||||
|
||||
/datum/asset/simple/fontawesome
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
|
||||
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
|
||||
"fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
|
||||
"fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
|
||||
"font-awesome.css" = 'html/font-awesome/css/all.min.css',
|
||||
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/goonchat
|
||||
name = "chat"
|
||||
|
||||
/datum/asset/spritesheet/goonchat/register()
|
||||
InsertAll("emoji", 'icons/emoji.dmi')
|
||||
|
||||
// pre-loading all lanugage icons also helps to avoid meta
|
||||
InsertAll("language", 'icons/misc/language.dmi')
|
||||
// catch languages which are pulling icons from another file
|
||||
for(var/path in typesof(/datum/language))
|
||||
var/datum/language/L = path
|
||||
var/icon = initial(L.icon)
|
||||
if (icon != 'icons/misc/language.dmi')
|
||||
var/icon_state = initial(L.icon_state)
|
||||
Insert("language-[icon_state]", icon, icon_state=icon_state)
|
||||
|
||||
..()
|
||||
|
||||
/datum/asset/simple/permissions
|
||||
assets = list(
|
||||
"padlock.png" = 'html/padlock.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/notes
|
||||
assets = list(
|
||||
"high_button.png" = 'html/high_button.png',
|
||||
"medium_button.png" = 'html/medium_button.png',
|
||||
"minor_button.png" = 'html/minor_button.png',
|
||||
"none_button.png" = 'html/none_button.png',
|
||||
)
|
||||
|
||||
//this exists purely to avoid meta by pre-loading all language icons.
|
||||
/datum/asset/language/register()
|
||||
for(var/path in typesof(/datum/language))
|
||||
set waitfor = FALSE
|
||||
var/datum/language/L = new path ()
|
||||
L.get_icon()
|
||||
|
||||
/datum/asset/spritesheet/pipes
|
||||
name = "pipes"
|
||||
|
||||
/datum/asset/spritesheet/pipes/register()
|
||||
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi'))
|
||||
InsertAll("", each, GLOB.alldirs)
|
||||
..()
|
||||
|
||||
// Representative icons for each research design
|
||||
/datum/asset/spritesheet/research_designs
|
||||
name = "design"
|
||||
|
||||
/datum/asset/spritesheet/research_designs/register()
|
||||
for (var/path in subtypesof(/datum/design))
|
||||
var/datum/design/D = path
|
||||
|
||||
var/icon_file
|
||||
var/icon_state
|
||||
var/icon/I
|
||||
|
||||
if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest
|
||||
icon_file = initial(D.research_icon)
|
||||
icon_state = initial(D.research_icon_state)
|
||||
if(!(icon_state in icon_states(icon_file)))
|
||||
warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
|
||||
continue
|
||||
I = icon(icon_file, icon_state, SOUTH)
|
||||
|
||||
else
|
||||
// construct the icon and slap it into the resource cache
|
||||
var/atom/item = initial(D.build_path)
|
||||
if (!ispath(item, /atom))
|
||||
// biogenerator outputs to beakers by default
|
||||
if (initial(D.build_type) & BIOGENERATOR)
|
||||
item = /obj/item/reagent_containers/glass/beaker/large
|
||||
else
|
||||
continue // shouldn't happen, but just in case
|
||||
|
||||
// circuit boards become their resulting machines or computers
|
||||
if (ispath(item, /obj/item/circuitboard))
|
||||
var/obj/item/circuitboard/C = item
|
||||
var/machine = initial(C.build_path)
|
||||
if (machine)
|
||||
item = machine
|
||||
|
||||
icon_file = initial(item.icon)
|
||||
icon_state = initial(item.icon_state)
|
||||
|
||||
if(!(icon_state in icon_states(icon_file)))
|
||||
warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
|
||||
continue
|
||||
I = icon(icon_file, icon_state, SOUTH)
|
||||
|
||||
// computers (and snowflakes) get their screen and keyboard sprites
|
||||
if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control))
|
||||
var/obj/machinery/computer/C = item
|
||||
var/screen = initial(C.icon_screen)
|
||||
var/keyboard = initial(C.icon_keyboard)
|
||||
var/all_states = icon_states(icon_file)
|
||||
if (screen && (screen in all_states))
|
||||
I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
|
||||
if (keyboard && (keyboard in all_states))
|
||||
I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
|
||||
|
||||
Insert(initial(D.id), I)
|
||||
return ..()
|
||||
|
||||
/datum/asset/spritesheet/vending
|
||||
name = "vending"
|
||||
|
||||
/datum/asset/spritesheet/vending/register()
|
||||
for(var/k in GLOB.vending_products)
|
||||
var/atom/item = k
|
||||
if(!ispath(item, /atom))
|
||||
continue
|
||||
|
||||
var/icon_file = initial(item.icon)
|
||||
var/icon_state = initial(item.icon_state)
|
||||
var/icon/I
|
||||
|
||||
var/icon_states_list = icon_states(icon_file)
|
||||
if(icon_state in icon_states_list)
|
||||
I = icon(icon_file, icon_state, SOUTH)
|
||||
var/c = initial(item.color)
|
||||
if(!isnull(c) && c != "#FFFFFF")
|
||||
I.Blend(c, ICON_MULTIPLY)
|
||||
else
|
||||
var/icon_states_string
|
||||
for(var/an_icon_state in icon_states_list)
|
||||
if(!icon_states_string)
|
||||
icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
else
|
||||
icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
|
||||
I = icon('icons/turf/floors.dmi', "", SOUTH)
|
||||
|
||||
var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
|
||||
|
||||
Insert(imgid, I)
|
||||
return ..()
|
||||
|
||||
/datum/asset/simple/genetics
|
||||
assets = list(
|
||||
"dna_discovered.gif" = 'html/dna_discovered.gif',
|
||||
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
|
||||
"dna_extra.gif" = 'html/dna_extra.gif'
|
||||
)
|
||||
|
||||
/datum/asset/simple/vv
|
||||
assets = list(
|
||||
"view_variables.css" = 'html/admin/view_variables.css'
|
||||
)
|
||||
@@ -50,6 +50,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
/// Custom Keybindings
|
||||
var/list/key_bindings = list()
|
||||
/// List with a key string associated to a list of keybindings. Unlike key_bindings, this one operates on raw key, allowing for binding a key that triggers regardless of if a modifier is depressed as long as the raw key is sent.
|
||||
var/list/modless_key_bindings = list()
|
||||
|
||||
|
||||
var/tgui_fancy = TRUE
|
||||
@@ -154,6 +156,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
"ipc_screen" = "Sunburst",
|
||||
"ipc_antenna" = "None",
|
||||
"flavor_text" = "",
|
||||
"silicon_flavor_text" = "",
|
||||
"ooc_notes" = "",
|
||||
"meat_type" = "Mammalian",
|
||||
"body_model" = MALE,
|
||||
@@ -367,6 +370,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "[features["flavor_text"]]"
|
||||
else
|
||||
dat += "[TextPreview(features["flavor_text"])]...<BR>"
|
||||
dat += "<h2>Silicon Flavor Text</h2>"
|
||||
dat += "<a href='?_src_=prefs;preference=silicon_flavor_text;task=input'><b>Set Silicon Examine Text</b></a><br>"
|
||||
if(length(features["silicon_flavor_text"]) <= 40)
|
||||
if(!length(features["silicon_flavor_text"]))
|
||||
dat += "\[...\]"
|
||||
else
|
||||
dat += "[features["silicon_flavor_text"]]"
|
||||
else
|
||||
dat += "[TextPreview(features["silicon_flavor_text"])]...<BR>"
|
||||
dat += "<h2>OOC notes</h2>"
|
||||
dat += "<a href='?_src_=prefs;preference=ooc_notes;task=input'><b>Set OOC notes</b></a><br>"
|
||||
var/ooc_notes_len = length(features["ooc_notes"])
|
||||
@@ -1088,11 +1100,16 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
Input mode is the closest thing to the old input system.<br>\
|
||||
<b>IMPORTANT:</b> While in input mode's non hotkey setting (tab toggled), Ctrl + KEY will send KEY to the keybind system as the key itself, not as Ctrl + KEY. This means Ctrl + T/W/A/S/D/all your familiar stuff still works, but you \
|
||||
won't be able to access any regular Ctrl binds.<br>"
|
||||
dat += "<br><b>Modifier-Independent binding</b> - This is a singular bind that works regardless of if Ctrl/Shift/Alt are held down. For example, if combat mode is bound to C in modifier-independent binds, it'll trigger regardless of if you are \
|
||||
holding down shift for sprint. <b>Each keybind can only have one independent binding, and each key can only have one keybind independently bound to it.</b>"
|
||||
// Create an inverted list of keybindings -> key
|
||||
var/list/user_binds = list()
|
||||
var/list/user_modless_binds = list()
|
||||
for (var/key in key_bindings)
|
||||
for(var/kb_name in key_bindings[key])
|
||||
user_binds[kb_name] += list(key)
|
||||
for (var/key in modless_key_bindings)
|
||||
user_modless_binds[modless_key_bindings[key]] = key
|
||||
|
||||
var/list/kb_categories = list()
|
||||
// Group keybinds by category
|
||||
@@ -1100,21 +1117,29 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[name]
|
||||
kb_categories[kb.category] += list(kb)
|
||||
|
||||
dat += "<style>label { display: inline-block; width: 200px; }</style><body>"
|
||||
dat += {"
|
||||
<style>
|
||||
span.bindname { display: inline-block; position: absolute; width: 20% ; left: 5px; padding: 5px; } \
|
||||
span.bindings { display: inline-block; position: relative; width: auto; left: 20%; width: auto; right: 20%; padding: 5px; } \
|
||||
span.independent { display: inline-block; position: absolute; width: 20%; right: 5px; padding: 5px; } \
|
||||
</style><body>
|
||||
"}
|
||||
|
||||
for (var/category in kb_categories)
|
||||
dat += "<h3>[category]</h3>"
|
||||
for (var/i in kb_categories[category])
|
||||
var/datum/keybinding/kb = i
|
||||
var/current_independent_binding = user_modless_binds[kb.name] || "Unbound"
|
||||
if(!length(user_binds[kb.name]))
|
||||
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a>"
|
||||
dat += "<span class='bindname'>[kb.full_name]</span><span class='bindings'><a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a>"
|
||||
var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys
|
||||
if(LAZYLEN(default_keys))
|
||||
dat += "| Default: [default_keys.Join(", ")]"
|
||||
dat += "</span><span class='independent'>Independent Binding: <a href='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[current_independent_binding];independent=1'>[current_independent_binding]</a></span>"
|
||||
dat += "<br>"
|
||||
else
|
||||
var/bound_key = user_binds[kb.name][1]
|
||||
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
dat += "<span class='bindname'l>[kb.full_name]</span><span class='bindings'><a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
for(var/bound_key_index in 2 to length(user_binds[kb.name]))
|
||||
bound_key = user_binds[kb.name][bound_key_index]
|
||||
dat += " | <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
@@ -1123,6 +1148,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys
|
||||
if(LAZYLEN(default_keys))
|
||||
dat += "| Default: [default_keys.Join(", ")]"
|
||||
dat += "</span><span class='independent'>Independent Binding: <a href='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[current_independent_binding];independent=1'>[current_independent_binding]</a></span>"
|
||||
dat += "<br>"
|
||||
|
||||
dat += "<br><br>"
|
||||
@@ -1148,7 +1174,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
#undef APPEARANCE_CATEGORY_COLUMN
|
||||
#undef MAX_MUTANT_ROWS
|
||||
|
||||
/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, var/old_key)
|
||||
/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, independent = FALSE)
|
||||
var/HTML = {"
|
||||
<div id='focus' style="outline: 0;" tabindex=0>Keybinding: [kb.full_name]<br>[kb.description]<br><br><b>Press any key to change<br>Press ESC to clear</b></div>
|
||||
<script>
|
||||
@@ -1160,7 +1186,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var shift = e.shiftKey ? 1 : 0;
|
||||
var numpad = (95 < e.keyCode && e.keyCode < 112) ? 1 : 0;
|
||||
var escPressed = e.keyCode == 27 ? 1 : 0;
|
||||
var url = 'byond://?_src_=prefs;preference=keybindings_set;keybinding=[kb.name];old_key=[old_key];clear_key='+escPressed+';key='+e.key+';alt='+alt+';ctrl='+ctrl+';shift='+shift+';numpad='+numpad+';key_code='+e.keyCode;
|
||||
var url = 'byond://?_src_=prefs;preference=keybindings_set;keybinding=[kb.name];old_key=[old_key];[independent?"independent=1":""];clear_key='+escPressed+';key='+e.key+';alt='+alt+';ctrl='+ctrl+';shift='+shift+';numpad='+numpad+';key_code='+e.keyCode;
|
||||
window.location=url;
|
||||
deedDone = true;
|
||||
}
|
||||
@@ -1616,6 +1642,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(!isnull(msg))
|
||||
features["flavor_text"] = html_decode(msg)
|
||||
|
||||
if("silicon_flavor_text")
|
||||
var/msg = stripped_multiline_input(usr, "Set the silicon flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Silicon Flavor Text", features["silicon_flavor_text"], MAX_FLAVOR_LEN, TRUE)
|
||||
if(!isnull(msg))
|
||||
features["silicon_flavor_text"] = html_decode(msg)
|
||||
|
||||
if("ooc_notes")
|
||||
var/msg = stripped_multiline_input(usr, "Set always-visible OOC notes related to content preferences. THIS IS NOT FOR CHARACTER DESCRIPTIONS!", "OOC notes", features["ooc_notes"], MAX_FLAVOR_LEN, TRUE)
|
||||
if(!isnull(msg))
|
||||
@@ -2357,8 +2388,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
if("keybindings_capture")
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[href_list["keybinding"]]
|
||||
var/old_key = href_list["old_key"]
|
||||
CaptureKeybinding(user, kb, old_key)
|
||||
CaptureKeybinding(user, kb, href_list["old_key"], text2num(href_list["independent"]))
|
||||
return
|
||||
|
||||
if("keybindings_set")
|
||||
@@ -2368,13 +2398,18 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
ShowChoices(user)
|
||||
return
|
||||
|
||||
var/independent = href_list["independent"]
|
||||
|
||||
var/clear_key = text2num(href_list["clear_key"])
|
||||
var/old_key = href_list["old_key"]
|
||||
if(clear_key)
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
if(independent)
|
||||
modless_key_bindings -= old_key
|
||||
else
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
user << browse(null, "window=capturekeypress")
|
||||
save_preferences()
|
||||
ShowChoices(user)
|
||||
@@ -2400,15 +2435,18 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
full_key = "[AltMod][CtrlMod][new_key]"
|
||||
else
|
||||
full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]"
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
key_bindings[full_key] += list(kb_name)
|
||||
key_bindings[full_key] = sortList(key_bindings[full_key])
|
||||
|
||||
user << browse(null, "window=capturekeypress")
|
||||
if(independent)
|
||||
modless_key_bindings -= old_key
|
||||
modless_key_bindings[full_key] = kb_name
|
||||
else
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
key_bindings[full_key] += list(kb_name)
|
||||
key_bindings[full_key] = sortList(key_bindings[full_key])
|
||||
user.client.update_movement_keys()
|
||||
user << browse(null, "window=capturekeypress")
|
||||
save_preferences()
|
||||
|
||||
if("keybindings_reset")
|
||||
@@ -2418,6 +2456,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
return
|
||||
hotkeys = (choice == "Hotkey")
|
||||
key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key)
|
||||
modless_key_bindings = list()
|
||||
user.client.update_movement_keys()
|
||||
|
||||
if("chat_on_map")
|
||||
@@ -2572,8 +2611,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
current_tab = text2num(href_list["tab"])
|
||||
if(href_list["preference"] == "gear")
|
||||
if(href_list["clear_loadout"])
|
||||
LAZYCLEARLIST(chosen_gear)
|
||||
gear_points = initial(gear_points)
|
||||
chosen_gear = list()
|
||||
gear_points = CONFIG_GET(number/initial_gear_points)
|
||||
save_preferences()
|
||||
if(href_list["select_category"])
|
||||
for(var/i in GLOB.loadout_items)
|
||||
@@ -2585,7 +2624,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
return
|
||||
var/toggle = text2num(href_list["toggle_gear"])
|
||||
if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
|
||||
LAZYREMOVE(chosen_gear, G.type)
|
||||
chosen_gear -= G.type
|
||||
gear_points += initial(G.cost)
|
||||
else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
|
||||
if(!is_loadout_slot_available(G.category))
|
||||
@@ -2595,7 +2634,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
to_chat(user, "<span class='danger'>This is an item intended for donator use only. You are not authorized to use this item.</span>")
|
||||
return
|
||||
if(gear_points >= initial(G.cost))
|
||||
LAZYADD(chosen_gear, G.type)
|
||||
chosen_gear += G.type
|
||||
gear_points -= initial(G.cost)
|
||||
|
||||
ShowChoices(user)
|
||||
|
||||
@@ -262,6 +262,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
// Custom hotkeys
|
||||
S["key_bindings"] >> key_bindings
|
||||
S["modless_key_bindings"] >> modless_key_bindings
|
||||
|
||||
//citadel code
|
||||
S["arousable"] >> arousable
|
||||
@@ -315,7 +316,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles))
|
||||
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
|
||||
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
|
||||
key_bindings = sanitize_islist(key_bindings, list())
|
||||
key_bindings = sanitize_islist(key_bindings, list())
|
||||
modless_key_bindings = sanitize_islist(modless_key_bindings, list())
|
||||
|
||||
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
|
||||
|
||||
@@ -333,6 +335,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
if(!length(binds))
|
||||
key_bindings -= key
|
||||
// End
|
||||
// I hate copypaste but let's do it again but for modless ones
|
||||
for(var/key in modless_key_bindings)
|
||||
var/bindname = modless_key_bindings[key]
|
||||
if(!GLOB.keybindings_by_name[bindname])
|
||||
modless_key_bindings -= key
|
||||
|
||||
/datum/preferences/proc/save_preferences()
|
||||
if(!path)
|
||||
@@ -387,6 +394,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["pda_color"], pda_color)
|
||||
WRITE_FILE(S["pda_skin"], pda_skin)
|
||||
WRITE_FILE(S["key_bindings"], key_bindings)
|
||||
WRITE_FILE(S["modless_key_bindings"], modless_key_bindings)
|
||||
|
||||
//citadel code
|
||||
WRITE_FILE(S["screenshake"], screenshake)
|
||||
@@ -553,7 +561,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
else //We have no old flavortext, default to new
|
||||
S["feature_flavor_text"] >> features["flavor_text"]
|
||||
|
||||
|
||||
S["silicon_feature_flavor_text"] >> features["silicon_flavor_text"]
|
||||
|
||||
S["feature_ooc_notes"] >> features["ooc_notes"]
|
||||
S["silicon_flavor_text"] >> features["silicon_flavor_text"]
|
||||
|
||||
S["vore_flags"] >> vore_flags
|
||||
S["vore_taste"] >> vore_taste
|
||||
@@ -678,6 +690,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
|
||||
features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN)
|
||||
features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN)
|
||||
features["ooc_notes"] = copytext(features["ooc_notes"], 1, MAX_FLAVOR_LEN)
|
||||
|
||||
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
/obj/item/clothing/head/hunter
|
||||
name = "hunter"
|
||||
desc = "A basic hat for hunting things."
|
||||
icon = 'modular_citadel/icons/obj/clothing/cit_hats.dmi'
|
||||
icon_state = "hunter"
|
||||
item_state = "hunter_worn"
|
||||
@@ -375,12 +375,6 @@
|
||||
icon_state = "telegram"
|
||||
dog_fashion = /datum/dog_fashion/head/telegram
|
||||
|
||||
/obj/item/clothing/head/colour
|
||||
name = "Singer cap"
|
||||
desc = "A light white hat that has bands of color. Just makes you want to sing and dance!"
|
||||
icon_state = "colour"
|
||||
dog_fashion = /datum/dog_fashion/head/colour
|
||||
|
||||
/obj/item/clothing/head/christmashat
|
||||
name = "red santa hat"
|
||||
desc = "A red Christmas Hat! How festive!"
|
||||
@@ -434,3 +428,4 @@
|
||||
desc = "A symbol of discipline, honor, and lots and lots of removal of some type of skewered food."
|
||||
icon_state = "russobluecamohat"
|
||||
item_state = "russobluecamohat"
|
||||
dynamic_hair_suffix = ""
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
desc = "A jack o' lantern! Believed to ward off evil spirits."
|
||||
icon_state = "hardhat0_pumpkin"
|
||||
item_state = "hardhat0_pumpkin"
|
||||
hat_type = "pumpkin"
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
brightness_on = 2 //luminosity when on
|
||||
@@ -150,6 +151,7 @@
|
||||
desc = "Some fake antlers and a very fake red nose."
|
||||
icon_state = "hardhat0_reindeer"
|
||||
item_state = "hardhat0_reindeer"
|
||||
hat_type = "reindeer"
|
||||
flags_inv = 0
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
brightness_on = 1 //luminosity when on
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
name = "baseball cap"
|
||||
desc = "It's a robust baseball hat, this one belongs to syndicate major league team."
|
||||
icon_state = "baseballsoft"
|
||||
soft_type = "baseballsoft"
|
||||
soft_type = "baseball"
|
||||
item_state = "baseballsoft"
|
||||
flags_inv = HIDEEYES|HIDEFACE
|
||||
armor = list("melee" = 35, "bullet" = 35, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 90)
|
||||
|
||||
@@ -97,6 +97,48 @@
|
||||
icon_state = "trek_ds9_medsci"
|
||||
item_state = "b_suit"
|
||||
|
||||
//Orvilike (Orville-inspired clothing with TOS-like color code)
|
||||
/obj/item/clothing/under/trek/command/orv
|
||||
desc = "An uniform worn by command officers since 2420s."
|
||||
icon_state = "orv_com"
|
||||
|
||||
/obj/item/clothing/under/trek/engsec/orv
|
||||
desc = "An uniform worn by operations officers since 2420s."
|
||||
icon_state = "orv_ops"
|
||||
|
||||
/obj/item/clothing/under/trek/medsci/orv
|
||||
desc = "An uniform worn by medsci officers since 2420s."
|
||||
icon_state = "orv_medsci"
|
||||
|
||||
//Orvilike Extra (Ditto, but expands it for Civilian department with SS13 colors and gives specified command uniform)
|
||||
//honestly no idea why i added specified comm. uniforms but w/e
|
||||
/obj/item/clothing/under/trek/command/orv/captain
|
||||
name = "captain uniform"
|
||||
desc = "An uniform worn by captains since 2550s."
|
||||
icon_state = "orv_com_capt"
|
||||
|
||||
/obj/item/clothing/under/trek/command/orv/engsec
|
||||
name = "operations command uniform"
|
||||
desc = "An uniform worn by operations command officers since 2550s."
|
||||
icon_state = "orv_com_ops"
|
||||
|
||||
/obj/item/clothing/under/trek/command/orv/medsci
|
||||
name = "medsci command uniform"
|
||||
desc = "An uniform worn by medsci command officers since 2550s."
|
||||
icon_state = "orv_com_medsci"
|
||||
|
||||
/obj/item/clothing/under/trek/orv
|
||||
name = "adjutant uniform"
|
||||
desc = "An uniform worn by adjutants <i>(assistants)</i> since 2550s."
|
||||
icon_state = "orv_ass"
|
||||
item_state = "gy_suit"
|
||||
|
||||
/obj/item/clothing/under/trek/orv/service
|
||||
name = "service uniform"
|
||||
desc = "An uniform worn by service officers since 2550s."
|
||||
icon_state = "orv_srv"
|
||||
item_state = "g_suit"
|
||||
|
||||
//The Motion Picture
|
||||
/obj/item/clothing/under/trek/fedutil
|
||||
name = "federation utility uniform"
|
||||
|
||||
@@ -383,6 +383,7 @@
|
||||
/datum/spacevine_controller/New(turf/location, list/muts, potency, production, datum/round_event/event = null)
|
||||
vines = list()
|
||||
growth_queue = list()
|
||||
spawn_spacevine_piece(location, null, muts)
|
||||
START_PROCESSING(SSobj, src)
|
||||
vine_mutations_list = list()
|
||||
init_subtypes(/datum/spacevine_mutation/, vine_mutations_list)
|
||||
|
||||
@@ -412,6 +412,15 @@
|
||||
begin_month = JUNE
|
||||
begin_weekday = SUNDAY
|
||||
|
||||
/datum/holiday/pride
|
||||
name = PRIDE_MONTH
|
||||
begin_day = 1
|
||||
begin_month = JUNE
|
||||
end_day = 30
|
||||
|
||||
/datum/holiday/pride/getStationPrefix()
|
||||
return pick("Pride", "Gay", "Bi", "Trans", "Lesbian", "Ace", "Aro", "Agender", pick("Enby", "Enbie"), "Pan", "Intersex", "Demi", "Poly", "Closeted", "Genderfluid")
|
||||
|
||||
/datum/holiday/moth
|
||||
name = "Moth Week"
|
||||
|
||||
|
||||
@@ -40,9 +40,6 @@
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
/obj/item/holo/esword/attack(target as mob, mob/user as mob)
|
||||
..()
|
||||
|
||||
/obj/item/holo/esword/Initialize()
|
||||
. = ..()
|
||||
saber_color = pick("red","blue","green","purple")
|
||||
|
||||
@@ -205,6 +205,11 @@
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/biogenerator/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
detach(user)
|
||||
|
||||
/obj/machinery/biogenerator/proc/activate()
|
||||
if (usr.stat != CONSCIOUS)
|
||||
return
|
||||
@@ -293,9 +298,9 @@
|
||||
update_icon()
|
||||
return .
|
||||
|
||||
/obj/machinery/biogenerator/proc/detach()
|
||||
/obj/machinery/biogenerator/proc/detach(mob/living/user)
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
user.put_in_hands(beaker)
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
@@ -310,7 +315,7 @@
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["detach"])
|
||||
detach()
|
||||
detach(usr)
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["create"])
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
/obj/item/instrument/dropped(mob/user)
|
||||
. = ..()
|
||||
if((loc != user) && (user.machine == src))
|
||||
user.set_machine(null)
|
||||
user.unset_machine()
|
||||
|
||||
/obj/item/instrument/interact(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
/obj/structure/musician/ui_interact(mob/user)
|
||||
. = ..()
|
||||
user.set_machine(src)
|
||||
song.ui_interact(user)
|
||||
|
||||
/obj/structure/musician/wrench_act(mob/living/user, obj/item/I)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user