Merge pull request #1 from Citadel-Station-13/master

This may be a complete fuckup take no note of it
This commit is contained in:
Seris02
2019-09-28 18:23:31 +08:00
committed by GitHub
1283 changed files with 18016 additions and 11106 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
FROM tgstation/byond:512.1467 as base
FROM tgstation/byond:512.1484 as base
FROM base as build_base
+1 -1
View File
@@ -20,7 +20,7 @@ Based and maintained from /tg/station.<BR>
**Forums:** http://citadel-station.net/forum/ <BR>
**Ban Appeals:** http://citadel-station.net/forum/forumdisplay.php?fid=8 <BR>
**Code:** https://github.com/Citadel-Station-13/Citadel-Station-13 <BR>
**Discord:** [Here](https://discord.gg/3gJ9pnM). <BR>
**Discord:** [Here](https://discord.gg/E6SQuhz). <BR>
## DOWNLOADING
@@ -508,7 +508,9 @@
/obj/structure/stone_tile/cracked{
dir = 4
},
/obj/item/construction/rcd/loaded,
/obj/item/construction/rcd/loaded/upgraded{
},
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"bn" = (
+376 -145
View File
@@ -41,6 +41,21 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/bar)
"aad" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red{
dir = 8
},
/obj/structure/table,
/obj/item/restraints/handcuffs,
/turf/open/floor/plasteel,
/area/security/prison)
"aae" = (
/obj/effect/landmark/carpspawn,
/turf/open/space,
@@ -577,6 +592,22 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall,
/area/security/execution/transfer)
"abz" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
/obj/structure/cable{
icon_state = "4-8"
},
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red{
dir = 8
},
/obj/structure/cable{
icon_state = "2-8"
},
/turf/open/floor/plasteel,
/area/security/prison)
"abA" = (
/obj/machinery/light,
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
@@ -1849,16 +1880,16 @@
/turf/open/floor/plasteel/dark,
/area/security/execution/transfer)
"aef" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red,
/obj/effect/turf_decal/tile/red{
dir = 8
},
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel,
/area/security/prison)
"aeg" = (
@@ -2118,6 +2149,31 @@
},
/turf/open/floor/plating,
/area/maintenance/fore/secondary)
"aeD" = (
/obj/machinery/door/airlock/security{
name = "Firing Range";
req_access_txt = "2"
},
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel,
/area/security/prison)
"aeE" = (
/obj/effect/turf_decal/stripes/line{
dir = 9
},
/obj/machinery/light/small{
dir = 8
},
/turf/open/floor/plating,
/area/security/prison)
"aeF" = (
/obj/effect/turf_decal/stripes/line{
dir = 1
},
/turf/open/floor/plating,
/area/security/prison)
"aeG" = (
/obj/structure/cable,
/obj/machinery/power/solar{
@@ -2193,17 +2249,13 @@
/turf/open/floor/plasteel/dark,
/area/security/execution/transfer)
"aeM" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
/obj/structure/cable{
icon_state = "4-8"
/obj/effect/turf_decal/stripes/line{
dir = 5
},
/obj/effect/turf_decal/tile/red{
dir = 1
/obj/structure/window/reinforced{
dir = 4
},
/obj/effect/turf_decal/tile/red{
dir = 8
},
/turf/open/floor/plasteel,
/turf/open/floor/plating,
/area/security/prison)
"aeN" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
@@ -2494,6 +2546,10 @@
},
/turf/open/floor/plasteel,
/area/security/main)
"afn" = (
/obj/structure/table,
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"afo" = (
/obj/machinery/door/airlock/external{
name = "Escape Pod Three"
@@ -2514,6 +2570,20 @@
},
/turf/open/space/basic,
/area/space)
"afq" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
/turf/open/floor/plasteel,
/area/security/prison)
"afr" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/security/prison)
"afs" = (
/obj/effect/turf_decal/stripes/line{
dir = 8
},
/turf/open/floor/plating,
/area/security/prison)
"aft" = (
/obj/machinery/atmospherics/pipe/simple/general/visible{
dir = 5
@@ -2570,16 +2640,16 @@
/turf/open/floor/plasteel/dark,
/area/security/execution/transfer)
"afz" = (
/obj/structure/table,
/obj/item/restraints/handcuffs,
/obj/effect/turf_decal/tile/red{
dir = 1
/obj/effect/turf_decal/stripes/line{
dir = 4
},
/obj/effect/turf_decal/tile/red,
/obj/effect/turf_decal/tile/red{
dir = 8
/obj/machinery/door/window/westleft{
base_state = "right";
dir = 4;
icon_state = "right";
name = "Shooting Range"
},
/turf/open/floor/plasteel,
/turf/open/floor/plating,
/area/security/prison)
"afA" = (
/turf/closed/wall/r_wall,
@@ -2823,6 +2893,16 @@
/obj/machinery/atmospherics/pipe/manifold4w/general/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"age" = (
/obj/machinery/door/window/southleft{
name = "Target Storage"
},
/obj/item/target/clown,
/obj/item/target/clown,
/obj/item/target,
/obj/item/target,
/turf/open/floor/plating,
/area/security/prison)
"agf" = (
/obj/structure/table,
/obj/item/stack/sheet/metal,
@@ -2924,7 +3004,7 @@
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"agp" = (
/obj/machinery/computer/prisoner,
/obj/machinery/computer/prisoner/management,
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"agq" = (
@@ -2976,6 +3056,16 @@
},
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"agv" = (
/obj/structure/cable{
icon_state = "2-8"
},
/obj/structure/cable{
icon_state = "2-4"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
/area/security/prison)
"agw" = (
/obj/structure/table,
/obj/machinery/syndicatebomb/training,
@@ -3100,10 +3190,13 @@
/turf/open/floor/plasteel,
/area/security/main)
"agH" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
/obj/machinery/door/window/southright{
name = "Target Storage"
},
/turf/open/floor/plasteel/dark,
/obj/item/target/alien,
/obj/item/target/alien,
/obj/item/target/syndicate,
/turf/open/floor/plating,
/area/security/prison)
"agI" = (
/obj/machinery/airalarm{
@@ -3474,6 +3567,15 @@
},
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"ahw" = (
/obj/effect/turf_decal/stripes/line{
dir = 10
},
/obj/machinery/light/small{
dir = 8
},
/turf/open/floor/plating,
/area/security/prison)
"ahx" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -4489,7 +4591,7 @@
/turf/open/space,
/area/solar/port/fore)
"ajr" = (
/obj/machinery/computer/gulag_teleporter_computer,
/obj/machinery/computer/prisoner/gulag_teleporter_computer,
/turf/open/floor/plasteel,
/area/security/processing)
"ajs" = (
@@ -4497,26 +4599,18 @@
/turf/open/floor/plasteel,
/area/security/processing)
"ajt" = (
/obj/structure/sign/warning/securearea{
pixel_x = 32
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/obj/structure/table,
/obj/item/storage/box/prisoner,
/obj/machinery/camera{
c_tag = "Labor Shuttle Dock North"
},
/turf/open/floor/plasteel,
/area/security/processing)
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plating,
/area/security/prison)
"aju" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
/obj/effect/turf_decal/stripes/line{
dir = 6
},
/obj/machinery/computer/security/labor,
/turf/open/floor/plasteel,
/area/security/processing)
/obj/structure/window/reinforced{
dir = 4
},
/turf/open/floor/plating,
/area/security/prison)
"ajv" = (
/obj/machinery/light{
dir = 8
@@ -4830,6 +4924,29 @@
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/turf/open/floor/plating,
/area/maintenance/solars/port/fore)
"ajX" = (
/obj/structure/table,
/obj/structure/cable{
icon_state = "0-2"
},
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red{
dir = 8
},
/obj/machinery/recharger,
/obj/item/gun/energy/laser/practice,
/obj/item/gun/energy/laser/practice,
/turf/open/floor/plasteel,
/area/security/prison)
"ajY" = (
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
/area/security/prison)
"ajZ" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/structure/sign/warning/vacuum/external{
@@ -4854,20 +4971,18 @@
/area/security/processing)
"akc" = (
/obj/structure/cable{
icon_state = "4-8"
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 6
/obj/machinery/airalarm{
dir = 8;
pixel_x = 24
},
/turf/open/floor/plasteel,
/area/security/processing)
/area/security/prison)
"akd" = (
/obj/structure/cable{
icon_state = "2-4"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
/area/security/processing)
/obj/structure/lattice,
/turf/closed/wall,
/area/security/prison)
"ake" = (
/obj/structure/cable{
icon_state = "4-8"
@@ -5136,6 +5251,44 @@
},
/turf/open/floor/plating,
/area/maintenance/solars/port/fore)
"akC" = (
/obj/machinery/door/airlock/security{
name = "Labor Shuttle";
req_access_txt = "2"
},
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
/area/security/processing)
"akD" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plating,
/area/security/prison)
"akE" = (
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 8
},
/turf/open/floor/plasteel,
/area/security/processing)
"akF" = (
/obj/structure/sign/warning/securearea{
pixel_x = 32
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/obj/machinery/camera{
c_tag = "Labor Shuttle Dock North"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/security/processing)
"akG" = (
/obj/structure/sign/warning/vacuum/external{
pixel_y = 32
@@ -5156,11 +5309,12 @@
/turf/open/floor/plasteel,
/area/security/processing)
"akJ" = (
/obj/machinery/light_switch{
pixel_x = 27
/obj/structure/cable{
icon_state = "2-4"
},
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 4
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel,
/area/security/processing)
@@ -5445,12 +5599,42 @@
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/maintenance/port/fore)
"alj" = (
/obj/structure/cable{
icon_state = "4-8"
},
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 8
},
/turf/open/floor/plasteel,
/area/security/processing)
"alk" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{
dir = 1
},
/turf/open/floor/plasteel,
/area/engine/atmos)
"all" = (
/obj/machinery/light_switch{
pixel_x = 27
},
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 4
},
/obj/machinery/computer/security/labor,
/turf/open/floor/plasteel,
/area/security/processing)
"alm" = (
/obj/machinery/airalarm{
dir = 8;
pixel_x = 24
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/chair{
dir = 1
},
/turf/open/floor/plasteel,
/area/security/processing)
"aln" = (
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 4
@@ -5462,6 +5646,12 @@
},
/turf/open/floor/plating,
/area/security/processing)
"alo" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/table,
/obj/item/storage/box/prisoner,
/turf/open/floor/plasteel,
/area/security/processing)
"alp" = (
/turf/open/floor/plating,
/area/security/processing)
@@ -5469,13 +5659,10 @@
/turf/open/floor/plasteel,
/area/security/processing)
"alr" = (
/obj/machinery/airalarm{
dir = 8;
pixel_x = 24
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/security/processing)
/obj/structure/target_stake,
/obj/item/target/syndicate,
/turf/open/floor/plating,
/area/security/prison)
"als" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -5527,6 +5714,18 @@
},
/turf/open/floor/plasteel,
/area/security/brig)
"alx" = (
/obj/structure/cable{
icon_state = "1-4"
},
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red{
dir = 8
},
/turf/open/floor/plasteel,
/area/security/prison)
"aly" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
dir = 1
@@ -5681,6 +5880,24 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating,
/area/maintenance/fore/secondary)
"alM" = (
/obj/structure/cable{
icon_state = "1-8"
},
/obj/structure/cable{
icon_state = "0-8"
},
/obj/machinery/light{
dir = 4
},
/obj/machinery/power/apc{
areastring = "/area/security/main";
dir = 4;
name = "Firing Range APC";
pixel_x = 24
},
/turf/open/floor/plasteel,
/area/security/prison)
"alO" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -5736,6 +5953,44 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,
/turf/open/floor/plasteel,
/area/engine/atmos)
"alY" = (
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red{
dir = 8
},
/obj/machinery/camera{
c_tag = "Firing Range";
dir = 1
},
/turf/open/floor/plasteel,
/area/security/prison)
"alZ" = (
/obj/structure/table,
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/obj/item/clothing/glasses/sunglasses{
pixel_x = 3;
pixel_y = 3
},
/obj/item/clothing/glasses/sunglasses{
pixel_x = 3;
pixel_y = 3
},
/obj/item/clothing/ears/earmuffs{
pixel_x = -3;
pixel_y = -2
},
/obj/item/clothing/ears/earmuffs{
pixel_x = -3;
pixel_y = -2
},
/obj/machinery/firealarm{
dir = 4;
pixel_x = 24
},
/turf/open/floor/plasteel,
/area/security/prison)
"ama" = (
/mob/living/simple_animal/sloth/paperwork,
/turf/open/floor/plasteel,
@@ -5755,10 +6010,6 @@
},
/turf/open/floor/plasteel,
/area/security/processing)
"amd" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/security/processing)
"ame" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -6031,26 +6282,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel,
/area/security/processing)
"amN" = (
/obj/structure/table,
/obj/item/clothing/glasses/sunglasses{
pixel_x = 3;
pixel_y = 3
},
/obj/item/clothing/glasses/sunglasses{
pixel_x = 3;
pixel_y = 3
},
/obj/item/clothing/ears/earmuffs{
pixel_x = -3;
pixel_y = -2
},
/obj/item/clothing/ears/earmuffs{
pixel_x = -3;
pixel_y = -2
},
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"amQ" = (
/obj/structure/cable{
icon_state = "0-4"
@@ -19371,7 +19602,7 @@
/turf/closed/wall,
/area/bridge)
"aTR" = (
/obj/machinery/computer/prisoner,
/obj/machinery/computer/prisoner/management,
/obj/effect/turf_decal/tile/red{
dir = 1
},
@@ -80535,12 +80766,12 @@ adB
aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
acd
acd
acd
afr
acd
acd
aaa
aaa
aaa
@@ -80793,11 +81024,11 @@ abc
abc
afu
abc
aaa
aaa
aaa
aaa
aaa
age
aeE
afs
ahw
acd
aaa
aaa
aaa
@@ -81050,11 +81281,11 @@ aea
aeH
aft
abc
aaa
aaa
aaa
aaa
aaa
agH
aeF
alr
ajt
afr
aaa
aaa
aiU
@@ -81308,10 +81539,10 @@ aeJ
afw
abc
abc
aaf
aaa
aaf
aaf
aeF
aay
ajt
akd
aaf
aaf
aiU
@@ -81565,9 +81796,9 @@ aeI
afv
agf
abc
aaf
aaa
aaa
aeF
aay
ajt
aiT
aiT
aiV
@@ -81822,9 +82053,9 @@ aeL
afy
agh
abc
aaf
aaa
aaf
aeM
afz
aju
aiT
ajs
akb
@@ -82079,9 +82310,9 @@ aeK
afx
agg
abc
aaf
aaa
aaa
ajX
alx
alY
aiU
ajr
aka
@@ -82335,13 +82566,13 @@ aeg
aeN
afA
afA
afA
aaf
aaa
aaa
aiU
aju
akd
abc
afq
agv
ajY
akC
akE
akJ
akK
als
ame
@@ -82588,20 +82819,20 @@ acd
acC
ada
adF
aad
abz
aef
aeM
afz
aai
aai
aai
aai
aai
aai
ajt
aeD
aav
akc
akJ
alr
amd
alM
alZ
akD
akF
alj
all
alm
alo
amL
anu
alq
@@ -82848,11 +83079,11 @@ adH
aei
aeO
afJ
acd
agL
agK
agK
aiB
aai
aai
aai
aai
aai
aai
ajw
akf
@@ -83106,10 +83337,10 @@ aeh
aeO
afI
agl
agH
agL
ags
ags
aho
aiB
acd
ajv
ake
@@ -87731,7 +87962,7 @@ bkA
acF
aes
avB
amN
afn
agt
awN
aHp
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -2017,7 +2017,7 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/hos)
"aeu" = (
/obj/machinery/computer/prisoner,
/obj/machinery/computer/prisoner/management,
/turf/open/floor/plasteel/dark,
/area/crew_quarters/heads/hos)
"aev" = (
@@ -8416,7 +8416,7 @@
/turf/open/floor/plating,
/area/security/warden)
"apI" = (
/obj/machinery/computer/prisoner{
/obj/machinery/computer/prisoner/management{
dir = 4
},
/obj/structure/cable/yellow{
@@ -10514,7 +10514,7 @@
/turf/open/floor/plating,
/area/maintenance/port/fore)
"atK" = (
/obj/machinery/computer/gulag_teleporter_computer{
/obj/machinery/computer/prisoner/gulag_teleporter_computer{
dir = 1
},
/turf/open/floor/plasteel/dark,
@@ -30781,7 +30781,7 @@
/obj/structure/cable/yellow{
icon_state = "2-4"
},
/obj/machinery/computer/prisoner,
/obj/machinery/computer/prisoner/management,
/obj/effect/turf_decal/tile/red{
dir = 1
},
@@ -4897,7 +4897,7 @@
/turf/open/floor/plasteel/showroomfloor,
/area/security/warden)
"amT" = (
/obj/machinery/computer/prisoner,
/obj/machinery/computer/prisoner/management,
/obj/machinery/airalarm{
pixel_y = 22
},
@@ -6072,7 +6072,7 @@
/turf/open/floor/plating,
/area/security/brig)
"apF" = (
/obj/machinery/computer/gulag_teleporter_computer{
/obj/machinery/computer/prisoner/gulag_teleporter_computer{
dir = 1
},
/turf/open/floor/plasteel/dark,
@@ -7048,7 +7048,7 @@
/turf/open/floor/plasteel/dark,
/area/bridge)
"arR" = (
/obj/machinery/computer/prisoner,
/obj/machinery/computer/prisoner/management,
/obj/effect/turf_decal/tile/red{
dir = 1
},
@@ -47466,8 +47466,8 @@
/area/hydroponics/garden/monastery)
"cgL" = (
/obj/structure/closet/cabinet,
/obj/item/clothing/suit/holidaypriest,
/obj/item/clothing/suit/nun,
/obj/item/clothing/suit/chaplain/holidaypriest,
/obj/item/clothing/suit/chaplain/nun,
/obj/item/clothing/head/nun_hood,
/obj/machinery/button/door{
id = "Cell1";
@@ -47834,8 +47834,8 @@
/area/space/nearstation)
"cio" = (
/obj/structure/closet/cabinet,
/obj/item/clothing/suit/holidaypriest,
/obj/item/clothing/suit/nun,
/obj/item/clothing/suit/chaplain/holidaypriest,
/obj/item/clothing/suit/chaplain/nun,
/obj/item/clothing/head/nun_hood,
/obj/machinery/button/door{
id = "Cell2";
@@ -50476,8 +50476,8 @@
/obj/structure/closet,
/obj/item/storage/backpack/cultpack,
/obj/item/clothing/head/nun_hood,
/obj/item/clothing/suit/nun,
/obj/item/clothing/suit/holidaypriest,
/obj/item/clothing/suit/chaplain/nun,
/obj/item/clothing/suit/chaplain/holidaypriest,
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
+1 -1
View File
@@ -523,7 +523,7 @@
/turf/open/floor/plasteel,
/area/science)
"bC" = (
/obj/machinery/computer/gulag_teleporter_computer{
/obj/machinery/computer/prisoner/gulag_teleporter_computer{
dir = 4
},
/turf/open/floor/plasteel,
+5 -5
View File
@@ -1264,9 +1264,9 @@
/area/holodeck/rec_center/chapelcourt)
"dw" = (
/obj/structure/table/wood/fancy,
/obj/item/clothing/suit/nun,
/obj/item/clothing/suit/chaplain/nun,
/obj/item/clothing/head/nun_hood,
/obj/item/clothing/suit/holidaypriest,
/obj/item/clothing/suit/chaplain/holidaypriest,
/turf/open/floor/holofloor{
dir = 8;
icon_state = "dark"
@@ -3864,7 +3864,7 @@
/turf/open/floor/plasteel,
/area/centcom/control)
"jS" = (
/obj/machinery/computer/prisoner,
/obj/machinery/computer/prisoner/management,
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plasteel,
/area/centcom/control)
@@ -5857,7 +5857,7 @@
/turf/open/floor/plasteel,
/area/centcom/control)
"nY" = (
/obj/machinery/computer/prisoner{
/obj/machinery/computer/prisoner/management{
dir = 1
},
/obj/effect/turf_decal/stripes/line{
@@ -10495,7 +10495,7 @@
/turf/open/floor/plasteel/dark,
/area/centcom/control)
"yv" = (
/obj/machinery/computer/prisoner{
/obj/machinery/computer/prisoner/management{
dir = 1
},
/obj/machinery/light,
+7
View File
@@ -98,6 +98,13 @@
#define DRINKSBLOOD 15
#define NOEYES 16
#define MARKINGS 17
#define MUTCOLORS2 18
#define MUTCOLORS3 19
#define NOAROUSAL 20 //Stops all arousal effects
#define NOGENITALS 21 //Cannot create, use, or otherwise have genitals
#define MATRIXED 22 //if icon is color matrix'd
#define SKINTONE 23 //uses skin tones
#define HORNCOLOR 24
#define ORGAN_SLOT_BRAIN "brain"
#define ORGAN_SLOT_APPENDIX "appendix"
+7
View File
@@ -81,3 +81,10 @@
#define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu
#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you
///Max length of a keypress command before it's considered to be a forged packet/bogus command
#define MAX_KEYPRESS_COMMANDLENGTH 16
///Max amount of keypress messages per second over two seconds before client is autokicked
#define MAX_KEYPRESS_AUTOKICK 100
///Length of held key rolling buffer
#define HELD_KEY_BUFFER_LENGTH 15
+1 -1
View File
@@ -38,5 +38,5 @@
//Gangshit
#define NOT_DOMINATING -1
#define MAX_LEADERS_GANG 3
#define MAX_LEADERS_GANG 4
#define INITIAL_DOM_ATTEMPTS 3
-11
View File
@@ -89,17 +89,6 @@
//Damage stuffs
#define AROUSAL "arousal"
//DNA stuffs. Remember to change this if upstream adds more snowflake options
//Species stuffs. Remember to change this if upstream updates species flags
#define MUTCOLORS2 35
#define MUTCOLORS3 36
#define NOAROUSAL 37 //Stops all arousal effects
#define NOGENITALS 38 //Cannot create, use, or otherwise have genitals
#define MATRIXED 39 //if icon is color matrix'd
#define SKINTONE 40 //uses skin tones
//Citadel istypes
#define isgenital(A) (istype(A, /obj/item/organ/genital))
+2
View File
@@ -109,3 +109,5 @@
#define RCD_AIRLOCK 2
#define RCD_DECONSTRUCT 3
#define RCD_WINDOWGRILLE 4
#define RCD_MACHINE 8
#define RCD_COMPUTER 16
+18
View File
@@ -0,0 +1,18 @@
#define DONATOR_GROUP_TIER_1_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_1_donators
#define DONATOR_GROUP_TIER_2_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_2_donators
#define DONATOR_GROUP_TIER_3_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_3_donators
#define DONATOR_GROUP_TIER_1_CONFIG_SUBPATH keyed_list/donator_group/tier_1_donators
#define DONATOR_GROUP_TIER_2_CONFIG_SUBPATH keyed_list/donator_group/tier_2_donators
#define DONATOR_GROUP_TIER_3_CONFIG_SUBPATH keyed_list/donator_group/tier_3_donators
#define TIER_1_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_1_CONFIG_SUBPATH)
#define TIER_2_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_2_CONFIG_SUBPATH)
#define TIER_3_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_3_CONFIG_SUBPATH)
//flags
#define DONATOR_GROUP_TIER_1 "T1"
#define DONATOR_GROUP_TIER_2 "T2"
#define DONATOR_GROUP_TIER_3 "T3"
#define IS_CKEY_DONATOR_GROUP(ckey, groupid) is_donator_group(ckey, groupid)
+2 -2
View File
@@ -50,13 +50,13 @@
#define isgolem(A) (is_species(A, /datum/species/golem))
#define islizard(A) (is_species(A, /datum/species/lizard))
#define isplasmaman(A) (is_species(A, /datum/species/plasmaman))
#define ispodperson(A) (is_species(A, /datum/species/podperson))
#define ispodperson(A) (is_species(A, /datum/species/pod))
#define isflyperson(A) (is_species(A, /datum/species/fly))
#define isjellyperson(A) (is_species(A, /datum/species/jelly))
#define isslimeperson(A) (is_species(A, /datum/species/jelly/slime))
#define isluminescent(A) (is_species(A, /datum/species/jelly/luminescent))
#define iszombie(A) (is_species(A, /datum/species/zombie))
#define ismoth(A) (is_species(A, /datum/species/moth))
#define ismoth(A) (is_species(A, /datum/species/insect))
#define ishumanbasic(A) (is_species(A, /datum/species/human))
#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) )
+38
View File
@@ -48,3 +48,41 @@
#define JOB_UNAVAILABLE_PLAYTIME 3
#define JOB_UNAVAILABLE_ACCOUNTAGE 4
#define JOB_UNAVAILABLE_SLOTFULL 5
#define DEFAULT_RELIGION "Christianity"
#define DEFAULT_DEITY "Space Jesus"
#define JOB_DISPLAY_ORDER_DEFAULT 0
#define JOB_DISPLAY_ORDER_ASSISTANT 1
#define JOB_DISPLAY_ORDER_CAPTAIN 2
#define JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL 3
#define JOB_DISPLAY_ORDER_BARTENDER 4
#define JOB_DISPLAY_ORDER_COOK 5
#define JOB_DISPLAY_ORDER_BOTANIST 6
#define JOB_DISPLAY_ORDER_JANITOR 7
#define JOB_DISPLAY_ORDER_CLOWN 8
#define JOB_DISPLAY_ORDER_MIME 9
#define JOB_DISPLAY_ORDER_CURATOR 10
#define JOB_DISPLAY_ORDER_LAWYER 11
#define JOB_DISPLAY_ORDER_CHAPLAIN 12
#define JOB_DISPLAY_ORDER_QUARTERMASTER 13
#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 14
#define JOB_DISPLAY_ORDER_SHAFT_MINER 15
#define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 16
#define JOB_DISPLAY_ORDER_STATION_ENGINEER 17
#define JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN 18
#define JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER 19
#define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 20
#define JOB_DISPLAY_ORDER_CHEMIST 21
#define JOB_DISPLAY_ORDER_GENETICIST 22
#define JOB_DISPLAY_ORDER_VIROLOGIST 23
#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 24
#define JOB_DISPLAY_ORDER_SCIENTIST 25
#define JOB_DISPLAY_ORDER_ROBOTICIST 26
#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 27
#define JOB_DISPLAY_ORDER_WARDEN 28
#define JOB_DISPLAY_ORDER_DETECTIVE 29
#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 30
#define JOB_DISPLAY_ORDER_AI 31
#define JOB_DISPLAY_ORDER_CYBORG 32
+6
View File
@@ -201,4 +201,10 @@
return list(region_x1 & region_x2, region_y1 & region_y2)
#define EXP_DISTRIBUTION(desired_mean) ( -(1/(1/desired_mean)) * log(rand(1, 1000) * 0.001) )
#define LORENTZ_DISTRIBUTION(x, s) ( s*TAN(TODEGREES(PI*(rand()-0.5))) + x )
#define LORENTZ_CUMULATIVE_DISTRIBUTION(x, y, s) ( (1/PI)*TORADIANS(arctan((x-y)/s)) + 1/2 )
#define RULE_OF_THREE(a, b, x) ((a*x)/b)
// )
+3
View File
@@ -472,6 +472,9 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define EGG_LAYING_MESSAGES list("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")
// list of all null rod weapons
#define HOLY_WEAPONS /obj/item/nullrod, /obj/item/twohanded/dualsaber/hypereutactic/chaplain, /obj/item/gun/energy/laser/redtag/hitscan/chaplain, /obj/item/multitool/chaplain, /obj/item/melee/baseball_bat/chaplain
// Used by PDA and cartridge code to reduce repetitiveness of spritesheets
#define PDAIMG(what) {"<span class="pda16x16 [#what]"></span>"}
+5
View File
@@ -116,6 +116,8 @@
#define BIOWARE_GENERIC "generic"
#define BIOWARE_NERVES "nerves"
#define BIOWARE_CIRCULATION "circulation"
#define BIOWARE_LIGAMENTS "ligaments"
#define BIOWARE_DISSECTION "dissected"
//Health hud screws for carbon mobs
#define SCREWYHUD_NONE 0
@@ -264,3 +266,6 @@
#define BODYPART_LIFE_UPDATE_HEALTH (1<<0)
#define HUMAN_FIRE_STACK_ICON_NUM 3
#define PULL_PRONE_SLOWDOWN 0.6
#define HUMAN_CARRY_SLOWDOWN 0
+3
View File
@@ -31,3 +31,6 @@
#define MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD "PAI_SPACEWALK_MODIFIER"
#define MOVESPEED_ID_SANITY "MOOD_SANITY"
#define MOVESPEED_ID_PRONE_DRAGGING "PRONE_DRAG"
#define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY"
+6 -1
View File
@@ -69,4 +69,9 @@
//Flags in the players table in the db
#define DB_FLAG_EXEMPT 1
#define DEFAULT_CYBORG_NAME "Default Cyborg Name"
#define DEFAULT_CYBORG_NAME "Default Cyborg Name"
//Job preferences levels
#define JP_LOW 1
#define JP_MEDIUM 2
#define JP_HIGH 3
+2 -1
View File
@@ -25,7 +25,8 @@
#define NOBLIUM_FORMATION_ENERGY 2e9 //1 Mole of Noblium takes the planck energy to condense.
//Research point amounts
#define NOBLIUM_RESEARCH_AMOUNT 1000
#define BZ_RESEARCH_AMOUNT 150
#define BZ_RESEARCH_SCALE 4
#define BZ_RESEARCH_MAX_AMOUNT 400
#define MIASMA_RESEARCH_AMOUNT 160
#define STIMULUM_RESEARCH_AMOUNT 50
//Plasma fusion properties
+4 -1
View File
@@ -95,6 +95,8 @@
#define TRAIT_NOHUNGER "no_hunger"
#define TRAIT_EASYDISMEMBER "easy_dismember"
#define TRAIT_LIMBATTACHMENT "limb_attach"
#define TRAIT_NOLIMBDISABLE "no_limb_disable"
#define TRAIT_EASYLIMBDISABLE "easy_limb_disable"
#define TRAIT_TOXINLOVER "toxinlover"
#define TRAIT_NOBREATH "no_breath"
#define TRAIT_ANTIMAGIC "anti_magic"
@@ -118,6 +120,7 @@
#define TRAIT_LAW_ENFORCEMENT_METABOLISM "law-enforcement-metabolism"
#define TRAIT_STRONG_GRABBER "strong_grabber"
#define TRAIT_CALCIUM_HEALER "calcium_healer"
#define TRAIT_CAPTAIN_METABOLISM "captain-metabolism"
//non-mob traits
#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
@@ -203,4 +206,4 @@
#define FLIGHTSUIT_TRAIT "flightsuit"
#define LOCKED_HELMET_TRAIT "locked-helmet"
#define NINJA_SUIT_TRAIT "ninja-suit"
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
+6
View File
@@ -94,6 +94,12 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors
"Purple" = "#e300ff"//purple
))
GLOBAL_LIST_INIT(meat_types, list(
"Mammalian" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal,
"Aquatic" = /obj/item/reagent_containers/food/snacks/carpmeat/aquatic,
"Avian" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/avian,
"Inesct" = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect))
//Crew objective and miscreants stuff
GLOBAL_VAR_INIT(miscreants_allowed, FALSE)
+3
View File
@@ -81,3 +81,6 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B)
return A.totalResistance() - B.totalResistance()
/proc/cmp_job_display_asc(datum/job/A, datum/job/B)
return A.display_order - B.display_order
+25
View File
@@ -0,0 +1,25 @@
/*
Current specifications:
Donator groups in __DEFINES/donator_groupings.dm, config entries in controllers/configuration/entries/donator.dm
3 groups, Tier 1/2/3
Each tier includes the one before it (ascending)
For fast lookups, this is generated using regenerate_donator_grouping_list()
*/
/proc/is_donator_group(ckey, group)
ckey = ckey(ckey) //make sure it's ckey'd.
var/list/L = GLOB.donators_by_group[group]
return L && L.Find(ckey)
/proc/regenerate_donator_grouping_list()
GLOB.donators_by_group = list() //reinit everything
var/list/donator_list = GLOB.donators_by_group //cache
var/list/tier_1 = TIER_1_DONATORS
donator_list[DONATOR_GROUP_TIER_1] = tier_1.Copy() //The .Copy() is to "decouple"/make a new list, rather than letting the global list impact the config list.
var/list/tier_2 = tier_1 + TIER_2_DONATORS //Using + on lists implies making new lists, so we don't need to manually Copy().
donator_list[DONATOR_GROUP_TIER_2] = tier_2
var/list/tier_3 = tier_2 + TIER_3_DONATORS
donator_list[DONATOR_GROUP_TIER_3] = tier_3
+11 -2
View File
@@ -30,7 +30,8 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.r_wings_list,roundstart = TRUE)
init_sprite_accessory_subtypes(/datum/sprite_accessory/caps, GLOB.caps_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_wings, GLOB.insect_wings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_fluff, GLOB.insect_fluffs_list)
//CIT CHANGES START HERE, ADDS SNOWFLAKE BODYPARTS AND MORE
//mammal bodyparts (fucking furries)
@@ -44,6 +45,9 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
//ipcs
init_sprite_accessory_subtypes(/datum/sprite_accessory/screen, GLOB.ipc_screens_list, roundstart = TRUE)
init_sprite_accessory_subtypes(/datum/sprite_accessory/antenna, GLOB.ipc_antennas_list, roundstart = TRUE)
//genitals
init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
for(var/K in GLOB.cock_shapes_list)
@@ -53,7 +57,11 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
GLOB.breasts_size_list = list ("a", "b", "c", "d", "e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
GLOB.gentlemans_organ_names = list("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ", "cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret", "baloney pony", "schlanger")
GLOB.gentlemans_organ_names = list("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ",
"cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret",
"baloney pony", "schlanger", "Mutton dagger", "old blind bob","Hanging Johnny", "fishing rod", "Tally whacker", "polly rocket",
"One eyed trouser trout", "Ding dong", "ankle spanker", "Pork sword", "engine cranker", "Harry hot dog", "Davy Crockett",
"Kidney cracker", "Heat seeking moisture missile", "Giggle stick", "love whistle", "Tube steak", "Uncle Dick", "Purple helmet warrior")
for(var/K in GLOB.breasts_shapes_list)
var/datum/sprite_accessory/breasts/value = GLOB.breasts_shapes_list[K]
GLOB.breasts_shapes_icons[K] = value.icon_state
@@ -62,6 +70,7 @@
for(var/K in GLOB.balls_shapes_list)
var/datum/sprite_accessory/testicles/value = GLOB.balls_shapes_list[K]
GLOB.balls_shapes_icons[K] = value.icon_state
//END OF CIT CHANGES
//Species
+27 -22
View File
@@ -59,7 +59,7 @@
if(!GLOB.horns_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/horns, GLOB.horns_list)
if(!GLOB.ears_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.horns_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list)
if(!GLOB.frills_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list)
if(!GLOB.spines_list.len)
@@ -70,8 +70,10 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
if(!GLOB.wings_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
if(!GLOB.moth_wings_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
if(!GLOB.insect_wings_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_wings, GLOB.insect_wings_list)
if(!GLOB.insect_fluffs_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_fluff, GLOB.insect_fluffs_list)
//CIT CHANGES - genitals and such
if(!GLOB.cock_shapes_list.len)
@@ -130,22 +132,23 @@
//CIT CHANGE - changes this entire return to support cit's snowflake parts
return(list(
"mcolor" = color1,
"mcolor2" = color2,
"mcolor3" = color3,
"tail_lizard" = pick(GLOB.tails_list_lizard),
"tail_human" = "None",
"wings" = "None",
"snout" = pick(GLOB.snouts_list),
"horns" = pick(GLOB.horns_list),
"ears" = "None",
"frills" = pick(GLOB.frills_list),
"spines" = pick(GLOB.spines_list),
"body_markings" = pick(GLOB.body_markings_list),
"legs" = pick("Normal Legs","Digitigrade Legs"),
"caps" = pick(GLOB.caps_list),
"moth_wings" = pick(GLOB.moth_wings_list),
"taur" = "None",
"mcolor" = color1,
"mcolor2" = color2,
"mcolor3" = color3,
"tail_lizard" = pick(GLOB.tails_list_lizard),
"tail_human" = "None",
"wings" = "None",
"snout" = pick(GLOB.snouts_list),
"horns" = pick(GLOB.horns_list),
"ears" = "None",
"frills" = pick(GLOB.frills_list),
"spines" = pick(GLOB.spines_list),
"body_markings" = pick(GLOB.body_markings_list),
"legs" = pick("Plantigrade","Digitigrade"),
"caps" = pick(GLOB.caps_list),
"insect_wings" = pick(GLOB.insect_wings_list),
"insect_fluff" = "None",
"taur" = "None",
"mam_body_markings" = pick(snowflake_markings_list),
"mam_ears" = pick(snowflake_ears_list),
"mam_snouts" = pick(snowflake_mam_snouts_list),
@@ -201,9 +204,11 @@
"womb_cum_mult" = CUM_RATE_MULT,
"womb_efficiency" = CUM_EFFICIENCY,
"womb_fluid" = "femcum",
"ipc_screen" = "Sunburst",
"ipc_antenna" = "None",
"flavor_text" = ""))
"ipc_screen" = "Sunburst",
"ipc_antenna" = "None",
"flavor_text" = "",
"meat_type" = "Mammalian"
))
/proc/random_hair_style(gender)
switch(gender)
+7
View File
@@ -308,6 +308,13 @@
//ignore this comment, it fixes the broken sytax parsing caused by the " above
else
parts += "[GLOB.TAB]<i>Nobody died this shift!</i>"
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
parts += "[GLOB.TAB]Threat level: [mode.threat_level]"
parts += "[GLOB.TAB]Threat left: [mode.threat]"
parts += "[GLOB.TAB]Executed rules:"
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
parts += "[GLOB.TAB][GLOB.TAB][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost] threat"
return parts.Join("<br>")
/client/proc/roundend_report_file()
+3
View File
@@ -791,3 +791,6 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
rearranged += cword
message = "[prefix][jointext(rearranged," ")]"
. = message
#define is_alpha(X) ((text2ascii(X) <= 122) && (text2ascii(X) >= 97))
#define is_digit(X) ((length(X) == 1) && (length(text2num(X)) == 1))
+8
View File
@@ -73,3 +73,11 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
/proc/daysSince(realtimev)
return round((world.realtime - realtimev) / (24 HOURS))
/proc/worldtime2text()
return gameTimestamp("hh:mm:ss", world.time)
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
if(!wtime)
wtime = world.time
return time2text(wtime - GLOB.timezoneOffset, format)
+1
View File
@@ -1487,6 +1487,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/obj/item/reagent_containers/food/snacks/grown/nettle, // base type
/obj/item/reagent_containers/food/snacks/deepfryholder,
/obj/item/reagent_containers/food/snacks/grown/shell,
/obj/item/reagent_containers/food/snacks/clothing,
/obj/item/reagent_containers/food/snacks/store/bread
)
blocked |= typesof(/obj/item/reagent_containers/food/snacks/customizable)
+2 -1
View File
@@ -34,7 +34,8 @@ GLOBAL_LIST_EMPTY(ears_list)
GLOBAL_LIST_EMPTY(wings_list)
GLOBAL_LIST_EMPTY(wings_open_list)
GLOBAL_LIST_EMPTY(r_wings_list)
GLOBAL_LIST_EMPTY(moth_wings_list)
GLOBAL_LIST_EMPTY(insect_wings_list)
GLOBAL_LIST_EMPTY(insect_fluffs_list)
GLOBAL_LIST_EMPTY(caps_list)
GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites
+1
View File
@@ -0,0 +1 @@
GLOBAL_LIST_EMPTY(donators_by_group) //group id = donator list of ckeys
+1 -1
View File
@@ -67,7 +67,7 @@
/mob/proc/ClickOn( atom/A, params )
if(world.time <= next_click)
return
next_click = world.time + 1
next_click = world.time + world.tick_lag
if(check_click_intercept(params,A))
return
@@ -19,6 +19,7 @@
var/abstract_type = /datum/config_entry //do not instantiate if type matches this
var/vv_VAS = TRUE //Force validate and set on VV. VAS proccall guard will run regardless.
var/postload_required = FALSE //requires running OnPostload()
var/dupes_allowed = FALSE
@@ -72,6 +73,9 @@
/datum/config_entry/proc/DeprecationUpdate(value)
return
/datum/config_entry/proc/OnPostload()
return
/datum/config_entry/string
config_entry_value = ""
abstract_type = /datum/config_entry/string
@@ -80,7 +84,7 @@
/datum/config_entry/string/vv_edit_var(var_name, var_value)
return var_name != "auto_trim" && ..()
/datum/config_entry/string/ValidateAndSet(str_val)
/datum/config_entry/string/ValidateAndSet(str_val, during_load)
if(!VASProcCallGuard(str_val))
return FALSE
config_entry_value = auto_trim ? trim(str_val) : str_val
@@ -101,6 +101,7 @@
log_config("Loading config file [filename]...")
var/list/lines = world.file2list("[directory]/[filename]")
var/list/_entries = entries
var/list/postload_required = list()
for(var/L in lines)
L = trim(L)
if(!L)
@@ -157,18 +158,24 @@
else
warning("[new_ver.type] is deprecated but gave no proper return for DeprecationUpdate()")
var/validated = E.ValidateAndSet(value)
var/validated = E.ValidateAndSet(value, TRUE)
if(!validated)
log_config("Failed to validate setting \"[value]\" for [entry]")
else
if(E.modified && !E.dupes_allowed)
log_config("Duplicate setting for [entry] ([value], [E.resident_file]) detected! Using latest.")
if(E.postload_required)
postload_required[E] = TRUE
E.resident_file = filename
if(validated)
E.modified = TRUE
for(var/i in postload_required)
var/datum/config_entry/E = i
E.OnPostload()
++.
/datum/controller/configuration/can_vv_get(var_name)
@@ -0,0 +1,22 @@
/datum/config_entry/keyed_list/donator_group
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG
abstract_type = /datum/config_entry/keyed_list/donator_group
//If we're in the middle of a config load, only do the regeneration afterwards to prevent this from wasting a massive amount of CPU for list regenerations.
/datum/config_entry/keyed_list/donator_group/ValidateAndSet(str_val, during_load)
. = ..()
if(. && during_load)
regenerate_donator_grouping_list()
/datum/config_entry/keyed_list/donator_group/OnPostload()
. = ..()
regenerate_donator_grouping_list()
//This is kinda weird in that the config entries are defined here but all the handling/calculations are in __HELPERS/donator_groupings.dm
/datum/config_entry/keyed_list/donator_group/tier_1_donators
/datum/config_entry/keyed_list/donator_group/tier_2_donators
/datum/config_entry/keyed_list/donator_group/tier_3_donators
+11 -1
View File
@@ -6,7 +6,17 @@ SUBSYSTEM_DEF(assets)
var/list/preload = list()
/datum/controller/subsystem/assets/Initialize(timeofday)
for(var/type in typesof(/datum/asset))
var/list/priority_assets = list(
/datum/asset/simple/oui_theme_nano,
/datum/asset/simple/goonchat
)
for(var/type in priority_assets)
var/datum/asset/A = new type()
A.register()
for(var/type in typesof(/datum/asset) - (priority_assets | list(/datum/asset, /datum/asset/simple)))
var/datum/asset/A = type
if (type != initial(A._abstract))
get_asset_datum(type)
+2 -1
View File
@@ -23,7 +23,7 @@ SUBSYSTEM_DEF(input)
// This is for when macro sets are eventualy datumized
/datum/controller/subsystem/input/proc/setup_default_macro_sets()
var/list/static/default_macro_sets
if(default_macro_sets)
macro_sets = default_macro_sets
return
@@ -49,6 +49,7 @@ SUBSYSTEM_DEF(input)
"old_hotkeys" = list(
"Tab" = "\".winset \\\"mainwindow.macro=old_default input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"O" = "ooc",
"L" = "looc",
"T" = "say",
"M" = "me",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs
+126 -65
View File
@@ -110,13 +110,16 @@ SUBSYSTEM_DEF(job)
if(job.required_playtime_remaining(player.client))
JobDebug("FOC player not enough xp, Player: [player]")
continue
if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
JobDebug("FOC non-human failed, Player: [player]")
continue
if(flag && (!(flag in player.client.prefs.be_special)))
JobDebug("FOC flag failed, Player: [player], Flag: [flag], ")
continue
if(player.mind && job.title in player.mind.restricted_roles)
JobDebug("FOC incompatible with antagonist role, Player: [player]")
continue
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
if(player.client.prefs.job_preferences["[job.title]"] == level)
JobDebug("FOC pass, Player: [player], Level:[level]")
candidates += player
return candidates
@@ -145,6 +148,10 @@ SUBSYSTEM_DEF(job)
JobDebug("GRJ player not old enough, Player: [player]")
continue
if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
JobDebug("GRJ non-human failed, Player: [player]")
continue
if(job.required_playtime_remaining(player.client))
JobDebug("GRJ player not enough xp, Player: [player]")
continue
@@ -182,7 +189,7 @@ SUBSYSTEM_DEF(job)
if((job.current_positions >= job.total_positions) && job.total_positions != -1)
continue
var/list/candidates = FindOccupationCandidates(job, level)
if(!candidates.len)
if(!candidates?.len)
continue
var/mob/dead/new_player/candidate = pick(candidates)
if(AssignRole(candidate, command_position))
@@ -200,7 +207,7 @@ SUBSYSTEM_DEF(job)
if((job.current_positions >= job.total_positions) && job.total_positions != -1)
continue
var/list/candidates = FindOccupationCandidates(job, level)
if(!candidates.len)
if(!candidates?.len)
continue
var/mob/dead/new_player/candidate = pick(candidates)
AssignRole(candidate, command_position)
@@ -228,7 +235,7 @@ SUBSYSTEM_DEF(job)
* fills var "assigned_role" for all ready players.
* This proc must not have any side effect besides of modifying "assigned_role".
**/
/datum/controller/subsystem/job/proc/DivideOccupations()
/datum/controller/subsystem/job/proc/DivideOccupations(list/required_jobs)
//Setup new player list and get the jobs list
JobDebug("Running DO")
@@ -241,14 +248,14 @@ SUBSYSTEM_DEF(job)
//Get the players who are ready
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role)
if(player.ready == PLAYER_READY_TO_PLAY && player.check_preferences() && player.mind && !player.mind.assigned_role)
unassigned += player
initial_players_to_assign = unassigned.len
JobDebug("DO, Len: [unassigned.len]")
JobDebug("DO, Len: [unassigned?.len]")
if(unassigned.len == 0)
return 0
return validate_required_jobs(required_jobs)
//Scale number of open security officer slots to population
setup_officer_positions()
@@ -269,8 +276,8 @@ SUBSYSTEM_DEF(job)
//People who wants to be the overflow role, sure, go on.
JobDebug("DO, Running Overflow Check 1")
var/datum/job/overflow = GetJob(SSjob.overflow_role)
var/list/overflow_candidates = FindOccupationCandidates(overflow, 3)
JobDebug("AC1, Candidates: [overflow_candidates.len]")
var/list/overflow_candidates = FindOccupationCandidates(overflow, JP_LOW)
JobDebug("AC1, Candidates: [overflow_candidates?.len]")
for(var/mob/dead/new_player/player in overflow_candidates)
JobDebug("AC1 pass, Player: [player]")
AssignRole(player, SSjob.overflow_role)
@@ -297,7 +304,8 @@ SUBSYSTEM_DEF(job)
// Loop through all levels from high to low
var/list/shuffledoccupations = shuffle(occupations)
for(var/level = 1 to 3)
var/list/levels = list(JP_HIGH,JP_MEDIUM,JP_LOW)
for(var/level in levels)
//Check the head jobs first each level
CheckHeadPositions(level)
@@ -326,13 +334,17 @@ SUBSYSTEM_DEF(job)
if(job.required_playtime_remaining(player.client))
JobDebug("DO player not enough xp, Player: [player], Job:[job.title]")
continue
if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
JobDebug("DO non-human failed, Player: [player], Job:[job.title]")
continue
if(player.mind && job.title in player.mind.restricted_roles)
JobDebug("DO incompatible with antagonist role, Player: [player], Job:[job.title]")
continue
// If the player wants that job on this level, then try give it to him.
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
if(player.client.prefs.job_preferences["[job.title]"] == level)
// If the job isn't filled
if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1)
JobDebug("DO pass, Player: [player], Level:[level], Job:[job.title]")
@@ -351,9 +363,28 @@ SUBSYSTEM_DEF(job)
//Mop up people who can't leave.
for(var/mob/dead/new_player/player in unassigned) //Players that wanted to back out but couldn't because they're antags (can you feel the edge case?)
if(!GiveRandomJob(player))
AssignRole(player, SSjob.overflow_role) //If everything is already filled, make them an assistant
if(!AssignRole(player, SSjob.overflow_role)) //If everything is already filled, make them an assistant
return FALSE //Living on the edge, the forced antagonist couldn't be assigned to overflow role (bans, client age) - just reroll
return 1
return validate_required_jobs(required_jobs)
/datum/controller/subsystem/job/proc/validate_required_jobs(list/required_jobs)
if(!required_jobs.len)
return TRUE
for(var/required_group in required_jobs)
var/group_ok = TRUE
for(var/rank in required_group)
var/datum/job/J = GetJob(rank)
if(!J)
SSticker.mode.setup_error = "Invalid job [rank] in gamemode required jobs."
return FALSE
if(J.current_positions < required_group[rank])
group_ok = FALSE
break
if(group_ok)
return TRUE
SSticker.mode.setup_error = "Required jobs not present."
return FALSE
//We couldn't find a job from prefs for this guy.
/datum/controller/subsystem/job/proc/HandleUnassigned(mob/dead/new_player/player)
@@ -406,7 +437,7 @@ SUBSYSTEM_DEF(job)
if(length(GLOB.jobspawn_overrides[rank]))
S = pick(GLOB.jobspawn_overrides[rank])
if(S)
SendToAtom(H, S, buckle = FALSE)
S.JoinPlayerHere(H, FALSE)
if(!S) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper
log_world("Couldn't find a round start spawn point for [rank]")
SendToLateJoin(H)
@@ -418,7 +449,7 @@ SUBSYSTEM_DEF(job)
if(job)
if(!job.dresscodecompliant)// CIT CHANGE - dress code compliance
equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items
var/new_mob = job.equip(H, null, null, joined_late)
var/new_mob = job.equip(H, null, null, joined_late , null, M.client)
if(ismob(new_mob))
H = new_mob
if(!joined_late)
@@ -428,12 +459,18 @@ SUBSYSTEM_DEF(job)
SSpersistence.antag_rep_change[M.client.ckey] += job.GetAntagRep()
/* if(M.client.holder)
if(CONFIG_GET(flag/auto_deadmin_players) || (M.client.prefs?.toggles & DEADMIN_ALWAYS))
M.client.holder.auto_deadmin()
else
handle_auto_deadmin_roles(M.client, rank) */
to_chat(M, "<b>You are the [rank].</b>")
if(job)
to_chat(M, "<b>As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.</b>")
to_chat(M, "<b>To speak on your departments radio, use the :h button. To see others, look closely at your headset.</b>")
job.radio_help_message(M)
if(job.req_admin_notify)
to_chat(M, "<b>You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.</b>")
to_chat(M, "<b>You are playing a job that is important for Game Progression. If you have to disconnect immediately, please notify the admins via adminhelp. Otherwise put your locker gear back into the locker and cryo out.</b>")
if(job.custom_spawn_text)
to_chat(M, "<b>[job.custom_spawn_text]</b>")
if(CONFIG_GET(number/minimal_access_threshold))
@@ -446,12 +483,24 @@ SUBSYSTEM_DEF(job)
equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works
return H
/*
/datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank)
if(!C?.holder)
return TRUE
var/datum/job/job = GetJob(rank)
if(!job)
return
if((job.auto_deadmin_role_flags & DEADMIN_POSITION_HEAD) && (CONFIG_GET(flag/auto_deadmin_heads) || (C.prefs?.toggles & DEADMIN_POSITION_HEAD)))
return C.holder.auto_deadmin()
else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SECURITY) && (CONFIG_GET(flag/auto_deadmin_security) || (C.prefs?.toggles & DEADMIN_POSITION_SECURITY)))
return C.holder.auto_deadmin()
else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SILICON) && (CONFIG_GET(flag/auto_deadmin_silicons) || (C.prefs?.toggles & DEADMIN_POSITION_SILICON))) //in the event there's ever psuedo-silicon roles added, ie synths.
return C.holder.auto_deadmin()*/
/datum/controller/subsystem/job/proc/setup_officer_positions()
var/datum/job/J = SSjob.GetJob("Security Officer")
if(!J)
throw EXCEPTION("setup_officer_positions(): Security officer job is missing")
CRASH("setup_officer_positions(): Security officer job is missing")
var/ssc = CONFIG_GET(number/security_scaling_coeff)
if(ssc > 0)
@@ -502,13 +551,15 @@ SUBSYSTEM_DEF(job)
if(job.required_playtime_remaining(player.client))
young++
continue
if(player.client.prefs.GetJobDepartment(job, 1) & job.flag)
high++
else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag)
medium++
else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag)
low++
else never++ //not selected
switch(player.client.prefs.job_preferences["[job.title]"])
if(JP_HIGH)
high++
if(JP_MEDIUM)
medium++
if(JP_LOW)
low++
else
never++
SSblackbox.record_feedback("nested tally", "job_preferences", high, list("[job.title]", "high"))
SSblackbox.record_feedback("nested tally", "job_preferences", medium, list("[job.title]", "medium"))
SSblackbox.record_feedback("nested tally", "job_preferences", low, list("[job.title]", "low"))
@@ -551,51 +602,61 @@ SUBSYSTEM_DEF(job)
newjob.spawn_positions = J.spawn_positions
newjob.current_positions = J.current_positions
/datum/controller/subsystem/job/proc/SendToAtom(mob/M, atom/A, buckle)
if(buckle && isliving(M) && istype(A, /obj/structure/chair))
var/obj/structure/chair/C = A
if(C.buckle_mob(M, FALSE, FALSE))
return
M.forceMove(get_turf(A))
/atom/proc/JoinPlayerHere(mob/M, buckle)
// By default, just place the mob on the same turf as the marker or whatever.
M.forceMove(get_turf(src))
/obj/structure/chair/JoinPlayerHere(mob/M, buckle)
// Placing a mob in a chair will attempt to buckle it, or else fall back to default.
if (buckle && isliving(M) && buckle_mob(M, FALSE, FALSE))
return
..()
/datum/controller/subsystem/job/proc/SendToLateJoin(mob/M, buckle = TRUE)
var/atom/destination
if(M.mind && M.mind.assigned_role && length(GLOB.jobspawn_overrides[M.mind.assigned_role])) //We're doing something special today.
SendToAtom(M,pick(GLOB.jobspawn_overrides[M.mind.assigned_role]),FALSE)
destination = pick(GLOB.jobspawn_overrides[M.mind.assigned_role])
destination.JoinPlayerHere(M, FALSE)
return
if(latejoin_trackers.len)
SendToAtom(M, pick(latejoin_trackers), buckle)
else
//bad mojo
var/area/shuttle/arrival/A = GLOB.areas_by_type[/area/shuttle/arrival]
if(A)
//first check if we can find a chair
var/obj/structure/chair/C = locate() in A
if(C)
SendToAtom(M, C, buckle)
return
else //last hurrah
var/list/avail = list()
for(var/turf/T in A)
if(!is_blocked_turf(T, TRUE))
avail += T
if(avail.len)
SendToAtom(M, pick(avail), FALSE)
return
destination = pick(latejoin_trackers)
destination.JoinPlayerHere(M, buckle)
return
//pick an open spot on arrivals and dump em
var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival))
if(arrivals_turfs.len)
for(var/turf/T in arrivals_turfs)
if(!is_blocked_turf(T, TRUE))
SendToAtom(M, T, FALSE)
return
//last chance, pick ANY spot on arrivals and dump em
SendToAtom(M, arrivals_turfs[1], FALSE)
else
var/msg = "Unable to send mob [M] to late join!"
message_admins(msg)
CRASH(msg)
//bad mojo
var/area/shuttle/arrival/A = GLOB.areas_by_type[/area/shuttle/arrival]
if(A)
//first check if we can find a chair
var/obj/structure/chair/C = locate() in A
if(C)
C.JoinPlayerHere(M, buckle)
return
//last hurrah
var/list/avail = list()
for(var/turf/T in A)
if(!is_blocked_turf(T, TRUE))
avail += T
if(avail.len)
destination = pick(avail)
destination.JoinPlayerHere(M, FALSE)
return
//pick an open spot on arrivals and dump em
var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival))
if(arrivals_turfs.len)
for(var/turf/T in arrivals_turfs)
if(!is_blocked_turf(T, TRUE))
T.JoinPlayerHere(M, FALSE)
return
//last chance, pick ANY spot on arrivals and dump em
destination = arrivals_turfs[1]
destination.JoinPlayerHere(M, FALSE)
else
var/msg = "Unable to send mob [M] to late join!"
message_admins(msg)
CRASH(msg)
///////////////////////////////////
@@ -637,4 +698,4 @@ SUBSYSTEM_DEF(job)
. |= player.mind
/datum/controller/subsystem/job/proc/JobDebug(message)
log_job_debug(message)
log_job_debug(message)
+1 -1
View File
@@ -255,7 +255,7 @@ SUBSYSTEM_DEF(ticker)
var/can_continue = 0
can_continue = src.mode.pre_setup() //Choose antagonists
CHECK_TICK
SSjob.DivideOccupations() //Distribute jobs
can_continue = can_continue && SSjob.DivideOccupations(mode.required_jobs) //Distribute jobs
CHECK_TICK
if(!GLOB.Debug2)
+107 -107
View File
@@ -1,108 +1,108 @@
/datum/component/footstep
var/steps = 0
var/volume
var/e_range
/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
volume = volume_
e_range = e_range_
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep)
/datum/component/footstep/proc/play_footstep()
var/turf/open/T = get_turf(parent)
if(!istype(T))
return
var/mob/living/LM = parent
var/v = volume
var/e = e_range
if(!T.footstep || LM.buckled || LM.lying || !LM.canmove || LM.resting || LM.buckled || LM.throwing || LM.movement_type & (VENTCRAWLING | FLYING))
if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
return
if(HAS_TRAIT(LM, TRAIT_SILENT_STEP))
return
if(iscarbon(LM))
var/mob/living/carbon/C = LM
if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG))
return
if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK)
v /= 2
e -= 5
steps++
if(steps >= 3)
steps = 0
else
return
if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around
return
//begin playsound shenanigans//
//for barefooted non-clawed mobs like monkeys
if(isbarefoot(LM))
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
GLOB.barefootstep[T.barefootstep][2] * v,
TRUE,
GLOB.barefootstep[T.barefootstep][3] + e)
return
//for xenomorphs, dogs, and other clawed mobs
if(isclawfoot(LM))
if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps
v /= 3
e -= 5
playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]),
GLOB.clawfootstep[T.clawfootstep][2] * v,
TRUE,
GLOB.clawfootstep[T.clawfootstep][3] + e)
return
//for megafauna and other large and imtimidating mobs such as the bloodminer
if(isheavyfoot(LM))
playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]),
GLOB.heavyfootstep[T.heavyfootstep][2] * v,
TRUE,
GLOB.heavyfootstep[T.heavyfootstep][3] + e)
return
//for slimes
if(isslime(LM))
playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v)
return
//for (simple) humanoid mobs (clowns, russians, pirates, etc.)
if(isshoefoot(LM))
if(!ishuman(LM))
playsound(T, pick(GLOB.footstep[T.footstep][1]),
GLOB.footstep[T.footstep][2] * v,
TRUE,
GLOB.footstep[T.footstep][3] + e)
return
if(ishuman(LM)) //for proper humans, they're special
var/mob/living/carbon/human/H = LM
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
return
if(H.shoes || feetCover) //are we wearing shoes
playsound(T, pick(GLOB.footstep[T.footstep][1]),
GLOB.footstep[T.footstep][2] * v,
TRUE,
GLOB.footstep[T.footstep][3] + e)
if((!H.shoes && !feetCover)) //are we NOT wearing shoes
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
GLOB.barefootstep[T.barefootstep][2] * v,
TRUE,
/datum/component/footstep
var/steps = 0
var/volume
var/e_range
/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
volume = volume_
e_range = e_range_
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep)
/datum/component/footstep/proc/play_footstep()
var/turf/open/T = get_turf(parent)
if(!istype(T))
return
var/mob/living/LM = parent
var/v = volume
var/e = e_range
if(!T.footstep || LM.buckled || LM.lying || !LM.canmove || LM.resting || LM.buckled || LM.throwing || LM.movement_type & (VENTCRAWLING | FLYING))
if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
return
if(HAS_TRAIT(LM, TRAIT_SILENT_STEP))
return
if(iscarbon(LM))
var/mob/living/carbon/C = LM
if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG))
return
if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK)
v /= 2
e -= 5
steps++
if(steps >= 3)
steps = 0
else
return
if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around
return
//begin playsound shenanigans//
//for barefooted non-clawed mobs like monkeys
if(isbarefoot(LM))
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
GLOB.barefootstep[T.barefootstep][2] * v,
TRUE,
GLOB.barefootstep[T.barefootstep][3] + e)
return
//for xenomorphs, dogs, and other clawed mobs
if(isclawfoot(LM))
if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps
v /= 3
e -= 5
playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]),
GLOB.clawfootstep[T.clawfootstep][2] * v,
TRUE,
GLOB.clawfootstep[T.clawfootstep][3] + e)
return
//for megafauna and other large and imtimidating mobs such as the bloodminer
if(isheavyfoot(LM))
playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]),
GLOB.heavyfootstep[T.heavyfootstep][2] * v,
TRUE,
GLOB.heavyfootstep[T.heavyfootstep][3] + e)
return
//for slimes
if(isslime(LM))
playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v)
return
//for (simple) humanoid mobs (clowns, russians, pirates, etc.)
if(isshoefoot(LM))
if(!ishuman(LM))
playsound(T, pick(GLOB.footstep[T.footstep][1]),
GLOB.footstep[T.footstep][2] * v,
TRUE,
GLOB.footstep[T.footstep][3] + e)
return
if(ishuman(LM)) //for proper humans, they're special
var/mob/living/carbon/human/H = LM
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
return
if(H.shoes || feetCover) //are we wearing shoes
playsound(T, pick(GLOB.footstep[T.footstep][1]),
GLOB.footstep[T.footstep][2] * v,
TRUE,
GLOB.footstep[T.footstep][3] + e)
if((!H.shoes && !feetCover)) //are we NOT wearing shoes
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
GLOB.barefootstep[T.barefootstep][2] * v,
TRUE,
GLOB.barefootstep[T.barefootstep][3] + e)
+37 -8
View File
@@ -195,21 +195,47 @@
. = ..()
RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
/datum/component/riding/human/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
var/mob/living/carbon/human/H = parent
H.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING)
. = ..()
/datum/component/riding/human/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
. = ..()
var/mob/living/carbon/human/H = parent
H.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = HUMAN_CARRY_SLOWDOWN)
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
var/mob/living/carbon/human/AM = parent
if(AM.a_intent == INTENT_DISARM && (target in AM.buckled_mobs))
var/mob/living/carbon/human/H = parent
if(H.a_intent == INTENT_DISARM && (target in H.buckled_mobs))
force_dismount(target)
/datum/component/riding/human/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
for(var/mob/M in AM.buckled_mobs) //ensure proper layering of piggyback and carry, sometimes weird offsets get applied
M.layer = MOB_LAYER
if(!AM.buckle_lying)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
AM.layer = OBJ_LAYER
if(AM.dir == NORTH)
AM.layer = OBJ_LAYER
else
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/human/get_offsets(pass_index)
var/mob/living/carbon/human/H = parent
if(H.buckle_lying)
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(0, 6), TEXT_WEST = list(0, 6))
else
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4))
/datum/component/riding/human/force_dismount(mob/living/user)
var/atom/movable/AM = parent
AM.unbuckle_mob(user)
@@ -273,12 +299,15 @@
M.throw_at(target, 14, 5, AM)
M.Knockdown(60)
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1)
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1, riding_target_override = null)
var/atom/movable/AM = parent
var/amount_equipped = 0
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
var/obj/item/riding_offhand/inhand = new /obj/item/riding_offhand(user)
inhand.rider = user
if(!riding_target_override)
inhand.rider = user
else
inhand.rider = riding_target_override
inhand.parent = AM
if(user.put_in_hands(inhand, TRUE))
amount_equipped++
@@ -318,7 +347,7 @@
. = ..()
/obj/item/riding_offhand/equipped()
if(loc != rider)
if(loc != rider && loc != parent)
selfdeleting = TRUE
qdel(src)
. = ..()
@@ -36,3 +36,4 @@
/datum/component/storage/concrete/emergency/proc/unlock_me(datum/source)
if(locked)
set_locked(source, FALSE)
return TRUE
@@ -52,7 +52,7 @@
. = ..()
cant_hold = typecacheof(list(/obj/item/screwdriver/power))
can_hold = typecacheof(list(
/obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen,
/obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, /obj/item/melee/cultblade/dagger,
/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,
@@ -63,7 +63,7 @@
. = ..()
cant_hold = typecacheof(list(/obj/item/screwdriver/power))
can_hold = typecacheof(list(
/obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen,
/obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, /obj/item/melee/cultblade/dagger,
/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,
+3 -3
View File
@@ -21,8 +21,8 @@
/datum/ert/amber
code = "Amber"
leader_role = /datum/antagonist/ert/commander/red
roles = list(/datum/antagonist/ert/security/red, /datum/antagonist/ert/medic/red, /datum/antagonist/ert/engineer/red)
leader_role = /datum/antagonist/ert/commander/amber
roles = list(/datum/antagonist/ert/security/amber, /datum/antagonist/ert/medic/amber, /datum/antagonist/ert/engineer/amber)
/datum/ert/red
leader_role = /datum/antagonist/ert/commander/red
@@ -61,7 +61,7 @@
teamsize = 1
opendoors = FALSE
enforce_human = FALSE
roles = /datum/antagonist/greybois
roles = list(/datum/antagonist/greybois)
leader_role = /datum/antagonist/greybois/greygod
rename_team = "Emergency Assistants"
polldesc = "an Emergency Assistant"
+1 -1
View File
@@ -18,7 +18,7 @@
var/map_file = "BoxStation.dmm"
var/traits = null
var/space_ruin_levels = 1 //Citadel edit - reduces the default space ruin z-level count to 1
var/space_ruin_levels = 2
var/space_empty_levels = 1
var/minetype = "lavaland"
+8
View File
@@ -21,6 +21,7 @@
var/l_hand = null
var/internals_slot = null //ID of slot containing a gas tank
var/list/backpack_contents = null // In the list(path=count,otherpath=count) format
var/box // Internals box. Will be inserted at the start of backpack_contents
var/list/implants = null
var/accessory = null
@@ -83,6 +84,13 @@
H.equip_to_slot_or_del(new l_pocket(H),SLOT_L_STORE)
if(r_pocket)
H.equip_to_slot_or_del(new r_pocket(H),SLOT_R_STORE)
if(box)
if(!backpack_contents)
backpack_contents = list()
backpack_contents.Insert(1, box)
backpack_contents[box] = 1
if(backpack_contents)
for(var/path in backpack_contents)
var/number = backpack_contents[path]
+2 -1
View File
@@ -170,7 +170,7 @@
tick_interval = 4
alert_type = /obj/screen/alert/status_effect/his_grace
var/bloodlust = 0
/obj/screen/alert/status_effect/his_grace
name = "His Grace"
desc = "His Grace hungers, and you must feed Him."
@@ -208,6 +208,7 @@
owner.adjustToxLoss(-grace_heal, TRUE, TRUE)
owner.adjustOxyLoss(-(grace_heal * 2))
owner.adjustCloneLoss(-grace_heal)
owner.adjustStaminaLoss(-(grace_heal * 25))
/datum/status_effect/his_grace/on_remove()
owner.log_message("lost His Grace's stun immunity", LOG_ATTACK)
+1 -1
View File
@@ -379,7 +379,7 @@
SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume)
/atom/proc/emag_act()
SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
/atom/proc/rad_act(strength)
SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, strength)
+1 -1
View File
@@ -6,7 +6,7 @@
name = "traitor+brothers"
config_tag = "traitorbro"
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Research Director")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
announce_span = "danger"
announce_text = "There are Syndicate agents and Blood Brothers on the station!\n\
+1 -1
View File
@@ -135,7 +135,7 @@ Credit where due:
required_enemies = 3
recommended_enemies = 5
enemy_minimum_age = 7
protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain") //Silicons can eventually be converted
protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //Silicons can eventually be converted
restricted_jobs = list("Chaplain", "Captain")
announce_span = "brass"
announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\
+2 -2
View File
@@ -35,8 +35,8 @@
config_tag = "cult"
antag_flag = ROLE_CULTIST
false_report_weight = 10
restricted_jobs = list("Chaplain","AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel")
protected_jobs = list()
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 30
required_enemies = 3
recommended_enemies = 5
+750
View File
@@ -0,0 +1,750 @@
#define CURRENT_LIVING_PLAYERS 1
#define CURRENT_LIVING_ANTAGS 2
#define CURRENT_DEAD_PLAYERS 3
#define CURRENT_OBSERVERS 4
#define ONLY_RULESET 1
#define HIGHLANDER_RULESET 2
#define TRAITOR_RULESET 4
#define MINOR_RULESET 8
#define RULESET_STOP_PROCESSING 1
// -- Injection delays
GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (5 MINUTES))
GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (25 MINUTES))
GLOBAL_VAR_INIT(dynamic_midround_delay_min, (15 MINUTES))
GLOBAL_VAR_INIT(dynamic_midround_delay_max, (35 MINUTES))
// Are HIGHLANDER_RULESETs allowed to stack?
GLOBAL_VAR_INIT(dynamic_no_stacking, TRUE)
// A number between -5 and +5.
// A negative value will give a more peaceful round and
// a positive value will give a round with higher threat.
GLOBAL_VAR_INIT(dynamic_curve_centre, 0)
// A number between 0.5 and 4.
// Higher value will favour extreme rounds and
// lower value rounds closer to the average.
GLOBAL_VAR_INIT(dynamic_curve_width, 1.8)
// If enabled only picks a single starting rule and executes only autotraitor midround ruleset.
GLOBAL_VAR_INIT(dynamic_classic_secret, FALSE)
// How many roundstart players required for high population override to take effect.
GLOBAL_VAR_INIT(dynamic_high_pop_limit, 55)
// If enabled does not accept or execute any rulesets.
GLOBAL_VAR_INIT(dynamic_forced_extended, FALSE)
// How high threat is required for HIGHLANDER_RULESETs stacking.
// This is independent of dynamic_no_stacking.
GLOBAL_VAR_INIT(dynamic_stacking_limit, 90)
// List of forced roundstart rulesets.
GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset)
// Forced threat level, setting this to zero or higher forces the roundstart threat to the value.
GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
/datum/game_mode/dynamic
name = "dynamic mode"
config_tag = "dynamic"
announce_span = "danger"
announce_text = "Dynamic mode!" // This needs to be changed maybe
reroll_friendly = FALSE;
// Threat logging vars
/// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations
var/threat_level = 0
/// Set at the beginning of the round. Spent by the mode to "purchase" rules.
var/threat = 0
/// Running information about the threat. Can store text or datum entries.
var/list/threat_log = list()
/// List of roundstart rules used for selecting the rules.
var/list/roundstart_rules = list()
/// List of latejoin rules used for selecting the rules.
var/list/latejoin_rules = list()
/// List of midround rules used for selecting the rules.
var/list/midround_rules = list()
/** # Pop range per requirement.
* If the value is five the range is:
* 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+
* If it is six the range is:
* 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+
* If it is seven the range is:
* 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+
*/
var/pop_per_requirement = 6
/// The requirement used for checking if a second rule should be selected.
var/list/second_rule_req = list(100, 100, 80, 70, 60, 50, 30, 20, 10, 0)
/// The requirement used for checking if a third rule should be selected.
var/list/third_rule_req = list(100, 100, 100, 90, 80, 70, 60, 50, 40, 30)
/// Threat requirement for a second ruleset when high pop override is in effect.
var/high_pop_second_rule_req = 40
/// Threat requirement for a third ruleset when high pop override is in effect.
var/high_pop_third_rule_req = 60
/// Number of players who were ready on roundstart.
var/roundstart_pop_ready = 0
/// List of candidates used on roundstart rulesets.
var/list/candidates = list()
/// Rules that are processed, rule_process is called on the rules in this list.
var/list/current_rules = list()
/// List of executed rulesets.
var/list/executed_rules = list()
/// Associative list of current players, in order: living players, living antagonists, dead players and observers.
var/list/list/current_players = list(CURRENT_LIVING_PLAYERS, CURRENT_LIVING_ANTAGS, CURRENT_DEAD_PLAYERS, CURRENT_OBSERVERS)
/// When world.time is over this number the mode tries to inject a latejoin ruleset.
var/latejoin_injection_cooldown = 0
/// When world.time is over this number the mode tries to inject a midround ruleset.
var/midround_injection_cooldown = 0
/// When TRUE GetInjectionChance returns 100.
var/forced_injection = FALSE
/// Forced ruleset to be executed for the next latejoin.
var/datum/dynamic_ruleset/latejoin/forced_latejoin_rule = null
/// When current_players was updated last time.
var/pop_last_updated = 0
/// How many percent of the rounds are more peaceful.
var/peaceful_percentage = 50
/// If a highlander executed.
var/highlander_executed = FALSE
/// If a only ruleset has been executed.
var/only_ruleset_executed = FALSE
/datum/game_mode/dynamic/admin_panel()
var/list/dat = list("<html><head><title>Game Mode Panel</title></head><body><h1><B>Game Mode Panel</B></h1>")
dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</A><BR>"
dat += "Threat Level: <b>[threat_level]</b><br/>"
dat += "Threat to Spend: <b>[threat]</b> <a href='?src=\ref[src];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=\ref[src];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>"
dat += "<br/>"
dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].<br/>"
dat += "<i>On average, <b>[peaceful_percentage]</b>% of the rounds are more peaceful.</i><br/>"
dat += "Forced extended: <a href='?src=\ref[src];[HrefToken()];forced_extended=1'><b>[GLOB.dynamic_forced_extended ? "On" : "Off"]</b></a><br/>"
dat += "Classic secret (only autotraitor): <a href='?src=\ref[src];[HrefToken()];classic_secret=1'><b>[GLOB.dynamic_classic_secret ? "On" : "Off"]</b></a><br/>"
dat += "No stacking (only one round-ender): <a href='?src=\ref[src];[HrefToken()];no_stacking=1'><b>[GLOB.dynamic_no_stacking ? "On" : "Off"]</b></a><br/>"
dat += "Stacking limit: [GLOB.dynamic_stacking_limit] <a href='?src=\ref[src];[HrefToken()];stacking_limit=1'>\[Adjust\]</A>"
dat += "<br/>"
dat += "Executed rulesets: "
if (executed_rules.len > 0)
dat += "<br/>"
for (var/datum/dynamic_ruleset/DR in executed_rules)
dat += "[DR.ruletype] - <b>[DR.name]</b><br>"
else
dat += "none.<br>"
dat += "<br>Injection Timers: (<b>[get_injection_chance(TRUE)]%</b> chance)<BR>"
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
/datum/game_mode/dynamic/Topic(href, href_list)
if (..()) // Sanity, maybe ?
return
if(!check_rights(R_ADMIN))
message_admins("[usr.key] has attempted to override the game mode panel!")
log_admin("[key_name(usr)] tried to use the game mode panel without authorization.")
return
if (href_list["forced_extended"])
GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended
else if (href_list["no_stacking"])
GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking
else if (href_list["classic_secret"])
GLOB.dynamic_classic_secret = !GLOB.dynamic_classic_secret
else if (href_list["adjustthreat"])
var/threatadd = input("Specify how much threat to add (negative to subtract). This can inflate the threat level.", "Adjust Threat", 0) as null|num
if(!threatadd)
return
if(threatadd > 0)
create_threat(threatadd)
else
spend_threat(-threatadd)
else if (href_list["injectlate"])
latejoin_injection_cooldown = 0
forced_injection = TRUE
message_admins("[key_name(usr)] forced a latejoin injection.", 1)
else if (href_list["injectmid"])
midround_injection_cooldown = 0
forced_injection = TRUE
message_admins("[key_name(usr)] forced a midround injection.", 1)
else if (href_list["threatlog"])
show_threatlog(usr)
else if (href_list["stacking_limit"])
GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num
admin_panel() // Refreshes the window
// Checks if there are HIGHLANDER_RULESETs and calls the rule's round_result() proc
/datum/game_mode/dynamic/set_round_result()
for(var/datum/dynamic_ruleset/rule in executed_rules)
if(rule.flags & HIGHLANDER_RULESET)
if(rule.check_finished()) // Only the rule that actually finished the round sets round result.
return rule.round_result()
// If it got to this part, just pick one highlander if it exists
for(var/datum/dynamic_ruleset/rule in executed_rules)
if(rule.flags & HIGHLANDER_RULESET)
return rule.round_result()
return ..()
/datum/game_mode/dynamic/send_intercept()
. = "<b><i>Central Command Status Summary</i></b><hr>"
switch(round(threat_level))
if(0 to 19)
update_playercounts()
if(!current_players[CURRENT_LIVING_ANTAGS].len)
. += "<b>Peaceful Waypoint</b></center><BR>"
. += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive."
else
. += "<b>Core Territory</b></center><BR>"
. += "Your station orbits within reliably mundane, secure space. Although Nanotrasen has a firm grip on security in your region, the valuable resources and strategic position aboard your station make it a potential target for infiltrations. Monitor crew for non-loyal behavior, but expect a relatively tame shift free of large-scale destruction. We expect great things from your station."
if(20 to 39)
. += "<b>Anomalous Exogeology</b></center><BR>"
. += "Although your station lies within what is generally considered Nanotrasen-controlled space, the course of its orbit has caused it to cross unusually close to exogeological features with anomalous readings. Although these features offer opportunities for our research department, it is known that these little understood readings are often correlated with increased activity from competing interstellar organizations and individuals, among them the Wizard Federation and Cult of the Geometer of Blood - all known competitors for Anomaly Type B sites. Exercise elevated caution."
if(40 to 65)
. += "<b>Contested System</b></center><BR>"
. += "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt."
if(66 to 79)
. += "<b>Uncharted Space</b></center><BR>"
. += "Congratulations and thank you for participating in the NT 'Frontier' space program! Your station is actively orbiting a high value system far from the nearest support stations. Little is known about your region of space, and the opportunity to encounter the unknown invites greater glory. You are encouraged to elevate security as necessary to protect Nanotrasen assets."
if(80 to 99)
. += "<b>Black Orbit</b></center><BR>"
. += "As part of a mandatory security protocol, we are required to inform you that as a result of your orbital pattern directly behind an astrological body (oriented from our nearest observatory), your station will be under decreased monitoring and support. It is anticipated that your extreme location and decreased surveillance could pose security risks. Avoid unnecessary risks and attempt to keep your station in one piece."
if(100)
. += "<b>Impending Doom</b></center><BR>"
. += "Your station is somehow in the middle of hostile territory, in clear view of any enemy of the corporation. Your likelihood to survive is low, and station destruction is expected and almost inevitable. Secure any sensitive material and neutralize any enemy you will come across. It is important that you at least try to maintain the station.<BR>"
. += "Good luck."
if(station_goals.len)
. += "<hr><b>Special Orders for [station_name()]:</b>"
for(var/datum/station_goal/G in station_goals)
G.on_report()
. += G.get_report()
print_command_report(., "Central Command Status Summary", announce=FALSE)
priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", 'sound/ai/intercept.ogg')
if(GLOB.security_level < SEC_LEVEL_BLUE)
set_security_level(SEC_LEVEL_BLUE)
// Yes, this is copy pasted from game_mode
/datum/game_mode/dynamic/check_finished(force_ending)
if(!SSticker.setup_done || !gamemode_ready)
return FALSE
if(replacementmode && round_converted == 2)
return replacementmode.check_finished()
if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME))
return TRUE
if(station_was_nuked)
return TRUE
if(force_ending)
return TRUE
for(var/datum/dynamic_ruleset/rule in executed_rules)
if(rule.flags & HIGHLANDER_RULESET)
return rule.check_finished()
/datum/game_mode/dynamic/proc/show_threatlog(mob/admin)
if(!SSticker.HasRoundStarted())
alert("The round hasn't started yet!")
return
if(!check_rights(R_ADMIN))
return
var/list/out = list("<TITLE>Threat Log</TITLE><B><font size='3'>Threat Log</font></B><br><B>Starting Threat:</B> [threat_level]<BR>")
for(var/entry in threat_log)
if(istext(entry))
out += "[entry]<BR>"
out += "<B>Remaining threat/threat_level:</B> [threat]/[threat_level]"
usr << browse(out.Join(), "window=threatlog;size=700x500")
/// Generates the threat level using lorentz distribution and assigns peaceful_percentage.
/datum/game_mode/dynamic/proc/generate_threat()
var/relative_threat = LORENTZ_DISTRIBUTION(GLOB.dynamic_curve_centre, GLOB.dynamic_curve_width)
threat_level = round(lorentz_to_threat(relative_threat), 0.1)
peaceful_percentage = round(LORENTZ_CUMULATIVE_DISTRIBUTION(relative_threat, GLOB.dynamic_curve_centre, GLOB.dynamic_curve_width), 0.01)*100
threat = threat_level
/datum/game_mode/dynamic/can_start()
/* Disabled for now, had some changes that need to be tested and this might interfere with that.
if(GLOB.dynamic_curve_centre == 0)
// 10 is when the centre starts to decrease
// 6 is just 1 + 5 (from the maximum value and the one decreased)
// 1 just makes the curve look better, I don't know.
// Limited between 1 and 5 then inverted and rounded
// With this you get a centre curve that stays at -5 until 10 then first rapidly decreases but slows down at the end
GLOB.dynamic_curve_centre = round(-CLAMP((10*6/GLOB.player_list.len)-1, 0, 5), 0.5)
*/
message_admins("Dynamic mode parameters for the round:")
message_admins("Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].")
message_admins("Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].")
log_game("DYNAMIC: Dynamic mode parameters for the round:")
log_game("DYNAMIC: Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].")
log_game("DYNAMIC: Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].")
if(GLOB.dynamic_forced_threat_level >= 0)
threat_level = round(GLOB.dynamic_forced_threat_level, 0.1)
threat = threat_level
else
generate_threat()
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time
message_admins("Dynamic Mode initialized with a Threat Level of... [threat_level]!")
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
return TRUE
/datum/game_mode/dynamic/pre_setup()
for (var/rule in subtypesof(/datum/dynamic_ruleset))
var/datum/dynamic_ruleset/ruleset = new rule()
// Simple check if the ruleset should be added to the lists.
if(ruleset.name == "")
continue
switch(ruleset.ruletype)
if("Roundstart")
roundstart_rules += ruleset
if ("Latejoin")
latejoin_rules += ruleset
if ("Midround")
if (ruleset.weight)
midround_rules += ruleset
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
roundstart_pop_ready++
candidates.Add(player)
log_game("DYNAMIC: Listing [roundstart_rules.len] round start rulesets, and [candidates.len] players ready.")
if (candidates.len <= 0)
return TRUE
if (roundstart_rules.len <= 0)
return TRUE
if(GLOB.dynamic_forced_roundstart_ruleset.len > 0)
rigged_roundstart()
else
roundstart()
var/starting_rulesets = ""
for (var/datum/dynamic_ruleset/roundstart/DR in executed_rules)
starting_rulesets += "[DR.name], "
candidates.Cut()
return TRUE
/datum/game_mode/dynamic/post_setup(report)
update_playercounts()
for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules)
rule.candidates.Cut() // The rule should not use candidates at this point as they all are null.
if(!rule.execute())
stack_trace("The starting rule \"[rule.name]\" failed to execute.")
..()
/// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it.
/datum/game_mode/dynamic/proc/rigged_roundstart()
message_admins("[GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.")
log_game("DYNAMIC: [GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.")
for (var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
message_admins("Drafting players for forced ruleset [rule.name].")
log_game("DYNAMIC: Drafting players for forced ruleset [rule.name].")
rule.mode = src
rule.candidates = candidates.Copy()
rule.trim_candidates()
if (rule.ready(TRUE))
picking_roundstart_rule(list(rule), forced = TRUE)
/datum/game_mode/dynamic/proc/roundstart()
if (GLOB.dynamic_forced_extended)
log_game("DYNAMIC: Starting a round of forced extended.")
return TRUE
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules)
if (rule.acceptable(roundstart_pop_ready, threat_level) && threat >= rule.cost) // If we got the population and threat required
rule.candidates = candidates.Copy()
rule.trim_candidates()
if (rule.ready() && rule.candidates.len > 0)
drafted_rules[rule] = rule.weight
var/indice_pop = min(10,round(roundstart_pop_ready/pop_per_requirement)+1)
var/extra_rulesets_amount = 0
if (GLOB.dynamic_classic_secret)
extra_rulesets_amount = 0
else
if (roundstart_pop_ready > GLOB.dynamic_high_pop_limit)
message_admins("High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.")
log_game("DYNAMIC: High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.")
if (threat_level > high_pop_second_rule_req)
extra_rulesets_amount++
if (threat_level > high_pop_third_rule_req)
extra_rulesets_amount++
else
if (threat_level >= second_rule_req[indice_pop])
extra_rulesets_amount++
if (threat_level >= third_rule_req[indice_pop])
extra_rulesets_amount++
if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules))
if (extra_rulesets_amount > 0) // We've got enough population and threat for a second rulestart rule
for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules)
if (rule.cost > threat)
drafted_rules -= rule
if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules))
if (extra_rulesets_amount > 1) // We've got enough population and threat for a third rulestart rule
for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules)
if (rule.cost > threat)
drafted_rules -= rule
picking_roundstart_rule(drafted_rules)
else
return FALSE
return TRUE
/// Picks a random roundstart rule from the list given as an argument and executes it.
/datum/game_mode/dynamic/proc/picking_roundstart_rule(list/drafted_rules = list(), forced = FALSE)
var/datum/dynamic_ruleset/roundstart/starting_rule = pickweight(drafted_rules)
if(!starting_rule)
return FALSE
if(!forced)
if(only_ruleset_executed)
return FALSE
// Check if a blocking ruleset has been executed.
else if(check_blocking(starting_rule.blocking_rules, executed_rules))
drafted_rules -= starting_rule
if(drafted_rules.len <= 0)
return FALSE
starting_rule = pickweight(drafted_rules)
// Check if the ruleset is highlander and if a highlander ruleset has been executed
else if(starting_rule.flags & HIGHLANDER_RULESET)
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
if(highlander_executed)
drafted_rules -= starting_rule
if(drafted_rules.len <= 0)
return FALSE
starting_rule = pickweight(drafted_rules)
message_admins("Picking a [istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/) ? " delayed " : ""] ruleset [starting_rule.name]")
log_game("DYNAMIC: Picking a [istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/) ? " delayed " : ""] ruleset [starting_rule.name]")
roundstart_rules -= starting_rule
drafted_rules -= starting_rule
if (istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/))
var/datum/dynamic_ruleset/roundstart/delayed/rule = starting_rule
addtimer(CALLBACK(src, .proc/execute_delayed, rule), rule.delay)
starting_rule.trim_candidates()
if (starting_rule.pre_execute())
spend_threat(starting_rule.cost)
threat_log += "[worldtime2text()]: Roundstart [starting_rule.name] spent [starting_rule.cost]"
if(starting_rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
else if(starting_rule.flags & ONLY_RULESET)
only_ruleset_executed = TRUE
executed_rules += starting_rule
if (starting_rule.persistent)
current_rules += starting_rule
for(var/mob/M in starting_rule.assigned)
for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules)
if (!rule.ready())
drafted_rules -= rule // And removing rules that are no longer elligible
return TRUE
else
stack_trace("The starting rule \"[starting_rule.name]\" failed to pre_execute.")
return FALSE
/// Executes delayed roundstart rules and has a hack in it.
/datum/game_mode/dynamic/proc/execute_delayed(datum/dynamic_ruleset/roundstart/delayed/rule)
update_playercounts()
rule.candidates = current_players[CURRENT_LIVING_PLAYERS].Copy()
rule.trim_candidates()
if(rule.execute())
executed_rules += rule
if (rule.persistent)
current_rules += rule
return TRUE
else
stack_trace("The delayed roundstart rule \"[rule.name]\" failed to execute.")
return FALSE
/// Picks a random midround OR latejoin rule from the list given as an argument and executes it.
/// Also this could be named better.
/datum/game_mode/dynamic/proc/picking_midround_latejoin_rule(list/drafted_rules = list(), forced = FALSE)
var/datum/dynamic_ruleset/rule = pickweight(drafted_rules)
if(!rule)
return FALSE
if(!forced)
if(only_ruleset_executed)
return FALSE
// Check if a blocking ruleset has been executed.
else if(check_blocking(rule.blocking_rules, executed_rules))
drafted_rules -= rule
if(drafted_rules.len <= 0)
return FALSE
rule = pickweight(drafted_rules)
// Check if the ruleset is highlander and if a highlander ruleset has been executed
else if(rule.flags & HIGHLANDER_RULESET)
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
if(highlander_executed)
drafted_rules -= rule
if(drafted_rules.len <= 0)
return FALSE
rule = pickweight(drafted_rules)
if(!rule.repeatable)
if(rule.ruletype == "Latejoin")
latejoin_rules = remove_from_list(latejoin_rules, rule.type)
else if(rule.type == "Midround")
midround_rules = remove_from_list(midround_rules, rule.type)
if (rule.execute())
log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].")
spend_threat(rule.cost)
threat_log += "[worldtime2text()]: [rule.ruletype] [rule.name] spent [rule.cost]"
if(rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
else if(rule.flags & ONLY_RULESET)
only_ruleset_executed = TRUE
if(rule.ruletype == "Latejoin")
var/mob/M = pick(rule.candidates)
message_admins("[key_name(M)] joined the station, and was selected by the [rule.name] ruleset.")
log_game("DYNAMIC: [key_name(M)] joined the station, and was selected by the [rule.name] ruleset.")
executed_rules += rule
rule.candidates.Cut()
if (rule.persistent)
current_rules += rule
return TRUE
else
stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.")
return FALSE
/// An experimental proc to allow admins to call rules on the fly or have rules call other rules.
/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE)
var/datum/dynamic_ruleset/midround/new_rule
if(ispath(ruletype))
new_rule = new ruletype() // You should only use it to call midround rules though.
else if(istype(ruletype, /datum/dynamic_ruleset))
new_rule = ruletype
else
return FALSE
if(!new_rule)
return FALSE
if(!forced)
if(only_ruleset_executed)
return FALSE
// Check if a blocking ruleset has been executed.
else if(check_blocking(new_rule.blocking_rules, executed_rules))
return FALSE
// Check if the ruleset is highlander and if a highlander ruleset has been executed
else if(new_rule.flags & HIGHLANDER_RULESET)
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
if(highlander_executed)
return FALSE
update_playercounts()
if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat)))
new_rule.candidates = current_players.Copy()
new_rule.trim_candidates()
if (new_rule.ready(forced))
spend_threat(new_rule.cost)
threat_log += "[worldtime2text()]: Forced rule [new_rule.name] spent [new_rule.cost]"
if (new_rule.execute()) // This should never fail since ready() returned 1
if(new_rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
else if(new_rule.flags & ONLY_RULESET)
only_ruleset_executed = TRUE
log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!")
executed_rules += new_rule
if (new_rule.persistent)
current_rules += new_rule
return TRUE
else if (forced)
log_game("DYNAMIC: The ruleset [new_rule.name] couldn't be executed due to lack of elligible players.")
return FALSE
/datum/game_mode/dynamic/process()
if (pop_last_updated < world.time - (60 SECONDS))
pop_last_updated = world.time
update_playercounts()
for (var/datum/dynamic_ruleset/rule in current_rules)
if(rule.rule_process() == RULESET_STOP_PROCESSING) // If rule_process() returns 1 (RULESET_STOP_PROCESSING), stop processing.
current_rules -= rule
if (midround_injection_cooldown < world.time)
if (GLOB.dynamic_forced_extended)
return
// Somehow it manages to trigger midround multiple times so this was moved here.
// There is no way this should be able to trigger an injection twice now.
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time)
// Time to inject some threat into the round
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone
return
log_game("DYNAMIC: Checking state of the round.")
update_playercounts()
if (prob(get_injection_chance()))
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/midround/rule in midround_rules)
if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
// Classic secret : only autotraitor/minor roles
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
continue
rule.candidates = list()
rule.candidates = current_players.Copy()
rule.trim_candidates()
if (rule.ready() && rule.candidates.len > 0)
drafted_rules[rule] = rule.get_weight()
if (drafted_rules.len > 0)
picking_midround_latejoin_rule(drafted_rules)
/// Updates current_players.
/datum/game_mode/dynamic/proc/update_playercounts()
current_players[CURRENT_LIVING_PLAYERS] = list()
current_players[CURRENT_LIVING_ANTAGS] = list()
current_players[CURRENT_DEAD_PLAYERS] = list()
current_players[CURRENT_OBSERVERS] = list()
for (var/mob/M in GLOB.player_list)
if (istype(M, /mob/dead/new_player))
continue
if (M.stat != DEAD)
current_players[CURRENT_LIVING_PLAYERS].Add(M)
if (M.mind && (M.mind.special_role || M.mind.antag_datums?.len > 0))
current_players[CURRENT_LIVING_ANTAGS].Add(M)
else
if (istype(M,/mob/dead/observer))
var/mob/dead/observer/O = M
if (O.started_as_observer) // Observers
current_players[CURRENT_OBSERVERS].Add(M)
continue
current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow)
/// Gets the chance for latejoin and midround injection, the dry_run argument is only used for forced injection.
/datum/game_mode/dynamic/proc/get_injection_chance(dry_run = FALSE)
if(forced_injection)
forced_injection = !dry_run
return 100
var/chance = 0
// If the high pop override is in effect, we reduce the impact of population on the antag injection chance
var/high_pop_factor = (current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit)
var/max_pop_per_antag = max(5,15 - round(threat_level/10) - round(current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5)))
if (!current_players[CURRENT_LIVING_ANTAGS].len)
chance += 50 // No antags at all? let's boost those odds!
else
var/current_pop_per_antag = current_players[CURRENT_LIVING_PLAYERS].len / current_players[CURRENT_LIVING_ANTAGS].len
if (current_pop_per_antag > max_pop_per_antag)
chance += min(50, 25+10*(current_pop_per_antag-max_pop_per_antag))
else
chance += 25-10*(max_pop_per_antag-current_pop_per_antag)
if (current_players[CURRENT_DEAD_PLAYERS].len > current_players[CURRENT_LIVING_PLAYERS].len)
chance -= 30 // More than half the crew died? ew, let's calm down on antags
if (threat > 70)
chance += 15
if (threat < 30)
chance -= 15
return round(max(0,chance))
/// Removes type from the list
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
for(var/I in type_list)
if(istype(I, type))
type_list -= I
return type_list
/// Checks if a type in blocking_list is in rule_list.
/datum/game_mode/dynamic/proc/check_blocking(list/blocking_list, list/rule_list)
if(blocking_list.len > 0)
for(var/blocking in blocking_list)
for(var/datum/executed in rule_list)
if(blocking == executed.type)
return TRUE
return FALSE
/// Checks if client age is age or older.
/datum/game_mode/dynamic/proc/check_age(client/C, age)
enemy_minimum_age = age
if(get_remaining_days(C) == 0)
enemy_minimum_age = initial(enemy_minimum_age)
return TRUE // Available in 0 days = available right now = player is old enough to play.
enemy_minimum_age = initial(enemy_minimum_age)
return FALSE
/datum/game_mode/dynamic/make_antag_chance(mob/living/carbon/human/newPlayer)
if (GLOB.dynamic_forced_extended)
return
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left
return
update_playercounts()
if (forced_latejoin_rule)
forced_latejoin_rule.candidates = list(newPlayer)
forced_latejoin_rule.trim_candidates()
log_game("DYNAMIC: Forcing ruleset [forced_latejoin_rule]")
if (forced_latejoin_rule.ready(TRUE))
picking_midround_latejoin_rule(list(forced_latejoin_rule), forced = TRUE)
forced_latejoin_rule = null
else if (latejoin_injection_cooldown < world.time && prob(get_injection_chance()))
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/latejoin/rule in latejoin_rules)
if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
// Classic secret : only autotraitor/minor roles
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
continue
// No stacking : only one round-enter, unless > stacking_limit threat.
if (threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
if(rule.flags & HIGHLANDER_RULESET && highlander_executed)
continue
rule.candidates = list(newPlayer)
rule.trim_candidates()
if (rule.ready())
drafted_rules[rule] = rule.get_weight()
if (drafted_rules.len > 0 && picking_midround_latejoin_rule(drafted_rules))
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time
/// Refund threat, but no more than threat_level.
/datum/game_mode/dynamic/proc/refund_threat(regain)
threat = min(threat_level,threat+regain)
/// Generate threat and increase the threat_level if it goes beyond, capped at 100
/datum/game_mode/dynamic/proc/create_threat(gain)
threat = min(100, threat+gain)
if(threat > threat_level)
threat_level = threat
/// Expend threat, can't fall under 0.
/datum/game_mode/dynamic/proc/spend_threat(cost)
threat = max(threat-cost,0)
/// Turns the value generated by lorentz distribution to threat value between 0 and 100.
/datum/game_mode/dynamic/proc/lorentz_to_threat(x)
switch (x)
if (-INFINITY to -20)
return rand(0, 10)
if (-20 to -10)
return RULE_OF_THREE(-40, -20, x) + 50
if (-10 to -5)
return RULE_OF_THREE(-30, -10, x) + 50
if (-5 to -2.5)
return RULE_OF_THREE(-20, -5, x) + 50
if (-2.5 to -0)
return RULE_OF_THREE(-10, -2.5, x) + 50
if (0 to 2.5)
return RULE_OF_THREE(10, 2.5, x) + 50
if (2.5 to 5)
return RULE_OF_THREE(20, 5, x) + 50
if (5 to 10)
return RULE_OF_THREE(30, 10, x) + 50
if (10 to 20)
return RULE_OF_THREE(40, 20, x) + 50
if (20 to INFINITY)
return rand(90, 100)
@@ -0,0 +1,211 @@
/datum/dynamic_ruleset
/// For admin logging and round end screen.
var/name = ""
/// For admin logging and round end screen, do not change this unless making a new rule type.
var/ruletype = ""
/// If set to TRUE, the rule won't be discarded after being executed, and dynamic will call rule_process() every time it ticks.
var/persistent = FALSE
/// If set to TRUE, dynamic mode will be able to draft this ruleset again later on. (doesn't apply for roundstart rules)
var/repeatable = FALSE
/// If set higher than 0 decreases weight by itself causing the ruleset to appear less often the more it is repeated.
var/repeatable_weight_decrease = 2
/// List of players that are being drafted for this rule
var/list/mob/candidates = list()
/// List of players that were selected for this rule
var/list/datum/mind/assigned = list()
/// Preferences flag such as ROLE_WIZARD that need to be turned on for players to be antag
var/antag_flag = null
/// The antagonist datum that is assigned to the mobs mind on ruleset execution.
var/datum/antagonist/antag_datum = null
/// The required minimum account age for this ruleset.
var/minimum_required_age = 7
/// If set, and config flag protect_roles_from_antagonist is false, then the rule will not pick players from these roles.
var/list/protected_roles = list()
/// If set, rule will deny candidates from those roles always.
var/list/restricted_roles = list()
/// If set, rule will only accept candidates from those roles, IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
var/list/exclusive_roles = list()
/// If set, there needs to be a certain amount of players doing those roles (among the players who won't be drafted) for the rule to be drafted IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
var/list/enemy_roles = list()
/// If enemy_roles was set, this is the amount of enemy job workers needed per threat_level range (0-10,10-20,etc) IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
var/required_enemies = list(1,1,0,0,0,0,0,0,0,0)
/// The rule needs this many candidates (post-trimming) to be executed (example: Cult needs 4 players at round start)
var/required_candidates = 0
/// 1 -> 9, probability for this rule to be picked against other rules
var/weight = 5
/// Threat cost for this rule, this is decreased from the mode's threat when the rule is executed.
var/cost = 0
/// A flag that determines how the ruleset is handled
/// HIGHLANDER_RULESET are rulesets can end the round.
/// TRAITOR_RULESET and MINOR_RULESET can't end the round and have no difference right now.
var/flags = 0
/// Pop range per requirement. If zero defaults to mode's pop_per_requirement.
var/pop_per_requirement = 0
/// Requirements are the threat level requirements per pop range.
/// With the default values, The rule will never get drafted below 10 threat level (aka: "peaceful extended"), and it requires a higher threat level at lower pops.
var/list/requirements = list(40,30,20,10,10,10,10,10,10,10)
/// An alternative, static requirement used instead when pop is over mode's high_pop_limit.
var/high_population_requirement = 10
/// Reference to the mode, use this instead of SSticker.mode.
var/datum/game_mode/dynamic/mode = null
/// If a role is to be considered another for the purpose of banning.
var/antag_flag_override = null
/// If a ruleset type which is in this list has been executed, then the ruleset will not be executed.
var/list/blocking_rules = list()
/// The minimum amount of players required for the rule to be considered.
var/minimum_players = 0
/// The maximum amount of players required for the rule to be considered.
/// Anything below zero or exactly zero is ignored.
var/maximum_players = 0
/datum/dynamic_ruleset/New()
..()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_roles += protected_roles
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_roles += "Assistant"
if (istype(SSticker.mode, /datum/game_mode/dynamic))
mode = SSticker.mode
else if (GLOB.master_mode != "dynamic") // This is here to make roundstart forced ruleset function.
qdel(src)
/datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart
ruletype = "Roundstart"
/datum/dynamic_ruleset/roundstart/delayed/ // Executed with a 30 seconds delay
var/delay = 30 SECONDS
var/required_type = /mob/living/carbon/human // No ghosts, new players or silicons allowed.
// Can be drafted when a player joins the server
/datum/dynamic_ruleset/latejoin
ruletype = "Latejoin"
/// By default, a rule is acceptable if it satisfies the threat level/population requirements.
/// If your rule has extra checks, such as counting security officers, do that in ready() instead
/datum/dynamic_ruleset/proc/acceptable(population = 0, threat_level = 0)
if(minimum_players > population)
return FALSE
if(maximum_players > 0 && population > maximum_players)
return FALSE
if (population >= GLOB.dynamic_high_pop_limit)
return (threat_level >= high_population_requirement)
else
pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : mode.pop_per_requirement
var/indice_pop = min(10,round(population/pop_per_requirement)+1)
return (threat_level >= requirements[indice_pop])
/// This is called if persistent variable is true everytime SSTicker ticks.
/datum/dynamic_ruleset/proc/rule_process()
return
/// Called on game mode pre_setup, used for non-delayed roundstart rulesets only.
/// Do everything you need to do before job is assigned here.
/// IMPORTANT: ASSIGN special_role HERE
/datum/dynamic_ruleset/proc/pre_execute()
return TRUE
/// Called on post_setup on roundstart and when the rule executes on midround and latejoin.
/// Give your candidates or assignees equipment and antag datum here.
/datum/dynamic_ruleset/proc/execute()
for(var/datum/mind/M in assigned)
M.add_antag_datum(antag_datum)
return TRUE
/// Called after delay set in ruleset.
/// Give your candidates or assignees equipment and antag datum here.
/datum/dynamic_ruleset/roundstart/delayed/execute()
if (SSticker && SSticker.current_state < GAME_STATE_PLAYING)
CRASH("The delayed ruleset [name] executed before the round started.")
/// Here you can perform any additional checks you want. (such as checking the map etc)
/// Remember that on roundstart no one knows what their job is at this point.
/// IMPORTANT: If ready() returns TRUE, that means pre_execute() or execute() should never fail!
/datum/dynamic_ruleset/proc/ready(forced = 0)
if (required_candidates > candidates.len)
return FALSE
return TRUE
/// Gets weight of the ruleset
/// Note that this decreases weight if repeatable is TRUE and repeatable_weight_decrease is higher than 0
/// Note: If you don't want repeatable rulesets to decrease their weight use the weight variable directly
/datum/dynamic_ruleset/proc/get_weight()
if(repeatable && weight > 1 && repeatable_weight_decrease > 0)
for(var/datum/dynamic_ruleset/DR in mode.executed_rules)
if(istype(DR, type))
weight = max(weight-repeatable_weight_decrease,1)
return weight
/// Here you can remove candidates that do not meet your requirements.
/// This means if their job is not correct or they have disconnected you can remove them from candidates here.
/// Usually this does not need to be changed unless you need some specific requirements from your candidates.
/datum/dynamic_ruleset/proc/trim_candidates()
return
/// Counts how many players are ready at roundstart.
/// Used only by non-delayed roundstart rulesets.
/datum/dynamic_ruleset/proc/num_players()
. = 0
for(var/mob/dead/new_player/P in GLOB.player_list)
if(P.client && P.ready == PLAYER_READY_TO_PLAY)
. ++
/// Set mode result and news report here.
/// Only called if ruleset is flagged as HIGHLANDER_RULESET
/datum/dynamic_ruleset/proc/round_result()
/// Checks if round is finished, return true to end the round.
/// Only called if ruleset is flagged as HIGHLANDER_RULESET
/datum/dynamic_ruleset/proc/check_finished()
return FALSE
//////////////////////////////////////////////
// //
// ROUNDSTART RULESETS //
// //
//////////////////////////////////////////////
/// Checks if candidates are connected and if they are banned or don't want to be the antagonist.
/datum/dynamic_ruleset/roundstart/trim_candidates()
for(var/mob/dead/new_player/P in candidates)
if (!P.client || !P.mind) // Are they connected?
candidates.Remove(P)
continue
if(!mode.check_age(P.client, minimum_required_age))
candidates.Remove(P)
continue
if(P.mind.special_role) // We really don't want to give antag to an antag.
candidates.Remove(P)
continue
if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned?
candidates.Remove(P)
continue
/// Checks if candidates are required mob type, connected, banned and if the job is exclusive to the role.
/datum/dynamic_ruleset/roundstart/delayed/trim_candidates()
. = ..()
for (var/mob/P in candidates)
if (!istype(P, required_type))
candidates.Remove(P) // Can be a new_player, etc.
continue
if(!mode.check_age(P.client, minimum_required_age))
candidates.Remove(P)
continue
if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected?
candidates.Remove(P)
continue
if(P.mind.special_role || P.mind.antag_datums?.len > 0) // Are they an antag already?
candidates.Remove(P)
continue
if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned?
candidates.Remove(P)
continue
if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
candidates.Remove(P)
continue
/// Do your checks if the ruleset is ready to be executed here.
/// Should ignore certain checks if forced is TRUE
/datum/dynamic_ruleset/roundstart/ready(forced = FALSE)
return ..()
@@ -0,0 +1,110 @@
//////////////////////////////////////////////
// //
// LATEJOIN RULESETS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/latejoin/trim_candidates()
for(var/mob/P in candidates)
if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected?
candidates.Remove(P)
continue
if(!mode.check_age(P.client, minimum_required_age))
candidates.Remove(P)
continue
if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override))))//are they willing and not antag-banned?
candidates.Remove(P)
continue
if (P.mind.assigned_role in restricted_roles) // Does their job allow for it?
candidates.Remove(P)
continue
if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
candidates.Remove(P)
continue
/datum/dynamic_ruleset/latejoin/ready(forced = 0)
if (!forced)
var/job_check = 0
if (enemy_roles.len > 0)
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
if (M.stat == DEAD)
continue // Dead players cannot count as opponents
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles)))
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
var/threat = round(mode.threat_level/10)
if (job_check < required_enemies[threat])
return FALSE
return ..()
/datum/dynamic_ruleset/latejoin/execute()
var/mob/M = pick(candidates)
assigned += M.mind
M.mind.special_role = antag_flag
M.mind.add_antag_datum(antag_datum)
return TRUE
//////////////////////////////////////////////
// //
// SYNDICATE TRAITORS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/latejoin/infiltrator
name = "Syndicate Infiltrator"
antag_datum = /datum/antagonist/traitor
antag_flag = ROLE_TRAITOR
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 7
cost = 5
requirements = list(40,30,20,10,10,10,10,10,10,10)
high_population_requirement = 10
repeatable = TRUE
flags = TRAITOR_RULESET
//////////////////////////////////////////////
// //
// REVOLUTIONARY PROVOCATEUR //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/latejoin/provocateur
name = "Provocateur"
antag_datum = /datum/antagonist/rev/head
antag_flag = ROLE_REV_HEAD
antag_flag_override = ROLE_REV
restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
enemy_roles = list("AI", "Cyborg", "Security Officer","Detective","Head of Security", "Captain", "Warden")
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
weight = 2
cost = 20
requirements = list(101,101,70,40,30,20,20,20,20,20)
high_population_requirement = 50
flags = HIGHLANDER_RULESET
var/required_heads = 3
/datum/dynamic_ruleset/latejoin/provocateur/ready(forced=FALSE)
if (forced)
required_heads = 1
if(!..())
return FALSE
var/head_check = 0
for(var/mob/player in mode.current_players[CURRENT_LIVING_PLAYERS])
if (player.mind.assigned_role in GLOB.command_positions)
head_check++
return (head_check >= required_heads)
/datum/dynamic_ruleset/latejoin/provocateur/execute()
var/mob/M = pick(candidates)
assigned += M.mind
M.mind.special_role = antag_flag
var/datum/antagonist/rev/head/new_head = new()
new_head.give_flash = TRUE
new_head.give_hud = TRUE
new_head.remove_clumsy = TRUE
new_head = M.mind.add_antag_datum(new_head)
new_head.rev_team.max_headrevs = 1 // Only one revhead if it is latejoin.
return TRUE
@@ -0,0 +1,460 @@
//////////////////////////////////////////////
// //
// MIDROUND RULESETS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround // Can be drafted once in a while during a round
ruletype = "Midround"
/// If the ruleset should be restricted from ghost roles.
var/restrict_ghost_roles = TRUE
/// What type the ruleset is restricted to.
var/required_type = /mob/living/carbon/human
var/list/living_players = list()
var/list/living_antags = list()
var/list/dead_players = list()
var/list/list_observers = list()
/datum/dynamic_ruleset/midround/from_ghosts
weight = 0
/// Whether the ruleset should call generate_ruleset_body or not.
var/makeBody = TRUE
/datum/dynamic_ruleset/midround/trim_candidates()
// Unlike the previous two types, these rulesets are not meant for /mob/dead/new_player
// And since I want those rulesets to be as flexible as possible, I'm not gonna put much here,
//
// All you need to know is that here, the candidates list contains 4 lists itself, indexed with the following defines:
// Candidates = list(CURRENT_LIVING_PLAYERS, CURRENT_LIVING_ANTAGS, CURRENT_DEAD_PLAYERS, CURRENT_OBSERVERS)
// So for example you can get the list of all current dead players with var/list/dead_players = candidates[CURRENT_DEAD_PLAYERS]
// Make sure to properly typecheck the mobs in those lists, as the dead_players list could contain ghosts, or dead players still in their bodies.
// We're still gonna trim the obvious (mobs without clients, jobbanned players, etc)
living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS])
living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS])
dead_players = trim_list(mode.current_players[CURRENT_DEAD_PLAYERS])
list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS])
/datum/dynamic_ruleset/midround/proc/trim_list(list/L = list())
var/list/trimmed_list = L.Copy()
var/antag_name = initial(antag_flag)
for(var/mob/M in trimmed_list)
if (!istype(M, required_type))
trimmed_list.Remove(M)
continue
if (!M.client) // Are they connected?
trimmed_list.Remove(M)
continue
if(!mode.check_age(M.client, minimum_required_age))
trimmed_list.Remove(M)
continue
if (!(antag_name in M.client.prefs.be_special) || jobban_isbanned(M.ckey, list(antag_name, ROLE_SYNDICATE)))//are they willing and not antag-banned?
trimmed_list.Remove(M)
continue
if (M.mind)
if (restrict_ghost_roles && M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL]) // Are they playing a ghost role?
trimmed_list.Remove(M)
continue
if (M.mind.assigned_role in restricted_roles || HAS_TRAIT(M, TRAIT_MINDSHIELD)) // Does their job allow it or are they mindshielded?
trimmed_list.Remove(M)
continue
if ((exclusive_roles.len > 0) && !(M.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
trimmed_list.Remove(M)
continue
return trimmed_list
// You can then for example prompt dead players in execute() to join as strike teams or whatever
// Or autotator someone
// IMPORTANT, since /datum/dynamic_ruleset/midround may accept candidates from both living, dead, and even antag players, you need to manually check whether there are enough candidates
// (see /datum/dynamic_ruleset/midround/autotraitor/ready(var/forced = FALSE) for example)
/datum/dynamic_ruleset/midround/ready(forced = FALSE)
if (!forced)
var/job_check = 0
if (enemy_roles.len > 0)
for (var/mob/M in living_players)
if (M.stat == DEAD)
continue // Dead players cannot count as opponents
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles)))
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
var/threat = round(mode.threat_level/10)
if (job_check < required_enemies[threat])
return FALSE
return TRUE
/datum/dynamic_ruleset/midround/from_ghosts/execute()
var/list/possible_candidates = list()
possible_candidates.Add(dead_players)
possible_candidates.Add(list_observers)
send_applications(possible_candidates)
if(assigned.len > 0)
return TRUE
else
return FALSE
/// This sends a poll to ghosts if they want to be a ghost spawn from a ruleset.
/datum/dynamic_ruleset/midround/from_ghosts/proc/send_applications(list/possible_volunteers = list())
if (possible_volunteers.len <= 0) // This shouldn't happen, as ready() should return FALSE if there is not a single valid candidate
message_admins("Possible volunteers was 0. This shouldn't appear, because of ready(), unless you forced it!")
return
message_admins("Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
log_game("DYNAMIC: Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
candidates = pollGhostCandidates("The mode is looking for volunteers to become [antag_flag] for [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300)
if(!candidates || candidates.len <= 0)
message_admins("The ruleset [name] received no applications.")
log_game("DYNAMIC: The ruleset [name] received no applications.")
mode.refund_threat(cost)
mode.threat_log += "[worldtime2text()]: Rule [name] refunded [cost] (no applications)"
mode.executed_rules -= src
return
message_admins("[candidates.len] players volunteered for the ruleset [name].")
log_game("DYNAMIC: [candidates.len] players volunteered for [name].")
review_applications()
/// Here is where you can check if your ghost applicants are valid for the ruleset.
/// Called by send_applications().
/datum/dynamic_ruleset/midround/from_ghosts/proc/review_applications()
for (var/i = 1, i <= required_candidates, i++)
if(candidates.len <= 0)
if(i == 1)
// We have found no candidates so far and we are out of applicants.
mode.refund_threat(cost)
mode.threat_log += "[worldtime2text()]: Rule [name] refunded [cost] (all applications invalid)"
mode.executed_rules -= src
break
var/mob/applicant = pick(candidates)
candidates -= applicant
if(!isobserver(applicant))
if(applicant.stat == DEAD) // Not an observer? If they're dead, make them one.
applicant = applicant.ghostize(FALSE)
else // Not dead? Disregard them, pick a new applicant
i--
continue
if(!applicant)
i--
continue
var/mob/new_character = applicant
if (makeBody)
new_character = generate_ruleset_body(applicant)
finish_setup(new_character, i)
assigned += applicant
notify_ghosts("[new_character] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT, header="Something Interesting!")
/datum/dynamic_ruleset/midround/from_ghosts/proc/generate_ruleset_body(mob/applicant)
var/mob/living/carbon/human/new_character = makeBody(applicant)
new_character.dna.remove_all_mutations()
return new_character
/datum/dynamic_ruleset/midround/from_ghosts/proc/finish_setup(mob/new_character, index)
var/datum/antagonist/new_role = new antag_datum()
setup_role(new_role)
new_character.mind.add_antag_datum(new_role)
new_character.mind.special_role = antag_flag
/datum/dynamic_ruleset/midround/from_ghosts/proc/setup_role(datum/antagonist/new_role)
return
//////////////////////////////////////////////
// //
// SYNDICATE TRAITORS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround/autotraitor
name = "Syndicate Sleeper Agent"
antag_datum = /datum/antagonist/traitor
antag_flag = ROLE_TRAITOR
restricted_roles = list("AI", "Cyborg", "Positronic Brain")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 7
cost = 10
requirements = list(50,40,30,20,10,10,10,10,10,10)
repeatable = TRUE
high_population_requirement = 10
flags = TRAITOR_RULESET
/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0)
var/player_count = mode.current_players[CURRENT_LIVING_PLAYERS].len
var/antag_count = mode.current_players[CURRENT_LIVING_ANTAGS].len
var/max_traitors = round(player_count / 10) + 1
if ((antag_count < max_traitors) && prob(mode.threat_level))//adding traitors if the antag population is getting low
return ..()
else
return FALSE
/datum/dynamic_ruleset/midround/autotraitor/trim_candidates()
..()
for(var/mob/living/player in living_players)
if(issilicon(player)) // Your assigned role doesn't change when you are turned into a silicon.
living_players -= player
continue
if(is_centcom_level(player.z))
living_players -= player // We don't autotator people in CentCom
continue
if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0))
living_players -= player // We don't autotator people with roles already
/datum/dynamic_ruleset/midround/autotraitor/ready(forced = FALSE)
if (required_candidates > living_players.len)
return FALSE
return ..()
/datum/dynamic_ruleset/midround/autotraitor/execute()
var/mob/M = pick(living_players)
assigned += M
living_players -= M
var/datum/antagonist/traitor/newTraitor = new
M.mind.add_antag_datum(newTraitor)
return TRUE
//////////////////////////////////////////////
// //
// Malfunctioning AI //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround/malf
name = "Malfunctioning AI"
antag_datum = /datum/antagonist/traitor
antag_flag = ROLE_MALF
enemy_roles = list("Security Officer", "Warden","Detective","Head of Security", "Captain", "Scientist", "Chemist", "Research Director", "Chief Engineer")
exclusive_roles = list("AI")
required_enemies = list(4,4,4,4,4,4,2,2,2,0)
required_candidates = 1
weight = 3
cost = 35
requirements = list(101,101,80,70,60,60,50,50,40,40)
high_population_requirement = 35
required_type = /mob/living/silicon/ai
var/ion_announce = 33
var/removeDontImproveChance = 10
/datum/dynamic_ruleset/midround/malf/trim_candidates()
..()
candidates = candidates[CURRENT_LIVING_PLAYERS]
for(var/mob/living/player in candidates)
if(!isAI(player))
candidates -= player
continue
if(is_centcom_level(player.z))
candidates -= player
continue
if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0))
candidates -= player
/datum/dynamic_ruleset/midround/malf/execute()
if(!candidates || !candidates.len)
return FALSE
var/mob/living/silicon/ai/M = pick(candidates)
candidates -= M
assigned += M.mind
var/datum/antagonist/traitor/AI = new
M.mind.special_role = antag_flag
M.mind.add_antag_datum(AI)
if(prob(ion_announce))
priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", 'sound/ai/ionstorm.ogg')
if(prob(removeDontImproveChance))
M.replace_random_law(generate_ion_law(), list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION))
else
M.add_ion_law(generate_ion_law())
return TRUE
//////////////////////////////////////////////
// //
// WIZARD (GHOST) //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround/from_ghosts/wizard
name = "Wizard"
antag_datum = /datum/antagonist/wizard
antag_flag = ROLE_WIZARD
enemy_roles = list("Security Officer","Detective","Head of Security", "Captain")
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
weight = 1
cost = 20
requirements = list(90,90,70,40,30,20,10,10,10,10)
high_population_requirement = 50
repeatable = TRUE
/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE)
if (required_candidates > (dead_players.len + list_observers.len))
return FALSE
if(GLOB.wizardstart.len == 0)
log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.")
message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.")
return FALSE
return ..()
/datum/dynamic_ruleset/midround/from_ghosts/wizard/finish_setup(mob/new_character, index)
..()
new_character.forceMove(pick(GLOB.wizardstart))
//////////////////////////////////////////////
// //
// NUCLEAR OPERATIVES (MIDROUND) //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround/from_ghosts/nuclear
name = "Nuclear Assault"
antag_flag = ROLE_OPERATIVE
antag_datum = /datum/antagonist/nukeop
enemy_roles = list("AI", "Cyborg", "Security Officer", "Warden","Detective","Head of Security", "Captain")
required_enemies = list(3,3,3,3,3,2,1,1,0,0)
required_candidates = 5
weight = 5
cost = 35
requirements = list(90,90,90,80,60,40,30,20,10,10)
high_population_requirement = 10
var/operative_cap = list(2,2,3,3,4,5,5,5,5,5)
var/datum/team/nuclear/nuke_team
flags = HIGHLANDER_RULESET
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/acceptable(population=0, threat=0)
if (locate(/datum/dynamic_ruleset/roundstart/nuclear) in mode.executed_rules)
return FALSE // Unavailable if nuke ops were already sent at roundstart
var/indice_pop = min(10,round(living_players.len/5)+1)
required_candidates = operative_cap[indice_pop]
return ..()
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/ready(forced = FALSE)
if (required_candidates > (dead_players.len + list_observers.len))
return FALSE
return ..()
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_setup(mob/new_character, index)
new_character.mind.special_role = "Nuclear Operative"
new_character.mind.assigned_role = "Nuclear Operative"
if (index == 1) // Our first guy is the leader
var/datum/antagonist/nukeop/leader/new_role = new
nuke_team = new_role.nuke_team
new_character.mind.add_antag_datum(new_role)
else
return ..()
//////////////////////////////////////////////
// //
// BLOB (GHOST) //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround/from_ghosts/blob
name = "Blob"
antag_datum = /datum/antagonist/blob
antag_flag = ROLE_BLOB
enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain")
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
weight = 4
cost = 10
requirements = list(101,101,101,80,60,50,30,20,10,10)
high_population_requirement = 50
repeatable = TRUE
/datum/dynamic_ruleset/midround/from_ghosts/blob/generate_ruleset_body(mob/applicant)
var/body = applicant.become_overmind()
return body
//////////////////////////////////////////////
// //
// XENOMORPH (GHOST) //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph
name = "Alien Infestation"
antag_datum = /datum/antagonist/xeno
antag_flag = ROLE_ALIEN
enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain")
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
weight = 3
cost = 10
requirements = list(101,101,101,70,50,40,20,15,10,10)
high_population_requirement = 50
repeatable = TRUE
var/list/vents = list()
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/execute()
// 50% chance of being incremented by one
required_candidates += prob(50)
for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in GLOB.machines)
if(QDELETED(temp_vent))
continue
if(is_station_level(temp_vent.loc.z) && !temp_vent.welded)
var/datum/pipeline/temp_vent_parent = temp_vent.parents[1]
if(!temp_vent_parent)
continue // No parent vent
// Stops Aliens getting stuck in small networks.
// See: Security, Virology
if(temp_vent_parent.other_atmosmch.len > 20)
vents += temp_vent
if(!vents.len)
return FALSE
. = ..()
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/generate_ruleset_body(mob/applicant)
var/obj/vent = pick_n_take(vents)
var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc)
new_xeno.key = applicant.key
message_admins("[ADMIN_LOOKUPFLW(new_xeno)] has been made into an alien by the midround ruleset.")
log_game("DYNAMIC: [key_name(new_xeno)] was spawned as an alien by the midround ruleset.")
return new_xeno
//////////////////////////////////////////////
// //
// NIGHTMARE (GHOST) //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround/from_ghosts/nightmare
name = "Nightmare"
antag_datum = /datum/antagonist/nightmare
antag_flag = "Nightmare"
antag_flag_override = ROLE_ALIEN
enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain")
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
weight = 3
cost = 10
requirements = list(101,101,101,70,50,40,20,15,10,10)
high_population_requirement = 50
repeatable = TRUE
var/list/spawn_locs = list()
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute()
for(var/X in GLOB.xeno_spawn)
var/turf/T = X
var/light_amount = T.get_lumcount()
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
spawn_locs += T
if(!spawn_locs.len)
return FALSE
. = ..()
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/generate_ruleset_body(mob/applicant)
var/datum/mind/player_mind = new /datum/mind(applicant.key)
player_mind.active = TRUE
var/mob/living/carbon/human/S = new (pick(spawn_locs))
player_mind.transfer_to(S)
player_mind.assigned_role = "Nightmare"
player_mind.special_role = "Nightmare"
player_mind.add_antag_datum(/datum/antagonist/nightmare)
S.set_species(/datum/species/shadow/nightmare)
playsound(S, 'sound/magic/ethereal_exit.ogg', 50, 1, -1)
message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Nightmare by the midround ruleset.")
log_game("DYNAMIC: [key_name(S)] was spawned as a Nightmare by the midround ruleset.")
return S
@@ -0,0 +1,732 @@
//////////////////////////////////////////////
// //
// SYNDICATE TRAITORS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/traitor
name = "Traitors"
persistent = TRUE
antag_flag = ROLE_TRAITOR
antag_datum = /datum/antagonist/traitor/
minimum_required_age = 0
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster", "Cyborg")
restricted_roles = list("Cyborg")
required_candidates = 1
weight = 5
cost = 10
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec)
/datum/dynamic_ruleset/roundstart/traitor/pre_execute()
var/traitor_scaling_coeff = 10 - max(0,round(mode.threat_level/10)-5) // Above 50 threat level, coeff goes down by 1 for every 10 levels
var/num_traitors = min(round(mode.candidates.len / traitor_scaling_coeff) + 1, candidates.len)
for (var/i = 1 to num_traitors)
var/mob/M = pick(candidates)
candidates -= M
assigned += M.mind
M.mind.special_role = ROLE_TRAITOR
M.mind.restricted_roles = restricted_roles
return TRUE
/datum/dynamic_ruleset/roundstart/traitor/rule_process()
if (autotraitor_cooldown > 0)
autotraitor_cooldown--
else
autotraitor_cooldown = 450 // 15 minutes
message_admins("Checking if we can turn someone into a traitor.")
log_game("DYNAMIC: Checking if we can turn someone into a traitor.")
mode.picking_specific_rule(/datum/dynamic_ruleset/midround/autotraitor)
//////////////////////////////////////////
// //
// BLOOD BROTHERS //
// //
//////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/traitorbro
name = "Blood Brothers"
antag_flag = ROLE_BROTHER
antag_datum = /datum/antagonist/brother/
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 2
weight = 4
cost = 10
requirements = list(40,30,30,20,20,15,15,15,10,10)
high_population_requirement = 15
var/list/datum/team/brother_team/pre_brother_teams = list()
var/const/team_amount = 2 // Hard limit on brother teams if scaling is turned off
var/const/min_team_size = 2
/datum/dynamic_ruleset/roundstart/traitorbro/pre_execute()
var/num_teams = team_amount
var/bsc = CONFIG_GET(number/brother_scaling_coeff)
if(bsc)
num_teams = max(1, round(num_players() / bsc))
for(var/j = 1 to num_teams)
if(candidates.len < min_team_size || candidates.len < required_candidates)
break
var/datum/team/brother_team/team = new
var/team_size = prob(10) ? min(3, candidates.len) : 2
for(var/k = 1 to team_size)
var/mob/bro = pick(candidates)
candidates -= bro
assigned += bro.mind
team.add_member(bro.mind)
bro.mind.special_role = "brother"
bro.mind.restricted_roles = restricted_roles
pre_brother_teams += team
return TRUE
/datum/dynamic_ruleset/roundstart/traitorbro/execute()
for(var/datum/team/brother_team/team in pre_brother_teams)
team.pick_meeting_area()
team.forge_brother_objectives()
for(var/datum/mind/M in team.members)
M.add_antag_datum(/datum/antagonist/brother, team)
team.update_name()
mode.brother_teams += pre_brother_teams
return TRUE
//////////////////////////////////////////////
// //
// CHANGELINGS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/changeling
name = "Changelings"
antag_flag = ROLE_CHANGELING
antag_datum = /datum/antagonist/changeling
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 3
cost = 30
requirements = list(80,70,60,50,40,20,20,10,10,10)
high_population_requirement = 10
var/team_mode_probability = 30
/datum/dynamic_ruleset/roundstart/changeling/pre_execute()
var/num_changelings = min(round(mode.candidates.len / 10) + 1, candidates.len)
for (var/i = 1 to num_changelings)
var/mob/M = pick(candidates)
candidates -= M
assigned += M.mind
M.mind.restricted_roles = restricted_roles
M.mind.special_role = ROLE_CHANGELING
return TRUE
/datum/dynamic_ruleset/roundstart/changeling/execute()
var/team_mode = FALSE
if(prob(team_mode_probability))
team_mode = TRUE
var/list/team_objectives = subtypesof(/datum/objective/changeling_team_objective)
var/list/possible_team_objectives = list()
for(var/T in team_objectives)
var/datum/objective/changeling_team_objective/CTO = T
if(assigned.len >= initial(CTO.min_lings))
possible_team_objectives += T
if(possible_team_objectives.len && prob(20*assigned.len))
GLOB.changeling_team_objective_type = pick(possible_team_objectives)
for(var/datum/mind/changeling in assigned)
var/datum/antagonist/changeling/new_antag = new antag_datum()
new_antag.team_mode = team_mode
changeling.add_antag_datum(new_antag)
return TRUE
//////////////////////////////////////////////
// //
// WIZARDS //
// //
//////////////////////////////////////////////
// Dynamic is a wonderful thing that adds wizards to every round and then adds even more wizards during the round.
/datum/dynamic_ruleset/roundstart/wizard
name = "Wizard"
antag_flag = ROLE_WIZARD
antag_datum = /datum/antagonist/wizard
minimum_required_age = 14
restricted_roles = list("Head of Security", "Captain") // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted
required_candidates = 1
weight = 1
cost = 30
requirements = list(90,90,70,40,30,20,10,10,10,10)
high_population_requirement = 10
var/list/roundstart_wizards = list()
/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0)
if(GLOB.wizardstart.len == 0)
log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.")
message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.")
return FALSE
return ..()
/datum/dynamic_ruleset/roundstart/wizard/pre_execute()
if(GLOB.wizardstart.len == 0)
return FALSE
var/mob/M = pick(candidates)
if (M)
candidates -= M
assigned += M.mind
M.mind.assigned_role = ROLE_WIZARD
M.mind.special_role = ROLE_WIZARD
return TRUE
/datum/dynamic_ruleset/roundstart/wizard/execute()
for(var/datum/mind/M in assigned)
M.current.forceMove(pick(GLOB.wizardstart))
M.add_antag_datum(new antag_datum())
return TRUE
//////////////////////////////////////////////
// //
// BLOOD CULT //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/bloodcult
name = "Blood Cult"
antag_flag = ROLE_CULTIST
antag_datum = /datum/antagonist/cult
minimum_required_age = 14
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 2
weight = 3
cost = 30
requirements = list(100,90,80,60,40,30,10,10,10,10)
high_population_requirement = 10
pop_per_requirement = 5
flags = HIGHLANDER_RULESET
var/cultist_cap = list(2,2,2,3,3,4,4,4,4,4)
var/datum/team/cult/main_cult
/datum/dynamic_ruleset/roundstart/bloodcult/ready(forced = FALSE)
var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1)
required_candidates = cultist_cap[indice_pop]
. = ..()
/datum/dynamic_ruleset/roundstart/bloodcult/pre_execute()
var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1)
var/cultists = cultist_cap[indice_pop]
for(var/cultists_number = 1 to cultists)
if(candidates.len <= 0)
break
var/mob/M = pick(candidates)
candidates -= M
assigned += M.mind
M.mind.special_role = ROLE_CULTIST
M.mind.restricted_roles = restricted_roles
return TRUE
/datum/dynamic_ruleset/roundstart/bloodcult/execute()
main_cult = new
for(var/datum/mind/M in assigned)
var/datum/antagonist/cult/new_cultist = new antag_datum()
new_cultist.cult_team = main_cult
new_cultist.give_equipment = TRUE
M.add_antag_datum(new_cultist)
main_cult.setup_objectives()
return TRUE
/datum/dynamic_ruleset/roundstart/bloodcult/round_result()
..()
if(main_cult.check_cult_victory())
SSticker.mode_result = "win - cult win"
SSticker.news_report = CULT_SUMMON
else
SSticker.mode_result = "loss - staff stopped the cult"
SSticker.news_report = CULT_FAILURE
//////////////////////////////////////////////
// //
// NUCLEAR OPERATIVES //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/nuclear
name = "Nuclear Emergency"
antag_flag = ROLE_OPERATIVE
antag_datum = /datum/antagonist/nukeop
var/datum/antagonist/antag_leader_datum = /datum/antagonist/nukeop/leader
minimum_required_age = 14
restricted_roles = list("Head of Security", "Captain") // Just to be sure that a nukie getting picked won't ever imply a Captain or HoS not getting drafted
required_candidates = 5
weight = 3
cost = 40
requirements = list(90,90,90,80,60,40,30,20,10,10)
high_population_requirement = 10
pop_per_requirement = 5
flags = HIGHLANDER_RULESET
var/operative_cap = list(2,2,2,3,3,3,4,4,5,5)
var/datum/team/nuclear/nuke_team
/datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE)
var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1)
required_candidates = operative_cap[indice_pop]
. = ..()
/datum/dynamic_ruleset/roundstart/nuclear/pre_execute()
// If ready() did its job, candidates should have 5 or more members in it
var/indice_pop = min(10,round(mode.roundstart_pop_ready/5)+1)
var/operatives = operative_cap[indice_pop]
for(var/operatives_number = 1 to operatives)
if(candidates.len <= 0)
break
var/mob/M = pick(candidates)
candidates -= M
assigned += M.mind
M.mind.assigned_role = "Nuclear Operative"
M.mind.special_role = "Nuclear Operative"
return TRUE
/datum/dynamic_ruleset/roundstart/nuclear/execute()
var/leader = TRUE
for(var/datum/mind/M in assigned)
if (leader)
leader = FALSE
var/datum/antagonist/nukeop/leader/new_op = M.add_antag_datum(antag_leader_datum)
nuke_team = new_op.nuke_team
else
var/datum/antagonist/nukeop/new_op = new antag_datum()
M.add_antag_datum(new_op)
return TRUE
/datum/dynamic_ruleset/roundstart/nuclear/round_result()
var result = nuke_team.get_result()
switch(result)
if(NUKE_RESULT_FLUKE)
SSticker.mode_result = "loss - syndicate nuked - disk secured"
SSticker.news_report = NUKE_SYNDICATE_BASE
if(NUKE_RESULT_NUKE_WIN)
SSticker.mode_result = "win - syndicate nuke"
SSticker.news_report = STATION_NUKED
if(NUKE_RESULT_NOSURVIVORS)
SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time"
SSticker.news_report = STATION_NUKED
if(NUKE_RESULT_WRONG_STATION)
SSticker.mode_result = "halfwin - blew wrong station"
SSticker.news_report = NUKE_MISS
if(NUKE_RESULT_WRONG_STATION_DEAD)
SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time"
SSticker.news_report = NUKE_MISS
if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead"
SSticker.news_report = OPERATIVES_KILLED
if(NUKE_RESULT_CREW_WIN)
SSticker.mode_result = "loss - evacuation - disk secured"
SSticker.news_report = OPERATIVES_KILLED
if(NUKE_RESULT_DISK_LOST)
SSticker.mode_result = "halfwin - evacuation - disk not secured"
SSticker.news_report = OPERATIVE_SKIRMISH
if(NUKE_RESULT_DISK_STOLEN)
SSticker.mode_result = "halfwin - detonation averted"
SSticker.news_report = OPERATIVE_SKIRMISH
else
SSticker.mode_result = "halfwin - interrupted"
SSticker.news_report = OPERATIVE_SKIRMISH
//////////////////////////////////////////////
// //
// REVS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/delayed/revs
name = "Revolution"
persistent = TRUE
antag_flag = ROLE_REV_HEAD
antag_flag_override = ROLE_REV
antag_datum = /datum/antagonist/rev/head
minimum_required_age = 14
restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 3
weight = 2
cost = 35
requirements = list(101,101,70,40,30,20,10,10,10,10)
high_population_requirement = 10
delay = 5 MINUTES
flags = HIGHLANDER_RULESET
// I give up, just there should be enough heads with 35 players...
minimum_players = 35
var/datum/team/revolution/revolution
var/finished = 0
/datum/dynamic_ruleset/roundstart/delayed/revs/execute()
var/max_canditates = 4
revolution = new()
for(var/i = 1 to max_canditates)
if(candidates.len <= 0)
break
var/mob/M = pick(candidates)
candidates -= M
assigned += M.mind
M.mind.restricted_roles = restricted_roles
M.mind.special_role = antag_flag
var/datum/antagonist/rev/head/new_head = new antag_datum()
new_head.give_flash = TRUE
new_head.give_hud = TRUE
new_head.remove_clumsy = TRUE
M.mind.add_antag_datum(new_head,revolution)
revolution.update_objectives()
revolution.update_heads()
SSshuttle.registerHostileEnvironment(src)
return TRUE
/datum/dynamic_ruleset/roundstart/delayed/revs/rule_process()
if(check_rev_victory())
finished = 1
else if(check_heads_victory())
finished = 2
return
/datum/dynamic_ruleset/roundstart/delayed/revs/check_finished()
if(CONFIG_GET(keyed_list/continuous)["revolution"])
if(finished)
SSshuttle.clearHostileEnvironment(src)
return ..()
if(finished != 0)
return TRUE
else
return ..()
/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_rev_victory()
for(var/datum/objective/mutiny/objective in revolution.objectives)
if(!(objective.check_completion()))
return FALSE
return TRUE
/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_heads_victory()
for(var/datum/mind/rev_mind in revolution.head_revolutionaries())
var/turf/T = get_turf(rev_mind.current)
if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z))
if(ishuman(rev_mind.current) || ismonkey(rev_mind.current))
return FALSE
return TRUE
/datum/dynamic_ruleset/roundstart/delayed/revs/round_result()
if(finished == 1)
SSticker.mode_result = "win - heads killed"
SSticker.news_report = REVS_WIN
else if(finished == 2)
SSticker.mode_result = "loss - rev heads killed"
SSticker.news_report = REVS_LOSE
// Admin only rulesets. The threat requirement is 101 so it is not possible to roll them.
//////////////////////////////////////////////
// //
// EXTENDED //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/extended
name = "Extended"
antag_flag = null
antag_datum = null
restricted_roles = list()
required_candidates = 0
weight = 3
cost = 0
requirements = list(101,101,101,101,101,101,101,101,101,101)
high_population_requirement = 101
/datum/dynamic_ruleset/roundstart/extended/pre_execute()
message_admins("Starting a round of extended.")
log_game("Starting a round of extended.")
mode.spend_threat(mode.threat)
return TRUE
//////////////////////////////////////////////
// //
// CLOCKCULT //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/clockcult
name = "Clockcult"
antag_flag = ROLE_SERVANT_OF_RATVAR
antag_datum = /datum/antagonist/clockcult
restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 4
weight = 3
cost = 0
requirements = list(101,101,101,101,101,101,101,101,101,101)
high_population_requirement = 101
flags = HIGHLANDER_RULESET
var/ark_time
/datum/dynamic_ruleset/roundstart/clockcult/pre_execute()
var/list/errorList = list()
var/list/reebes = SSmapping.LoadGroup(errorList, "Reebe", "map_files/generic", "City_of_Cogs.dmm", default_traits = ZTRAITS_REEBE, silent = TRUE)
if(errorList.len)
message_admins("Reebe failed to load!")
log_game("Reebe failed to load!")
return FALSE
for(var/datum/parsed_map/PM in reebes)
PM.initTemplateBounds()
var/starter_servants = 4
var/number_players = num_players()
if(number_players > 30)
number_players -= 30
starter_servants += round(number_players / 10)
starter_servants = min(starter_servants, 8)
for (var/i in 1 to starter_servants)
var/mob/servant = pick(candidates)
candidates -= servant
assigned += servant.mind
servant.mind.assigned_role = ROLE_SERVANT_OF_RATVAR
servant.mind.special_role = ROLE_SERVANT_OF_RATVAR
ark_time = 30 + round((number_players / 5))
ark_time = min(ark_time, 35)
return TRUE
/datum/dynamic_ruleset/roundstart/clockcult/execute()
var/list/spread_out_spawns = GLOB.servant_spawns.Copy()
for(var/datum/mind/servant in assigned)
var/mob/S = servant.current
if(!spread_out_spawns.len)
spread_out_spawns = GLOB.servant_spawns.Copy()
log_game("[key_name(servant)] was made an initial servant of Ratvar")
var/turf/T = pick_n_take(spread_out_spawns)
S.forceMove(T)
greet_servant(S)
equip_servant(S)
add_servant_of_ratvar(S, TRUE)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar //that's a mouthful
G.final_countdown(ark_time)
return TRUE
/datum/dynamic_ruleset/roundstart/clockcult/proc/greet_servant(mob/M) //Description of their role
if(!M)
return 0
to_chat(M, "<span class='bold large_brass'>You are a servant of Ratvar, the Clockwork Justiciar!</span>")
to_chat(M, "<span class='brass'>You have approximately <b>[ark_time]</b> minutes until the Ark activates.</span>")
to_chat(M, "<span class='brass'>Unlock <b>Script</b> scripture by converting a new servant.</span>")
to_chat(M, "<span class='brass'><b>Application</b> scripture will be unlocked halfway until the Ark's activation.</span>")
M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE)
return 1
/datum/dynamic_ruleset/roundstart/clockcult/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob, with one of each component
if(!M || !ishuman(M))
return FALSE
var/mob/living/carbon/human/L = M
L.equipOutfit(/datum/outfit/servant_of_ratvar)
var/obj/item/clockwork/slab/S = new
var/slot = "At your feet"
var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK, "On your belt" = SLOT_BELT)
if(ishuman(L))
var/mob/living/carbon/human/H = L
slot = H.equip_in_one_of_slots(S, slots)
if(slot == "In your backpack")
slot = "In your [H.back.name]"
if(slot == "At your feet")
if(!S.forceMove(get_turf(L)))
qdel(S)
if(S && !QDELETED(S))
to_chat(L, "<span class='bold large_brass'>There is a paper in your backpack! It'll tell you if anything's changed, as well as what to expect.</span>")
to_chat(L, "<span class='alloy'>[slot] is a <b>clockwork slab</b>, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \
as a servant, you can find a concise tutorial in the Recollection category of its interface.</span>")
to_chat(L, "<span class='alloy italics'>If you want more information, you can read <a href=\"https://tgstation13.org/wiki/Clockwork_Cult\">the wiki page</a> to learn more.</span>")
return TRUE
return FALSE
/datum/dynamic_ruleset/roundstart/clockcult/round_result()
if(GLOB.clockwork_gateway_activated)
SSticker.news_report = CLOCK_SUMMON
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
else
SSticker.news_report = CULT_FAILURE
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
//////////////////////////////////////////////
// //
// CLOWN OPS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/nuclear/clown_ops
name = "Clown Ops"
antag_datum = /datum/antagonist/nukeop/clownop
antag_leader_datum = /datum/antagonist/nukeop/leader/clownop
requirements = list(101,101,101,101,101,101,101,101,101,101)
high_population_requirement = 101
/datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute()
. = ..()
if(.)
for(var/obj/machinery/nuclearbomb/syndicate/S in GLOB.nuke_list)
var/turf/T = get_turf(S)
if(T)
qdel(S)
new /obj/machinery/nuclearbomb/syndicate/bananium(T)
for(var/datum/mind/V in assigned)
V.assigned_role = "Clown Operative"
V.special_role = "Clown Operative"
//////////////////////////////////////////////
// //
// DEVIL //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/devil
name = "Devil"
antag_flag = ROLE_DEVIL
antag_datum = /datum/antagonist/devil
restricted_roles = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI")
required_candidates = 1
weight = 3
cost = 0
requirements = list(101,101,101,101,101,101,101,101,101,101)
high_population_requirement = 101
var/devil_limit = 4 // Hard limit on devils if scaling is turned off
/datum/dynamic_ruleset/roundstart/devil/pre_execute()
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
var/num_devils = 1
if(tsc)
num_devils = max(required_candidates, min(round(num_players() / (tsc * 3)) + 2, round(num_players() / (tsc * 1.5))))
else
num_devils = max(required_candidates, min(num_players(), devil_limit))
for(var/j = 0, j < num_devils, j++)
if (!candidates.len)
break
var/mob/devil = pick(candidates)
assigned += devil
candidates -= devil
devil.mind.special_role = ROLE_DEVIL
devil.mind.restricted_roles = restricted_roles
log_game("[key_name(devil)] has been selected as a devil")
return TRUE
/datum/dynamic_ruleset/roundstart/devil/execute()
for(var/datum/mind/devil in assigned)
add_devil(devil.current, ascendable = TRUE)
add_devil_objectives(devil,2)
return TRUE
/datum/dynamic_ruleset/roundstart/devil/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
var/datum/antagonist/devil/D = devil_mind.has_antag_datum(/datum/antagonist/devil)
for(var/i = 1 to quantity)
var/type = pick(validtypes)
var/datum/objective/devil/objective = new type(null)
objective.owner = devil_mind
D.objectives += objective
if(!istype(objective, /datum/objective/devil/buy_target))
validtypes -= type
else
objective.find_target()
//////////////////////////////////////////////
// //
// MONKEY //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/monkey
name = "Monkey"
antag_flag = ROLE_MONKEY
antag_datum = /datum/antagonist/monkey/leader
restricted_roles = list("Cyborg", "AI")
required_candidates = 1
weight = 3
cost = 0
requirements = list(101,101,101,101,101,101,101,101,101,101)
high_population_requirement = 101
var/players_per_carrier = 30
var/monkeys_to_win = 1
var/escaped_monkeys = 0
var/datum/team/monkey/monkey_team
/datum/dynamic_ruleset/roundstart/monkey/pre_execute()
var/carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1)
for(var/j = 0, j < carriers_to_make, j++)
if (!candidates.len)
break
var/mob/carrier = pick(candidates)
candidates -= carrier
assigned += carrier.mind
carrier.mind.special_role = "Monkey Leader"
carrier.mind.restricted_roles = restricted_roles
log_game("[key_name(carrier)] has been selected as a Jungle Fever carrier")
return TRUE
/datum/dynamic_ruleset/roundstart/monkey/execute()
for(var/datum/mind/carrier in assigned)
var/datum/antagonist/monkey/M = add_monkey_leader(carrier)
if(M)
monkey_team = M.monkey_team
return TRUE
/datum/dynamic_ruleset/roundstart/monkey/proc/check_monkey_victory()
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
return FALSE
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if (M.HasDisease(D))
if(M.onCentCom() || M.onSyndieBase())
escaped_monkeys++
if(escaped_monkeys >= monkeys_to_win)
return TRUE
else
return FALSE
// This does not get called. Look into making it work.
/datum/dynamic_ruleset/roundstart/monkey/round_result()
if(check_monkey_victory())
SSticker.mode_result = "win - monkey win"
else
SSticker.mode_result = "loss - staff stopped the monkeys"
//////////////////////////////////////////////
// //
// METEOR //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/meteor
name = "Meteor"
persistent = TRUE
required_candidates = 0
weight = 3
cost = 0
requirements = list(101,101,101,101,101,101,101,101,101,101)
high_population_requirement = 101
var/meteordelay = 2000
var/nometeors = 0
var/rampupdelta = 5
/datum/dynamic_ruleset/roundstart/meteor/rule_process()
if(nometeors || meteordelay > world.time - SSticker.round_start_time)
return
var/list/wavetype = GLOB.meteors_normal
var/meteorminutes = (world.time - SSticker.round_start_time - meteordelay) / 10 / 60
if (prob(meteorminutes))
wavetype = GLOB.meteors_threatening
if (prob(meteorminutes/2))
wavetype = GLOB.meteors_catastrophic
var/ramp_up_final = CLAMP(round(meteorminutes/rampupdelta), 1, 10)
spawn_meteors(ramp_up_final, wavetype)
+57
View File
@@ -0,0 +1,57 @@
# DYNAMIC
## ROUNDSTART
Dynamic rolls threat based on a special sauce formula:
"dynamic_curve_width \* tan((3.1416 \* (rand() - 0.5) \* 57.2957795)) + dynamic_curve_centre"
Latejoin and midround injection cooldowns are set using exponential distribution between
5 minutes and 25 for latejoin
15 minutes and 35 for midround
this value is then added to world.time and assigned to the injection cooldown variables.
rigged_roundstart() is called instead if there are forced rules (an admin set the mode)
can_start() -> pre_setup() -> roundstart() OR rigged_roundstart() -> picking_roundstart_rule(drafted_rules) -> post_setup()
## PROCESS
Calls rule_process on every rule which is in the current_rules list.
Every sixty seconds, update_playercounts()
Midround injection time is checked against world.time to see if an injection should happen.
If midround injection time is lower than world.time, it updates playercounts again, then tries to inject and generates a new cooldown regardless of whether a rule is picked.
## LATEJOIN
make_antag_chance(newPlayer) -> [For each latespawn rule...]
-> acceptable(living players, threat_level) -> trim_candidates() -> ready(forced=FALSE)
**If true, add to drafted rules
**NOTE that acceptable uses threat_level not threat!
**NOTE Latejoin timer is ONLY reset if at least one rule was drafted.
**NOTE the new_player.dm AttemptLateSpawn() calls OnPostSetup for all roles (unless assigned role is MODE)
[After collecting all draftble rules...]
-> picking_latejoin_ruleset(drafted_rules) -> spend threat -> ruleset.execute()
## MIDROUND
process() -> [For each midround rule...]
-> acceptable(living players, threat_level) -> trim_candidates() -> ready(forced=FALSE)
[After collecting all draftble rules...]
-> picking_midround_ruleset(drafted_rules) -> spend threat -> ruleset.execute()
## FORCED
For latejoin, it simply sets forced_latejoin_rule
make_antag_chance(newPlayer) -> trim_candidates() -> ready(forced=TRUE) **NOTE no acceptable() call
For midround, calls the below proc with forced = TRUE
picking_specific_rule(ruletype,forced) -> forced OR acceptable(living_players, threat_level) -> trim_candidates() -> ready(forced) -> spend threat -> execute()
**NOTE specific rule can be called by RS traitor->MR autotraitor w/ forced=FALSE
**NOTE that due to short circuiting acceptable() need not be called if forced.
## RULESET
acceptable(population,threat) just checks if enough threat_level for population indice.
**NOTE that we currently only send threat_level as the second arg, not threat.
ready(forced) checks if enough candidates and calls the map's map_ruleset(dynamic_ruleset) at the parent level
trim_candidates() varies significantly according to the ruleset type
Roundstart: All candidates are new_player mobs. Check them for standard stuff: connected, desire role, not banned, etc.
**NOTE Roundstart deals with both candidates (trimmed list of valid players) and mode.candidates (everyone readied up). Don't confuse them!
Latejoin: Only one candidate, the latejoiner. Standard checks.
Midround: Instead of building a single list candidates, candidates contains four lists: living, dead, observing, and living antags. Standard checks in trim_list(list).
Midround - Rulesets have additional types
/from_ghosts: execute() -> send_applications() -> review_applications() -> finish_setup(mob/newcharacter, index) -> setup_role(role)
**NOTE: execute() here adds dead players and observers to candidates list
+6 -1
View File
@@ -24,6 +24,7 @@
var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist
var/list/protected_jobs = list() // Jobs that can't be traitors because
var/list/required_jobs = list() // alternative required job groups eg list(list(cap=1),list(hos=1,sec=2)) translates to one captain OR one hos and two secmans
var/required_players = 0
var/maximum_players = -1 // -1 is no maximum, positive numbers limit the selection of a mode on overstaffed stations
var/required_enemies = 0
@@ -355,7 +356,7 @@
// Ultimate randomizing code right here
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
if(player.client && player.ready == PLAYER_READY_TO_PLAY && player.check_preferences())
players += player
// Shuffling, the players list is now ping-independent!!!
@@ -558,3 +559,7 @@
SSticker.news_report = STATION_EVACUATED
if(SSshuttle.emergency.is_hijacked())
SSticker.news_report = SHUTTLE_HIJACK
/// Mode specific admin panel.
/datum/game_mode/proc/admin_panel()
return
+2 -1
View File
@@ -3,7 +3,8 @@
name = "overthrow"
config_tag = "overthrow"
antag_flag = ROLE_OVERTHROW
restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 20 // the core idea is of a swift, bloodless coup, so it shouldn't be as chaotic as revs.
required_enemies = 2 // minimum two teams, otherwise it's just nerfed revs.
recommended_enemies = 4
+2 -1
View File
@@ -12,7 +12,8 @@
config_tag = "revolution"
antag_flag = ROLE_REV
false_report_weight = 10
restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 30
required_enemies = 2
recommended_enemies = 3
+1 -1
View File
@@ -96,4 +96,4 @@
/datum/game_mode/traitor/generate_report()
return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \
Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
+2
View File
@@ -193,8 +193,10 @@
to_chat(usr, "<span class='warning'>Chem System Re-route detected, results may not be as expected!</span>")
/obj/machinery/sleeper/emag_act(mob/user)
. = ..()
scramble_chem_buttons()
to_chat(user, "<span class='warning'>You scramble the sleeper's user interface!</span>")
return TRUE
/obj/machinery/sleeper/proc/inject_chem(chem, mob/user)
if((chem in available_chems) && chem_allowed(chem))
+102 -15
View File
@@ -113,6 +113,11 @@ Class Procs:
var/atom/movable/occupant = null
var/speed_process = FALSE // Process as fast as possible?
var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created
var/obj/item/card/id/inserted_scan_id
var/obj/item/card/id/inserted_modify_id
var/list/region_access = null // For the identification console (card.dm)
var/list/head_subordinates = null // For the identification console (card.dm)
var/authenticated = 0 // For the identification console (card.dm)
var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_SET_MACHINE
@@ -131,7 +136,7 @@ Class Procs:
else
START_PROCESSING(SSfastprocess, src)
power_change()
AddComponent(/datum/component/redirect, list(COMSIG_ENTER_AREA = CALLBACK(src, .proc/power_change)))
RegisterSignal(src, COMSIG_ENTER_AREA, .proc/power_change)
if (occupant_typecache)
occupant_typecache = typecacheof(occupant_typecache)
@@ -143,6 +148,10 @@ Class Procs:
else
STOP_PROCESSING(SSfastprocess, src)
dropContents()
if(length(component_parts))
for(var/atom/A in component_parts)
qdel(A)
component_parts.Cut()
return ..()
/obj/machinery/proc/locate_machinery()
@@ -179,12 +188,15 @@ Class Procs:
L.update_canmove()
occupant = null
/obj/machinery/proc/can_be_occupant(atom/movable/am)
return occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am)
/obj/machinery/proc/close_machine(atom/movable/target = null)
state_open = FALSE
density = TRUE
if(!target)
for(var/am in loc)
if (!(occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am)))
if (!(can_be_occupant(am)))
continue
var/atom/movable/AM = am
if(AM.has_buckled_mobs())
@@ -311,6 +323,7 @@ Class Procs:
spawn_frame(disassembled)
for(var/obj/item/I in component_parts)
I.forceMove(loc)
component_parts.Cut()
qdel(src)
/obj/machinery/proc/spawn_frame(disassembled)
@@ -348,8 +361,8 @@ Class Procs:
panel_open = FALSE
icon_state = icon_state_closed
to_chat(user, "<span class='notice'>You close the maintenance hatch of [src].</span>")
return 1
return 0
return TRUE
return FALSE
/obj/machinery/proc/default_change_direction_wrench(mob/user, obj/item/I)
if(panel_open && I.tool_behaviour == TOOL_WRENCH)
@@ -401,7 +414,7 @@ Class Procs:
var/obj/item/circuitboard/machine/CB = locate(/obj/item/circuitboard/machine) in component_parts
var/P
if(W.works_from_distance)
display_parts(user)
to_chat(user, display_parts(user))
for(var/obj/item/A in component_parts)
for(var/D in CB.req_components)
if(ispath(A.type, D))
@@ -429,34 +442,38 @@ Class Procs:
break
RefreshParts()
else
display_parts(user)
to_chat(user, display_parts(user))
if(shouldplaysound)
W.play_rped_sound()
return TRUE
return FALSE
/obj/machinery/proc/display_parts(mob/user)
to_chat(user, "<span class='notice'>It contains the following parts:</span>")
. = list()
. += "<span class='notice'>It contains the following parts:</span>"
for(var/obj/item/C in component_parts)
to_chat(user, "<span class='notice'>[icon2html(C, user)] \A [C].</span>")
. += "<span class='notice'>[icon2html(C, user)] \A [C].</span>"
. = jointext(., "")
/obj/machinery/examine(mob/user)
..()
. = ..()
if(stat & BROKEN)
to_chat(user, "<span class='notice'>It looks broken and non-functional.</span>")
. += "<span class='notice'>It looks broken and non-functional.</span>"
if(!(resistance_flags & INDESTRUCTIBLE))
if(resistance_flags & ON_FIRE)
to_chat(user, "<span class='warning'>It's on fire!</span>")
. += "<span class='warning'>It's on fire!</span>"
var/healthpercent = (obj_integrity/max_integrity) * 100
switch(healthpercent)
if(50 to 99)
to_chat(user, "It looks slightly damaged.")
. += "It looks slightly damaged."
if(25 to 50)
to_chat(user, "It appears heavily damaged.")
. += "It appears heavily damaged."
if(0 to 25)
to_chat(user, "<span class='warning'>It's falling apart!</span>")
. += "<span class='warning'>It's falling apart!</span>"
if(user.research_scanner && component_parts)
display_parts(user)
. += display_parts(user, TRUE)
if(inserted_scan_id || inserted_modify_id)
. += "<span class='notice'>Alt-click to eject the ID card.</span>"
//called on machinery construction (i.e from frame to machinery) but not on initialization
/obj/machinery/proc/on_construction()
@@ -490,3 +507,73 @@ Class Procs:
. = . % 9
AM.pixel_x = -8 + ((.%3)*8)
AM.pixel_y = -8 + (round( . / 3)*8)
/obj/machinery/proc/id_insert_scan(mob/user, obj/item/card/id/I)
I = user.get_active_held_item()
if(istype(I))
if(inserted_scan_id)
to_chat(user, "<span class='warning'>There's already an ID card in the console!</span>")
return
if(!user.transferItemToLoc(I, src))
return
inserted_scan_id = I
user.visible_message("<span class='notice'>[user] inserts an ID card into the console.</span>", \
"<span class='notice'>You insert the ID card into the console.</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
updateUsrDialog()
/obj/machinery/proc/id_eject_scan(mob/user)
if(!inserted_scan_id)
to_chat(user, "<span class='warning'>There's no ID card in the console!</span>")
return
if(inserted_scan_id)
inserted_scan_id.forceMove(drop_location())
if(!issilicon(user) && Adjacent(user))
user.put_in_hands(inserted_scan_id)
inserted_scan_id = null
user.visible_message("<span class='notice'>[user] gets an ID card from the console.</span>", \
"<span class='notice'>You get the ID card from the console.</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
updateUsrDialog()
/obj/machinery/proc/id_eject_modify(mob/user)
if(inserted_modify_id)
GLOB.data_core.manifest_modify(inserted_modify_id.registered_name, inserted_modify_id.assignment)
inserted_modify_id.update_label()
inserted_modify_id.forceMove(drop_location())
if(!issilicon(user) && Adjacent(user))
user.put_in_hands(inserted_modify_id)
user.visible_message("<span class='notice'>[user] gets an ID card from the console.</span>", \
"<span class='notice'>You get the ID card from the console.</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
inserted_modify_id = null
region_access = null
head_subordinates = null
updateUsrDialog()
/obj/machinery/proc/id_insert_modify(mob/user)
var/obj/item/card/id/I = user.get_active_held_item()
if(istype(I))
if(inserted_modify_id)
to_chat(user, "<span class='warning'>There's already an ID card in the console!</span>")
return
if(!user.transferItemToLoc(I, src))
return
inserted_modify_id = I
user.visible_message("<span class='notice'>[user] inserts an ID card into the console.</span>", \
"<span class='notice'>You insert the ID card into the console.</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
updateUsrDialog()
/obj/machinery/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !issilicon(user)) || !is_operational())
return
if(inserted_modify_id)
id_eject_modify(user)
authenticated = FALSE
return
if(inserted_scan_id)
id_eject_scan(user)
authenticated = FALSE
return
@@ -177,7 +177,9 @@ GLOBAL_LIST_EMPTY(announcement_systems)
act_up()
/obj/machinery/announcement_system/emag_act()
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
act_up()
return TRUE
+2
View File
@@ -101,12 +101,14 @@
return ..()
/obj/machinery/button/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
req_access = list()
req_one_access = list()
playsound(src, "sparks", 100, 1)
obj_flags |= EMAGGED
return TRUE
/obj/machinery/button/attack_ai(mob/user)
if(!panel_open)
+2
View File
@@ -320,10 +320,12 @@
return ..()
/obj/machinery/clonepod/emag_act(mob/user)
. = ..()
if(!occupant)
return
to_chat(user, "<span class='warning'>You corrupt the genetic compiler.</span>")
malfunction()
return TRUE
//Put messages in the connected computer's temp var for display.
/obj/machinery/clonepod/proc/connected_message(message)
+6 -3
View File
@@ -11,7 +11,6 @@
var/list/result_filters //For sorting the results
var/checking_logs = 0
var/list/logs
var/authenticated = 0
var/auth_id = "\[NULL\]"
/obj/machinery/computer/apc_control/Initialize()
@@ -185,15 +184,19 @@
ui_interact(usr) //Refresh the UI after a filter changes
/obj/machinery/computer/apc_control/emag_act(mob/user)
. = ..()
if(!authenticated)
to_chat(user, "<span class='warning'>You bypass [src]'s access requirements using your emag.</span>")
authenticated = TRUE
log_activity("logged in")
else if(!(obj_flags & EMAGGED))
else
if(obj_flags & EMAGGED)
return
user.visible_message("<span class='warning'>You emag [src], disabling precise logging and allowing you to clear logs.</span>")
log_game("[key_name(user)] emagged [src] at [AREACOORD(src)], disabling operator tracking.")
obj_flags |= EMAGGED
playsound(src, "sparks", 50, 1)
playsound(src, "sparks", 50, 1)
return TRUE
/obj/machinery/computer/apc_control/proc/log_activity(log_text)
var/op_string = operator && !(obj_flags & EMAGGED) ? operator : "\[NULL OPERATOR\]"
@@ -186,6 +186,7 @@
/obj/machinery/computer/arcade/battle/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "<span class='warning'>A mesmerizing Rhumba beat starts playing from the arcade machine's speakers!</span>")
@@ -202,5 +203,5 @@
enemy_name = "Cuban Pete"
name = "Outbomb Cuban Pete"
updateUsrDialog()
return TRUE
@@ -284,6 +284,7 @@
return
/obj/machinery/computer/arcade/minesweeper/emag_act(mob/user)
. = ..()
if(CHECK_BITFIELD(obj_flags, EMAGGED))
return
desc = "An arcade machine that generates grids. It's clunking and sparking everywhere, almost as if threatening to explode at any moment!"
@@ -298,6 +299,7 @@
to_chat(user, "<span class='warning'>The machine buzzes and sparks... the game has been reset!</span>")
playsound(user, 'sound/machines/buzz-sigh.ogg', 100, 0, extrarange = 3, falloff = 10) //Loud buzz
game_status = MINESWEEPER_GAME_MAIN_MENU
return TRUE
/obj/machinery/computer/arcade/minesweeper/proc/custom_generation(mob/user)
playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10) //Entered into the menu so ping sound
@@ -736,6 +736,7 @@
desc = "Learn how our ancestors got to Orion, and have fun in the process!"
/obj/machinery/computer/arcade/orion_trail/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "<span class='notice'>You override the cheat code menu and skip to Cheat #[rand(1, 50)]: Realism Mode.</span>")
@@ -743,6 +744,7 @@
desc = "Learn how our ancestors got to Orion, and try not to die in the process!"
newgame()
obj_flags |= EMAGGED
return TRUE
/mob/living/simple_animal/hostile/syndicate/ranged/smg/orion
name = "spaceport security"
-3
View File
@@ -13,11 +13,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
circuit = /obj/item/circuitboard/computer/card
var/obj/item/card/id/scan = null
var/obj/item/card/id/modify = null
var/authenticated = 0
var/mode = 0
var/printing = null
var/list/region_access = null
var/list/head_subordinates = null
var/target_dept = 0 //Which department this computer has access to. 0=all departments
//Cooldown for closing positions in seconds
-3
View File
@@ -64,9 +64,6 @@
if(!(scanner && LAZYLEN(pods) && autoprocess))
return
if(scanner.occupant && scanner.scan_level > 2)
scan_occupant(scanner.occupant)
for(var/datum/data/record/R in records)
var/obj/machinery/clonepod/pod = GetAvailableEfficientPod(R.fields["mind"])
@@ -6,7 +6,6 @@
icon_keyboard = "tech_key"
req_access = list(ACCESS_HEADS)
circuit = /obj/item/circuitboard/computer/communications
var/authenticated = 0
var/auth_id = "Unknown" //Who is currently logged in?
var/list/datum/comm_message/messages = list()
var/datum/comm_message/currmsg
@@ -432,6 +431,7 @@
return ..()
/obj/machinery/computer/communications/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -440,6 +440,7 @@
authenticated = 2
to_chat(user, "<span class='danger'>You scramble the communication routing circuits!</span>")
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return TRUE
/obj/machinery/computer/communications/ui_interact(mob/user)
. = ..()
+139 -147
View File
@@ -7,13 +7,10 @@
icon_keyboard = "med_key"
req_one_access = list(ACCESS_MEDICAL, ACCESS_FORENSICS_LOCKERS)
circuit = /obj/item/circuitboard/computer/med_data
var/obj/item/card/id/scan = null
var/authenticated = null
var/rank = null
var/screen = null
var/datum/data/record/active1
var/datum/data/record/active2
var/a_id = null
var/temp = null
var/printing = null
//Sorting Variables
@@ -25,24 +22,22 @@
/obj/machinery/computer/med_data/syndie
icon_keyboard = "syndie_key"
/obj/machinery/computer/med_data/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/card/id) && !scan)
if(!user.transferItemToLoc(O, src))
return
scan = O
to_chat(user, "<span class='notice'>You insert [O].</span>")
/obj/machinery/computer/med_data/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/id))
id_insert_scan(user)
else
return ..()
/obj/machinery/computer/med_data/ui_interact(mob/user)
. = ..()
if(isliving(user))
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
var/dat
if(temp)
dat = text("<TT>[temp]</TT><BR><BR><A href='?src=[REF(src)];temp=1'>Clear Screen</A>")
else
dat = text("Confirm Identity: <A href='?src=[REF(src)];scan=1'>[]</A><HR>", (src.scan ? text("[]", src.scan.name) : "----------"))
if(src.authenticated)
switch(src.screen)
if(authenticated)
switch(screen)
if(1)
dat += {"
<A href='?src=[REF(src)];search=1'>Search Records</A>
@@ -116,7 +111,7 @@
dat += "<td><a href='?src=[REF(src)];field=show_photo_front'><img src=photo_front height=80 width=80 border=4></a></td>"
dat += "<td><a href='?src=[REF(src)];field=show_photo_side'><img src=photo_side height=80 width=80 border=4></a></td></tr>"
dat += "<tr><td>ID:</td><td>[active1.fields["id"]]</td></tr>"
dat += "<tr><td>Sex:</td><td><A href='?src=[REF(src)];field=sex'>&nbsp;[active1.fields["sex"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Gender:</td><td><A href='?src=[REF(src)];field=gender'>&nbsp;[active1.fields["gender"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Age:</td><td><A href='?src=[REF(src)];field=age'>&nbsp;[active1.fields["age"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Species:</td><td><A href='?src=[REF(src)];field=species'>&nbsp;[active1.fields["species"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Fingerprint:</td><td><A href='?src=[REF(src)];field=fingerprint'>&nbsp;[active1.fields["fingerprint"]]&nbsp;</A></td></tr>"
@@ -141,7 +136,7 @@
dat += "<tr><td><br><b><font size='4'>Comments/Log</font></b></td></tr>"
var/counter = 1
while(src.active2.fields[text("com_[]", counter)])
while(active2.fields[text("com_[]", counter)])
dat += "<tr><td>[active2.fields[text("com_[]", counter)]]</td></tr><tr><td><A href='?src=[REF(src)];del_c=[counter]'>Delete Entry</A></td></tr>"
counter++
dat += "<tr><td><A href='?src=[REF(src)];add_c=1'>Add Entry</A></td></tr>"
@@ -169,7 +164,7 @@
dat += "<br><b>Medical Robots:</b>"
var/bdat = null
for(var/mob/living/simple_animal/bot/medbot/M in GLOB.alive_mob_list)
if(M.z != src.z)
if(M.z != z)
continue //only find medibots on the same z-level as the computer
var/turf/bl = get_turf(M)
if(bl) //if it can't find a turf for the medibot, then it probably shouldn't be showing up
@@ -189,7 +184,7 @@
dat += "<A href='?src=[REF(src)];login=1'>{Log In}</A>"
var/datum/browser/popup = new(user, "med_rec", "Medical Records Console", 600, 400)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/med_data/Topic(href, href_list)
@@ -197,29 +192,20 @@
if(.)
return .
if(!(active1 in GLOB.data_core.general))
src.active1 = null
active1 = null
if(!(active2 in GLOB.data_core.medical))
src.active2 = null
active2 = null
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr) || IsAdminGhost(usr))
usr.set_machine(src)
if(href_list["temp"])
src.temp = null
if(href_list["scan"])
if(src.scan)
usr.put_in_hands(scan)
scan = null
else
var/obj/item/I = usr.is_holding_item_of_type(/obj/item/card/id)
if(I)
if(!usr.transferItemToLoc(I, src))
return
src.scan = I
temp = null
else if(href_list["logout"])
src.authenticated = null
src.screen = null
src.active1 = null
src.active2 = null
authenticated = null
screen = null
active1 = null
active2 = null
playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE)
else if(href_list["choice"])
// SORTING!
if(href_list["choice"] == "Sorting")
@@ -234,34 +220,37 @@
sortBy = href_list["sort"]
order = initial(order)
else if(href_list["login"])
if(issilicon(usr))
src.active1 = null
src.active2 = null
src.authenticated = 1
src.rank = "AI"
src.screen = 1
else if(IsAdminGhost(usr))
src.active1 = null
src.active2 = null
src.authenticated = 1
src.rank = "Central Command"
src.screen = 1
else if(istype(src.scan, /obj/item/card/id))
src.active1 = null
src.active2 = null
if(src.check_access(src.scan))
src.authenticated = src.scan.registered_name
src.rank = src.scan.assignment
src.screen = 1
if(src.authenticated)
var/mob/M = usr
var/obj/item/card/id/I = M.get_idcard(TRUE)
if(issilicon(M))
active1 = null
active2 = null
authenticated = 1
rank = "AI"
screen = 1
else if(IsAdminGhost(M))
active1 = null
active2 = null
authenticated = 1
rank = "Central Command"
screen = 1
else if(istype(I) && check_access(I))
active1 = null
active2 = null
authenticated = I.registered_name
rank = I.assignment
screen = 1
else
to_chat(usr, "<span class='danger'>Unauthorized access.</span>")
playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE)
if(authenticated)
if(href_list["screen"])
src.screen = text2num(href_list["screen"])
if(src.screen < 1)
src.screen = 1
screen = text2num(href_list["screen"])
if(screen < 1)
screen = 1
src.active1 = null
src.active2 = null
active1 = null
active2 = null
else if(href_list["vir"])
var/type = href_list["vir"]
@@ -269,7 +258,7 @@
var/AfS = ""
for(var/mob/M in Dis.viable_mobtypes)
AfS += " [initial(M.name)];"
src.temp = {"<b>Name:</b> [Dis.name]
temp = {"<b>Name:</b> [Dis.name]
<BR><b>Number of stages:</b> [Dis.max_stages]
<BR><b>Spread:</b> [Dis.spread_text] Transmission
<BR><b>Possible Cure:</b> [(Dis.cure_text||"none")]
@@ -280,110 +269,112 @@
<BR><b>Severity:</b> [Dis.severity]"}
else if(href_list["del_all"])
src.temp = "Are you sure you wish to delete all records?<br>\n\t<A href='?src=[REF(src)];temp=1;del_all2=1'>Yes</A><br>\n\t<A href='?src=[REF(src)];temp=1'>No</A><br>"
temp = "Are you sure you wish to delete all records?<br>\n\t<A href='?src=[REF(src)];temp=1;del_all2=1'>Yes</A><br>\n\t<A href='?src=[REF(src)];temp=1'>No</A><br>"
else if(href_list["del_all2"])
investigate_log("[key_name(usr)] has deleted all medical records.", INVESTIGATE_RECORDS)
GLOB.data_core.medical.Cut()
src.temp = "All records deleted."
temp = "All records deleted."
else if(href_list["field"])
var/a1 = src.active1
var/a2 = src.active2
var/a1 = active1
var/a2 = active2
switch(href_list["field"])
if("fingerprint")
if(active1)
var/t1 = stripped_input("Please input fingerprint hash:", "Med. records", src.active1.fields["fingerprint"], null)
var/t1 = stripped_input("Please input fingerprint hash:", "Med. records", active1.fields["fingerprint"], null)
if(!canUseMedicalRecordsConsole(usr, t1, a1))
return
src.active1.fields["fingerprint"] = t1
if("sex")
active1.fields["fingerprint"] = t1
if("gender")
if(active1)
if(src.active1.fields["sex"] == "Male")
src.active1.fields["sex"] = "Female"
if(active1.fields["gender"] == "Male")
active1.fields["gender"] = "Female"
else if(active1.fields["gender"] == "Female")
active1.fields["gender"] = "Other"
else
src.active1.fields["sex"] = "Male"
active1.fields["gender"] = "Male"
if("age")
if(active1)
var/t1 = input("Please input age:", "Med. records", src.active1.fields["age"], null) as num
var/t1 = input("Please input age:", "Med. records", active1.fields["age"], null) as num
if(!canUseMedicalRecordsConsole(usr, t1, a1))
return
src.active1.fields["age"] = t1
active1.fields["age"] = t1
if("species")
if(active1)
var/t1 = stripped_input("Please input species name", "Med. records", src.active1.fields["species"], null)
var/t1 = stripped_input("Please input species name", "Med. records", active1.fields["species"], null)
if(!canUseMedicalRecordsConsole(usr, t1, a1))
return
active1.fields["species"] = t1
if("mi_dis")
if(active2)
var/t1 = stripped_input("Please input minor disabilities list:", "Med. records", src.active2.fields["mi_dis"], null)
var/t1 = stripped_input("Please input minor disabilities list:", "Med. records", active2.fields["mi_dis"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["mi_dis"] = t1
active2.fields["mi_dis"] = t1
if("mi_dis_d")
if(active2)
var/t1 = stripped_input("Please summarize minor dis.:", "Med. records", src.active2.fields["mi_dis_d"], null)
var/t1 = stripped_input("Please summarize minor dis.:", "Med. records", active2.fields["mi_dis_d"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["mi_dis_d"] = t1
active2.fields["mi_dis_d"] = t1
if("ma_dis")
if(active2)
var/t1 = stripped_input("Please input major disabilities list:", "Med. records", src.active2.fields["ma_dis"], null)
var/t1 = stripped_input("Please input major disabilities list:", "Med. records", active2.fields["ma_dis"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["ma_dis"] = t1
active2.fields["ma_dis"] = t1
if("ma_dis_d")
if(active2)
var/t1 = stripped_input("Please summarize major dis.:", "Med. records", src.active2.fields["ma_dis_d"], null)
var/t1 = stripped_input("Please summarize major dis.:", "Med. records", active2.fields["ma_dis_d"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["ma_dis_d"] = t1
active2.fields["ma_dis_d"] = t1
if("alg")
if(active2)
var/t1 = stripped_input("Please state allergies:", "Med. records", src.active2.fields["alg"], null)
var/t1 = stripped_input("Please state allergies:", "Med. records", active2.fields["alg"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["alg"] = t1
active2.fields["alg"] = t1
if("alg_d")
if(active2)
var/t1 = stripped_input("Please summarize allergies:", "Med. records", src.active2.fields["alg_d"], null)
var/t1 = stripped_input("Please summarize allergies:", "Med. records", active2.fields["alg_d"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["alg_d"] = t1
active2.fields["alg_d"] = t1
if("cdi")
if(active2)
var/t1 = stripped_input("Please state diseases:", "Med. records", src.active2.fields["cdi"], null)
var/t1 = stripped_input("Please state diseases:", "Med. records", active2.fields["cdi"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["cdi"] = t1
active2.fields["cdi"] = t1
if("cdi_d")
if(active2)
var/t1 = stripped_input("Please summarize diseases:", "Med. records", src.active2.fields["cdi_d"], null)
var/t1 = stripped_input("Please summarize diseases:", "Med. records", active2.fields["cdi_d"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["cdi_d"] = t1
active2.fields["cdi_d"] = t1
if("notes")
if(active2)
var/t1 = stripped_input("Please summarize notes:", "Med. records", src.active2.fields["notes"], null)
var/t1 = stripped_input("Please summarize notes:", "Med. records", active2.fields["notes"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["notes"] = t1
active2.fields["notes"] = t1
if("p_stat")
if(active1)
src.temp = "<B>Physical Condition:</B><BR>\n\t<A href='?src=[REF(src)];temp=1;p_stat=deceased'>*Deceased*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;p_stat=unconscious'>*Unconscious*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;p_stat=active'>Active</A><BR>\n\t<A href='?src=[REF(src)];temp=1;p_stat=unfit'>Physically Unfit</A><BR>"
temp = "<B>Physical Condition:</B><BR>\n\t<A href='?src=[REF(src)];temp=1;p_stat=deceased'>*Deceased*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;p_stat=unconscious'>*Unconscious*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;p_stat=active'>Active</A><BR>\n\t<A href='?src=[REF(src)];temp=1;p_stat=unfit'>Physically Unfit</A><BR>"
if("m_stat")
if(active1)
src.temp = "<B>Mental Condition:</B><BR>\n\t<A href='?src=[REF(src)];temp=1;m_stat=insane'>*Insane*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;m_stat=unstable'>*Unstable*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;m_stat=watch'>*Watch*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;m_stat=stable'>Stable</A><BR>"
temp = "<B>Mental Condition:</B><BR>\n\t<A href='?src=[REF(src)];temp=1;m_stat=insane'>*Insane*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;m_stat=unstable'>*Unstable*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;m_stat=watch'>*Watch*</A><BR>\n\t<A href='?src=[REF(src)];temp=1;m_stat=stable'>Stable</A><BR>"
if("blood_type")
if(active2)
src.temp = "<B>Blood Type:</B><BR>\n\t<A href='?src=[REF(src)];temp=1;blood_type=an'>A-</A> <A href='?src=[REF(src)];temp=1;blood_type=ap'>A+</A><BR>\n\t<A href='?src=[REF(src)];temp=1;blood_type=bn'>B-</A> <A href='?src=[REF(src)];temp=1;blood_type=bp'>B+</A><BR>\n\t<A href='?src=[REF(src)];temp=1;blood_type=abn'>AB-</A> <A href='?src=[REF(src)];temp=1;blood_type=abp'>AB+</A><BR>\n\t<A href='?src=[REF(src)];temp=1;blood_type=on'>O-</A> <A href='?src=[REF(src)];temp=1;blood_type=op'>O+</A><BR>"
temp = "<B>Blood Type:</B><BR>\n\t<A href='?src=[REF(src)];temp=1;blood_type=an'>A-</A> <A href='?src=[REF(src)];temp=1;blood_type=ap'>A+</A><BR>\n\t<A href='?src=[REF(src)];temp=1;blood_type=bn'>B-</A> <A href='?src=[REF(src)];temp=1;blood_type=bp'>B+</A><BR>\n\t<A href='?src=[REF(src)];temp=1;blood_type=abn'>AB-</A> <A href='?src=[REF(src)];temp=1;blood_type=abp'>AB+</A><BR>\n\t<A href='?src=[REF(src)];temp=1;blood_type=on'>O-</A> <A href='?src=[REF(src)];temp=1;blood_type=op'>O+</A><BR>"
if("b_dna")
if(active2)
var/t1 = stripped_input("Please input DNA hash:", "Med. records", src.active2.fields["b_dna"], null)
var/t1 = stripped_input("Please input DNA hash:", "Med. records", active2.fields["b_dna"], null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
src.active2.fields["b_dna"] = t1
active2.fields["b_dna"] = t1
if("show_photo_front")
if(active1)
if(active1.fields["photo_front"])
@@ -402,51 +393,51 @@
if(active1)
switch(href_list["p_stat"])
if("deceased")
src.active1.fields["p_stat"] = "*Deceased*"
active1.fields["p_stat"] = "*Deceased*"
if("unconscious")
src.active1.fields["p_stat"] = "*Unconscious*"
active1.fields["p_stat"] = "*Unconscious*"
if("active")
src.active1.fields["p_stat"] = "Active"
active1.fields["p_stat"] = "Active"
if("unfit")
src.active1.fields["p_stat"] = "Physically Unfit"
active1.fields["p_stat"] = "Physically Unfit"
else if(href_list["m_stat"])
if(active1)
switch(href_list["m_stat"])
if("insane")
src.active1.fields["m_stat"] = "*Insane*"
active1.fields["m_stat"] = "*Insane*"
if("unstable")
src.active1.fields["m_stat"] = "*Unstable*"
active1.fields["m_stat"] = "*Unstable*"
if("watch")
src.active1.fields["m_stat"] = "*Watch*"
active1.fields["m_stat"] = "*Watch*"
if("stable")
src.active1.fields["m_stat"] = "Stable"
active1.fields["m_stat"] = "Stable"
else if(href_list["blood_type"])
if(active2)
switch(href_list["blood_type"])
if("an")
src.active2.fields["blood_type"] = "A-"
active2.fields["blood_type"] = "A-"
if("bn")
src.active2.fields["blood_type"] = "B-"
active2.fields["blood_type"] = "B-"
if("abn")
src.active2.fields["blood_type"] = "AB-"
active2.fields["blood_type"] = "AB-"
if("on")
src.active2.fields["blood_type"] = "O-"
active2.fields["blood_type"] = "O-"
if("ap")
src.active2.fields["blood_type"] = "A+"
active2.fields["blood_type"] = "A+"
if("bp")
src.active2.fields["blood_type"] = "B+"
active2.fields["blood_type"] = "B+"
if("abp")
src.active2.fields["blood_type"] = "AB+"
active2.fields["blood_type"] = "AB+"
if("op")
src.active2.fields["blood_type"] = "O+"
active2.fields["blood_type"] = "O+"
else if(href_list["del_r"])
if(active2)
src.temp = "Are you sure you wish to delete the record (Medical Portion Only)?<br>\n\t<A href='?src=[REF(src)];temp=1;del_r2=1'>Yes</A><br>\n\t<A href='?src=[REF(src)];temp=1'>No</A><br>"
temp = "Are you sure you wish to delete the record (Medical Portion Only)?<br>\n\t<A href='?src=[REF(src)];temp=1;del_r2=1'>Yes</A><br>\n\t<A href='?src=[REF(src)];temp=1'>No</A><br>"
else if(href_list["del_r2"])
investigate_log("[key_name(usr)] has deleted the medical records for [active1.fields["name"]].", INVESTIGATE_RECORDS)
@@ -463,10 +454,10 @@
screen = 4
else if(href_list["new"])
if((istype(src.active1, /datum/data/record) && !( istype(src.active2, /datum/data/record) )))
if((istype(active1, /datum/data/record) && !( istype(active2, /datum/data/record) )))
var/datum/data/record/R = new /datum/data/record( )
R.fields["name"] = src.active1.fields["name"]
R.fields["id"] = src.active1.fields["id"]
R.fields["name"] = active1.fields["name"]
R.fields["id"] = active1.fields["id"]
R.name = text("Medical Record #[]", R.fields["id"])
R.fields["blood_type"] = "Unknown"
R.fields["b_dna"] = "Unknown"
@@ -480,76 +471,77 @@
R.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
R.fields["notes"] = "No notes."
GLOB.data_core.medical += R
src.active2 = R
src.screen = 4
active2 = R
screen = 4
else if(href_list["add_c"])
if(!(active2 in GLOB.data_core.medical))
return
var/a2 = src.active2
var/a2 = active2
var/t1 = stripped_multiline_input("Add Comment:", "Med. records", null, null)
if(!canUseMedicalRecordsConsole(usr, t1, null, a2))
return
var/counter = 1
while(src.active2.fields[text("com_[]", counter)])
while(active2.fields[text("com_[]", counter)])
counter++
src.active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [] [], []<BR>[]", src.authenticated, src.rank, STATION_TIME_TIMESTAMP("hh:mm:ss"), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1)
active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [] [], []<BR>[]", authenticated, rank, STATION_TIME_TIMESTAMP("hh:mm:ss"), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1)
else if(href_list["del_c"])
if((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])]))
src.active2.fields[text("com_[]", href_list["del_c"])] = "<B>Deleted</B>"
if((istype(active2, /datum/data/record) && active2.fields[text("com_[]", href_list["del_c"])]))
active2.fields[text("com_[]", href_list["del_c"])] = "<B>Deleted</B>"
else if(href_list["search"])
var/t1 = stripped_input(usr, "Search String: (Name, DNA, or ID)", "Med. records")
if(!canUseMedicalRecordsConsole(usr, t1))
return
src.active1 = null
src.active2 = null
active1 = null
active2 = null
t1 = lowertext(t1)
for(var/datum/data/record/R in GLOB.data_core.medical)
if((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"])))
src.active2 = R
active2 = R
else
//Foreach continue //goto(3229)
if(!( src.active2 ))
src.temp = text("Could not locate record [].", sanitize(t1))
if(!( active2 ))
temp = text("Could not locate record [].", sanitize(t1))
else
for(var/datum/data/record/E in GLOB.data_core.general)
if((E.fields["name"] == src.active2.fields["name"] || E.fields["id"] == src.active2.fields["id"]))
src.active1 = E
if((E.fields["name"] == active2.fields["name"] || E.fields["id"] == active2.fields["id"]))
active1 = E
else
//Foreach continue //goto(3334)
src.screen = 4
screen = 4
else if(href_list["print_p"])
if(!( src.printing ))
src.printing = 1
if(!( printing ))
printing = 1
GLOB.data_core.medicalPrintCount++
playsound(loc, 'sound/items/poster_being_created.ogg', 100, 1)
sleep(30)
var/obj/item/paper/P = new /obj/item/paper( src.loc )
var/obj/item/paper/P = new /obj/item/paper( loc )
P.info = "<CENTER><B>Medical Record - (MR-[GLOB.data_core.medicalPrintCount])</B></CENTER><BR>"
if(active1 in GLOB.data_core.general)
P.info += text("Name: [] ID: []<BR>\nSex: []<BR>\nAge: []<BR>", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"])
P.info += text("Name: [] ID: []<BR>\nGender: []<BR>\nAge: []<BR>", active1.fields["name"], active1.fields["id"], active1.fields["gender"], active1.fields["age"])
P.info += "\nSpecies: [active1.fields["species"]]<BR>"
P.info += text("\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"])
P.info += text("\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"])
else
P.info += "<B>General Record Lost!</B><BR>"
if(active2 in GLOB.data_core.medical)
P.info += text("<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: []<BR>\nDNA: []<BR>\n<BR>\nMinor Disabilities: []<BR>\nDetails: []<BR>\n<BR>\nMajor Disabilities: []<BR>\nDetails: []<BR>\n<BR>\nAllergies: []<BR>\nDetails: []<BR>\n<BR>\nCurrent Diseases: [] (per disease info placed in log/comment section)<BR>\nDetails: []<BR>\n<BR>\nImportant Notes:<BR>\n\t[]<BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src.active2.fields["blood_type"], src.active2.fields["b_dna"], src.active2.fields["mi_dis"], src.active2.fields["mi_dis_d"], src.active2.fields["ma_dis"], src.active2.fields["ma_dis_d"], src.active2.fields["alg"], src.active2.fields["alg_d"], src.active2.fields["cdi"], src.active2.fields["cdi_d"], src.active2.fields["notes"])
P.info += text("<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: []<BR>\nDNA: []<BR>\n<BR>\nMinor Disabilities: []<BR>\nDetails: []<BR>\n<BR>\nMajor Disabilities: []<BR>\nDetails: []<BR>\n<BR>\nAllergies: []<BR>\nDetails: []<BR>\n<BR>\nCurrent Diseases: [] (per disease info placed in log/comment section)<BR>\nDetails: []<BR>\n<BR>\nImportant Notes:<BR>\n\t[]<BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", active2.fields["blood_type"], active2.fields["b_dna"], active2.fields["mi_dis"], active2.fields["mi_dis_d"], active2.fields["ma_dis"], active2.fields["ma_dis_d"], active2.fields["alg"], active2.fields["alg_d"], active2.fields["cdi"], active2.fields["cdi_d"], active2.fields["notes"])
var/counter = 1
while(src.active2.fields[text("com_[]", counter)])
P.info += text("[]<BR>", src.active2.fields[text("com_[]", counter)])
while(active2.fields[text("com_[]", counter)])
P.info += text("[]<BR>", active2.fields[text("com_[]", counter)])
counter++
P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, src.active1.fields["name"])
P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, active1.fields["name"])
else
P.info += "<B>Medical Record Lost!</B><BR>"
P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, "Record Lost")
P.info += "</TT>"
src.printing = null
P.update_icon()
printing = null
src.add_fingerprint(usr)
src.updateUsrDialog()
add_fingerprint(usr)
updateUsrDialog()
return
/obj/machinery/computer/med_data/emp_act(severity)
@@ -560,11 +552,11 @@
switch(rand(1,6))
if(1)
if(prob(10))
R.fields["name"] = random_unique_lizard_name(R.fields["sex"],1)
R.fields["name"] = random_unique_lizard_name(R.fields["gender"],1)
else
R.fields["name"] = random_unique_name(R.fields["sex"],1)
R.fields["name"] = random_unique_name(R.fields["gender"],1)
if(2)
R.fields["sex"] = pick("Male", "Female")
R.fields["gender"] = pick("Male", "Female", "Other")
if(3)
R.fields["age"] = rand(AGE_MIN, AGE_MAX)
if(4)
@@ -583,7 +575,7 @@
if(user)
if(message)
if(authenticated)
if(user.canUseTopic(src))
if(user.canUseTopic(src, BE_CLOSE))
if(!record1 || record1 == active1)
if(!record2 || record2 == active2)
return 1
-142
View File
@@ -1,143 +1 @@
/obj/machinery/computer/prisoner
name = "prisoner management console"
desc = "Used to manage tracking implants placed inside criminals."
icon_screen = "explosive"
icon_keyboard = "security_key"
req_access = list(ACCESS_BRIG)
var/id = 0
var/temp = null
var/status = 0
var/timeleft = 60
var/stop = 0
var/screen = 0 // 0 - No Access Denied, 1 - Access allowed
var/obj/item/card/id/prisoner/inserted_id
circuit = /obj/item/circuitboard/computer/prisoner
light_color = LIGHT_COLOR_RED
/obj/machinery/computer/prisoner/ui_interact(mob/user)
. = ..()
var/dat = ""
if(screen == 0)
dat += "<HR><A href='?src=[REF(src)];lock=1'>Unlock Console</A>"
else if(screen == 1)
dat += "<H3>Prisoner ID Management</H3>"
if(inserted_id)
dat += text("<A href='?src=[REF(src)];id=eject'>[inserted_id]</A><br>")
dat += text("Collected Points: [inserted_id.points]. <A href='?src=[REF(src)];id=reset'>Reset.</A><br>")
dat += text("Card goal: [inserted_id.goal]. <A href='?src=[REF(src)];id=setgoal'>Set </A><br>")
dat += text("Space Law recommends quotas of 100 points per minute they would normally serve in the brig.<BR>")
else
dat += text("<A href='?src=[REF(src)];id=insert'>Insert Prisoner ID.</A><br>")
dat += "<H3>Prisoner Implant Management</H3>"
dat += "<HR>Chemical Implants<BR>"
var/turf/Tr = null
for(var/obj/item/implant/chem/C in GLOB.tracked_chem_implants)
Tr = get_turf(C)
if((Tr) && (Tr.z != src.z))
continue//Out of range
if(!C.imp_in)
continue
dat += "ID: [C.imp_in.name] | Remaining Units: [C.reagents.total_volume] <BR>"
dat += "| Inject: "
dat += "<A href='?src=[REF(src)];inject1=[REF(C)]'>(<font class='bad'>(1)</font>)</A>"
dat += "<A href='?src=[REF(src)];inject5=[REF(C)]'>(<font class='bad'>(5)</font>)</A>"
dat += "<A href='?src=[REF(src)];inject10=[REF(C)]'>(<font class='bad'>(10)</font>)</A><BR>"
dat += "********************************<BR>"
dat += "<HR>Tracking Implants<BR>"
for(var/obj/item/implant/tracking/T in GLOB.tracked_implants)
if(!isliving(T.imp_in))
continue
Tr = get_turf(T)
if((Tr) && (Tr.z != src.z))
continue//Out of range
var/loc_display = "Unknown"
var/mob/living/M = T.imp_in
if(is_station_level(Tr.z) && !isspaceturf(M.loc))
var/turf/mob_loc = get_turf(M)
loc_display = mob_loc.loc
dat += "ID: [T.imp_in.name] | Location: [loc_display]<BR>"
dat += "<A href='?src=[REF(src)];warn=[REF(T)]'>(<font class='bad'><i>Message Holder</i></font>)</A> |<BR>"
dat += "********************************<BR>"
dat += "<HR><A href='?src=[REF(src)];lock=1'>Lock Console</A>"
var/datum/browser/popup = new(user, "computer", "Prisoner Management Console", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/computer/prisoner/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/id))
return attack_hand(user)
else
return ..()
/obj/machinery/computer/prisoner/process()
if(!..())
src.updateDialog()
return
/obj/machinery/computer/prisoner/Topic(href, href_list)
if(..())
return
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr))
usr.set_machine(src)
if(href_list["id"])
if(href_list["id"] =="insert" && !inserted_id)
var/obj/item/card/id/prisoner/I = usr.is_holding_item_of_type(/obj/item/card/id/prisoner)
if(I)
if(!usr.transferItemToLoc(I, src))
return
inserted_id = I
else
to_chat(usr, "<span class='danger'>No valid ID.</span>")
else if(inserted_id)
switch(href_list["id"])
if("eject")
inserted_id.forceMove(drop_location())
inserted_id.verb_pickup()
inserted_id = null
if("reset")
inserted_id.points = 0
if("setgoal")
var/num = round(input(usr, "Choose prisoner's goal:", "Input an Integer", null) as num|null)
if(num >= 0)
num = min(num,1000) //Cap the quota to the equivilent of 10 minutes.
inserted_id.goal = num
else if(href_list["inject1"])
var/obj/item/implant/I = locate(href_list["inject1"]) in GLOB.tracked_chem_implants
if(I && istype(I))
I.activate(1)
else if(href_list["inject5"])
var/obj/item/implant/I = locate(href_list["inject5"]) in GLOB.tracked_chem_implants
if(I && istype(I))
I.activate(5)
else if(href_list["inject10"])
var/obj/item/implant/I = locate(href_list["inject10"]) in GLOB.tracked_chem_implants
if(I && istype(I))
I.activate(10)
else if(href_list["lock"])
if(src.allowed(usr))
screen = !screen
else
to_chat(usr, "Unauthorized Access.")
else if(href_list["warn"])
var/warning = copytext(sanitize(input(usr,"Message:","Enter your message here!","")),1,MAX_MESSAGE_LEN)
if(!warning)
return
var/obj/item/implant/I = locate(href_list["warn"]) in GLOB.tracked_implants
if(I && istype(I) && I.imp_in)
var/mob/living/R = I.imp_in
to_chat(R, "<span class='italics'>You hear a voice in your head saying: '[warning]'</span>")
log_directed_talk(usr, R, warning, LOG_SAY, "implant message")
src.add_fingerprint(usr)
src.updateUsrDialog()
return
@@ -0,0 +1,52 @@
/obj/machinery/computer/prisoner
var/obj/item/card/id/prisoner/contained_id
/obj/machinery/computer/prisoner/Destroy()
if(contained_id)
contained_id.forceMove(get_turf(src))
return ..()
/obj/machinery/computer/prisoner/examine(mob/user)
. = ..()
if(contained_id)
. += "<span class='notice'><b>Alt-click</b> to eject the ID card.</span>"
/obj/machinery/computer/prisoner/AltClick(mob/user)
id_eject(user)
return ..()
/obj/machinery/computer/prisoner/proc/id_insert(mob/user, obj/item/card/id/prisoner/P)
if(istype(P))
if(contained_id)
to_chat(user, "<span class='warning'>There's already an ID card in the console!</span>")
return
if(!user.transferItemToLoc(P, src))
return
contained_id = P
user.visible_message("<span class='notice'>[user] inserts an ID card into the console.</span>", \
"<span class='notice'>You insert the ID card into the console.</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
updateUsrDialog()
/obj/machinery/computer/prisoner/proc/id_eject(mob/user)
if(!contained_id)
to_chat(user, "<span class='warning'>There's no ID card in the console!</span>")
return
else
contained_id.forceMove(drop_location())
if(!issilicon(user) && Adjacent(user))
user.put_in_hands(contained_id)
contained_id = null
user.visible_message("<span class='notice'>[user] gets an ID card from the console.</span>", \
"<span class='notice'>You get the ID card from the console.</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
updateUsrDialog()
/obj/machinery/computer/prisoner/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/card/id/prisoner))
id_insert(user, I)
else
return ..()
@@ -0,0 +1,142 @@
//computer that handle the points and teleports the prisoner
/obj/machinery/computer/prisoner/gulag_teleporter_computer
name = "labor camp teleporter console"
desc = "Used to send criminals to the Labor Camp."
icon_screen = "explosive"
icon_keyboard = "security_key"
req_access = list(ACCESS_ARMORY)
circuit = /obj/item/circuitboard/computer/gulag_teleporter_console
var/default_goal = 200
var/obj/machinery/gulag_teleporter/teleporter = null
var/obj/structure/gulag_beacon/beacon = null
var/mob/living/carbon/human/prisoner = null
var/datum/data/record/temporary_record = null
light_color = LIGHT_COLOR_RED
/obj/machinery/computer/prisoner/gulag_teleporter_computer/Initialize()
. = ..()
scan_machinery()
/obj/machinery/computer/prisoner/gulag_teleporter_computer/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, "gulag_console", name, 455, 440, master_ui, state)
ui.open()
/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_data(mob/user)
var/list/data = list()
var/list/prisoner_list = list()
var/can_teleport = FALSE
if(teleporter && (teleporter.occupant && ishuman(teleporter.occupant)))
prisoner = teleporter.occupant
prisoner_list["name"] = prisoner.real_name
if(contained_id)
can_teleport = TRUE
if(!isnull(GLOB.data_core.general))
for(var/r in GLOB.data_core.security)
var/datum/data/record/R = r
if(R.fields["name"] == prisoner_list["name"])
temporary_record = R
prisoner_list["crimstat"] = temporary_record.fields["criminal"]
data["prisoner"] = prisoner_list
if(teleporter)
data["teleporter"] = teleporter
data["teleporter_location"] = "([teleporter.x], [teleporter.y], [teleporter.z])"
data["teleporter_lock"] = teleporter.locked
data["teleporter_state_open"] = teleporter.state_open
if(beacon)
data["beacon"] = beacon
data["beacon_location"] = "([beacon.x], [beacon.y], [beacon.z])"
if(contained_id)
data["id"] = contained_id
data["id_name"] = contained_id.registered_name
data["goal"] = contained_id.goal
data["can_teleport"] = can_teleport
return data
/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_act(action, list/params)
if(isliving(usr))
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
if(..())
return
if(!allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return
switch(action)
if("scan_teleporter")
teleporter = findteleporter()
if("scan_beacon")
beacon = findbeacon()
if("handle_id")
if(contained_id)
id_eject(usr)
else
id_insert(usr)
if("set_goal")
var/new_goal = input("Set the amount of points:", "Points", contained_id.goal) as num|null
if(!isnum(new_goal))
return
if(!new_goal)
new_goal = default_goal
if (new_goal > 1000)
to_chat(usr, "The entered amount of points is too large. Points have instead been set to the maximum allowed amount.")
contained_id.goal = CLAMP(new_goal, 0, 1000) //maximum 1000 points
if("toggle_open")
if(teleporter.locked)
to_chat(usr, "The teleporter is locked")
return
teleporter.toggle_open()
if("teleporter_lock")
if(teleporter.state_open)
to_chat(usr, "Close the teleporter before locking!")
return
teleporter.locked = !teleporter.locked
if("teleport")
if(!teleporter || !beacon)
return
addtimer(CALLBACK(src, .proc/teleport, usr), 5)
/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/scan_machinery()
teleporter = findteleporter()
beacon = findbeacon()
/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/findteleporter()
var/obj/machinery/gulag_teleporter/teleporterf = null
for(var/direction in GLOB.cardinals)
teleporterf = locate(/obj/machinery/gulag_teleporter, get_step(src, direction))
if(teleporterf && teleporterf.is_operational())
return teleporterf
/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/findbeacon()
return locate(/obj/structure/gulag_beacon)
/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/teleport(mob/user)
if(!contained_id) //incase the ID was removed after the transfer timer was set.
say("Warning: Unable to transfer prisoner without a valid Prisoner ID inserted!")
return
var/id_goal_not_set
if(!contained_id.goal)
id_goal_not_set = TRUE
contained_id.goal = default_goal
say("[contained_id]'s ID card goal defaulting to [contained_id.goal] points.")
log_game("[key_name(user)] teleported [key_name(prisoner)] to the Labor Camp [COORD(beacon)] for [id_goal_not_set ? "default goal of ":""][contained_id.goal] points.")
teleporter.handle_prisoner(contained_id, temporary_record)
playsound(src, 'sound/weapons/emitter.ogg', 50, 1)
prisoner.forceMove(get_turf(beacon))
prisoner.Stun(40) // small travel dizziness
to_chat(prisoner, "<span class='warning'>The teleportation makes you a little dizzy.</span>")
new /obj/effect/particle_effect/sparks(get_turf(prisoner))
playsound(src, "sparks", 50, 1)
if(teleporter.locked)
teleporter.locked = FALSE
teleporter.toggle_open()
contained_id = null
temporary_record = null
@@ -0,0 +1,139 @@
/obj/machinery/computer/prisoner/management
name = "prisoner management console"
desc = "Used to manage tracking implants placed inside criminals."
icon_screen = "explosive"
icon_keyboard = "security_key"
req_access = list(ACCESS_BRIG)
var/id = 0
var/temp = null
var/status = 0
var/timeleft = 60
var/stop = 0
var/screen = 0 // 0 - No Access Denied, 1 - Access allowed
circuit = /obj/item/circuitboard/computer/prisoner
light_color = LIGHT_COLOR_RED
/obj/machinery/computer/prisoner/management/ui_interact(mob/user)
. = ..()
if(isliving(user))
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
var/dat = ""
if(screen == 0)
dat += "<HR><A href='?src=[REF(src)];lock=1'>{Log In}</A>"
else if(screen == 1)
dat += "<H3>Prisoner ID Management</H3>"
if(contained_id)
dat += text("<A href='?src=[REF(src)];id=eject'>[contained_id]</A><br>")
dat += text("Collected Points: [contained_id.points]. <A href='?src=[REF(src)];id=reset'>Reset.</A><br>")
dat += text("Card goal: [contained_id.goal]. <A href='?src=[REF(src)];id=setgoal'>Set </A><br>")
dat += text("Space Law recommends quotas of 100 points per minute they would normally serve in the brig.<BR>")
else
dat += text("<A href='?src=[REF(src)];id=insert'>Insert Prisoner ID.</A><br>")
dat += "<H3>Prisoner Implant Management</H3>"
dat += "<HR>Chemical Implants<BR>"
var/turf/Tr = null
for(var/obj/item/implant/chem/C in GLOB.tracked_chem_implants)
Tr = get_turf(C)
if((Tr) && (Tr.z != src.z))
continue//Out of range
if(!C.imp_in)
continue
dat += "ID: [C.imp_in.name] | Remaining Units: [C.reagents.total_volume] <BR>"
dat += "| Inject: "
dat += "<A href='?src=[REF(src)];inject1=[REF(C)]'>(<font class='bad'>(1)</font>)</A>"
dat += "<A href='?src=[REF(src)];inject5=[REF(C)]'>(<font class='bad'>(5)</font>)</A>"
dat += "<A href='?src=[REF(src)];inject10=[REF(C)]'>(<font class='bad'>(10)</font>)</A><BR>"
dat += "********************************<BR>"
dat += "<HR>Tracking Implants<BR>"
for(var/obj/item/implant/tracking/T in GLOB.tracked_implants)
if(!isliving(T.imp_in))
continue
Tr = get_turf(T)
if((Tr) && (Tr.z != src.z))
continue//Out of range
var/loc_display = "Unknown"
var/mob/living/M = T.imp_in
if(is_station_level(Tr.z) && !isspaceturf(M.loc))
var/turf/mob_loc = get_turf(M)
loc_display = mob_loc.loc
dat += "ID: [T.imp_in.name] | Location: [loc_display]<BR>"
dat += "<A href='?src=[REF(src)];warn=[REF(T)]'>(<font class='bad'><i>Message Holder</i></font>)</A> |<BR>"
dat += "********************************<BR>"
dat += "<HR><A href='?src=[REF(src)];lock=1'>{Log Out}</A>"
var/datum/browser/popup = new(user, "computer", "Prisoner Management Console", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/computer/prisoner/management/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/id))
if(screen)
id_insert(user)
else
to_chat(user, "<span class='danger'>Unauthorized access.</span>")
else
return ..()
/obj/machinery/computer/prisoner/management/process()
if(!..())
src.updateDialog()
return
/obj/machinery/computer/prisoner/management/Topic(href, href_list)
if(..())
return
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr))
usr.set_machine(src)
if(href_list["id"])
if(href_list["id"] =="insert" && !contained_id)
id_insert(usr)
else if(contained_id)
switch(href_list["id"])
if("eject")
id_eject(usr)
if("reset")
contained_id.points = 0
if("setgoal")
var/num = round(input(usr, "Choose prisoner's goal:", "Input an Integer", null) as num|null)
if(num >= 0)
num = min(num,1000) //Cap the quota to the equivilent of 10 minutes.
contained_id.goal = num
else if(href_list["inject1"])
var/obj/item/implant/I = locate(href_list["inject1"]) in GLOB.tracked_chem_implants
if(I && istype(I))
I.activate(1)
else if(href_list["inject5"])
var/obj/item/implant/I = locate(href_list["inject5"]) in GLOB.tracked_chem_implants
if(I && istype(I))
I.activate(5)
else if(href_list["inject10"])
var/obj/item/implant/I = locate(href_list["inject10"]) in GLOB.tracked_chem_implants
if(I && istype(I))
I.activate(10)
else if(href_list["lock"])
if(allowed(usr))
screen = !screen
playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE)
else
to_chat(usr, "<span class='danger'>Unauthorized access.</span>")
else if(href_list["warn"])
var/warning = copytext(sanitize(input(usr,"Message:","Enter your message here!","")),1,MAX_MESSAGE_LEN)
if(!warning)
return
var/obj/item/implant/I = locate(href_list["warn"]) in GLOB.tracked_implants
if(I && istype(I) && I.imp_in)
var/mob/living/R = I.imp_in
to_chat(R, "<span class='italics'>You hear a voice in your head saying: '[warning]'</span>")
log_directed_talk(usr, R, warning, LOG_SAY, "implant message")
src.add_fingerprint(usr)
src.updateUsrDialog()
return
+37 -78
View File
@@ -5,13 +5,10 @@
icon_keyboard = "security_key"
req_one_access = list(ACCESS_SECURITY, ACCESS_FORENSICS_LOCKERS)
circuit = /obj/item/circuitboard/computer/secure_data
var/obj/item/card/id/scan = null
var/authenticated = null
var/rank = null
var/screen = null
var/datum/data/record/active1 = null
var/datum/data/record/active2 = null
var/a_id = null
var/temp = null
var/printing = null
var/can_change_id = 0
@@ -23,11 +20,6 @@
light_color = LIGHT_COLOR_RED
/obj/machinery/computer/secure_data/examine(mob/user)
..()
if(scan)
to_chat(user, "<span class='notice'>Alt-click to eject the ID card.</span>")
/obj/machinery/computer/secure_data/syndie
icon_keyboard = "syndie_key"
@@ -40,32 +32,19 @@
clockwork = TRUE //it'd look weird
pass_flags = PASSTABLE
/obj/machinery/computer/secure_data/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/card/id))
if(!scan)
if(!user.transferItemToLoc(O, src))
return
scan = O
to_chat(user, "<span class='notice'>You insert [O].</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
updateUsrDialog()
else
to_chat(user, "<span class='warning'>There's already an ID card in the console.</span>")
else
return ..()
//Someone needs to break down the dat += into chunks instead of long ass lines.
/obj/machinery/computer/secure_data/ui_interact(mob/user)
. = ..()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
if(src.z > 6)
to_chat(user, "<span class='boldannounce'>Unable to establish a connection</span>: \black You're too far away from the station!")
return
var/dat
if(temp)
dat = text("<TT>[]</TT><BR><BR><A href='?src=[REF(src)];choice=Clear Screen'>Clear Screen</A>", temp)
dat = "<TT>[temp]</TT><BR><BR><A href='?src=[REF(src)];choice=Clear Screen'>Clear Screen</A>"
else
dat = text("Confirm Identity: <A href='?src=[REF(src)];choice=Confirm Identity'>[]</A><HR>", (scan ? text("[]", scan.name) : "----------"))
dat = ""
if(authenticated)
switch(screen)
if(1)
@@ -190,7 +169,7 @@
dat += {"<table><tr><td><table>
<tr><td>Name:</td><td><A href='?src=[REF(src)];choice=Edit Field;field=name'>&nbsp;[active1.fields["name"]]&nbsp;</A></td></tr>
<tr><td>ID:</td><td><A href='?src=[REF(src)];choice=Edit Field;field=id'>&nbsp;[active1.fields["id"]]&nbsp;</A></td></tr>
<tr><td>Sex:</td><td><A href='?src=[REF(src)];choice=Edit Field;field=sex'>&nbsp;[active1.fields["sex"]]&nbsp;</A></td></tr>
<tr><td>Gender:</td><td><A href='?src=[REF(src)];choice=Edit Field;field=gender'>&nbsp;[active1.fields["gender"]]&nbsp;</A></td></tr>
<tr><td>Age:</td><td><A href='?src=[REF(src)];choice=Edit Field;field=age'>&nbsp;[active1.fields["age"]]&nbsp;</A></td></tr>"}
dat += "<tr><td>Species:</td><td><A href ='?src=[REF(src)];choice=Edit Field;field=species'>&nbsp;[active1.fields["species"]]&nbsp;</A></td></tr>"
dat += {"<tr><td>Rank:</td><td><A href='?src=[REF(src)];choice=Edit Field;field=rank'>&nbsp;[active1.fields["rank"]]&nbsp;</A></td></tr>
@@ -309,36 +288,39 @@ What a mess.*/
active1 = null
active2 = null
if("Confirm Identity")
eject_id(usr)
if("Log Out")
authenticated = null
screen = null
active1 = null
active2 = null
playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE)
if("Log In")
if(issilicon(usr))
var/mob/living/silicon/borg = usr
var/mob/M = usr
var/obj/item/card/id/I = M.get_idcard(TRUE)
if(issilicon(M))
var/mob/living/silicon/borg = M
active1 = null
active2 = null
authenticated = borg.name
rank = "AI"
screen = 1
else if(IsAdminGhost(usr))
else if(IsAdminGhost(M))
active1 = null
active2 = null
authenticated = usr.client.holder.admin_signature
authenticated = M.client.holder.admin_signature
rank = "Central Command"
screen = 1
else if(istype(scan, /obj/item/card/id))
else if(I && check_access(I))
active1 = null
active2 = null
if(check_access(scan))
authenticated = scan.registered_name
rank = scan.assignment
screen = 1
authenticated = I.registered_name
rank = I.assignment
screen = 1
else
to_chat(usr, "<span class='danger'>Unauthorized Access.</span>")
playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE)
//RECORD FUNCTIONS
if("Record Maintenance")
screen = 2
@@ -346,16 +328,14 @@ What a mess.*/
active2 = null
if("Browse Record")
var/datum/data/record/R = locate(href_list["d_rec"])
var/S = locate(href_list["d_rec"])
if(!( GLOB.data_core.general.Find(R) ))
var/datum/data/record/R = locate(href_list["d_rec"]) in GLOB.data_core.general
if(!R)
temp = "Record Not Found!"
else
active1 = active2 = R
for(var/datum/data/record/E in GLOB.data_core.security)
if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
S = E
active1 = R
active2 = S
active2 = E
screen = 3
@@ -368,7 +348,7 @@ What a mess.*/
var/obj/item/paper/P = new /obj/item/paper( loc )
P.info = "<CENTER><B>Security Record - (SR-[GLOB.data_core.securityPrintCount])</B></CENTER><BR>"
if((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)))
P.info += text("Name: [] ID: []<BR>\nSex: []<BR>\nAge: []<BR>", active1.fields["name"], active1.fields["id"], active1.fields["sex"], active1.fields["age"])
P.info += text("Name: [] ID: []<BR>\nGender: []<BR>\nAge: []<BR>", active1.fields["name"], active1.fields["id"], active1.fields["gender"], active1.fields["age"])
P.info += "\nSpecies: [active1.fields["species"]]<BR>"
P.info += text("\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"])
else
@@ -419,6 +399,7 @@ What a mess.*/
P.info += "<B>Security Record Lost!</B><BR>"
P.name = text("SR-[] '[]'", GLOB.data_core.securityPrintCount, "Record Lost")
P.info += "</TT>"
P.update_icon()
printing = null
if("Print Poster")
if(!( printing ))
@@ -512,7 +493,7 @@ What a mess.*/
G.fields["name"] = "New Record"
G.fields["id"] = "[num2hex(rand(1, 1.6777215E7), 6)]"
G.fields["rank"] = "Unassigned"
G.fields["sex"] = "Male"
G.fields["gender"] = "Male"
G.fields["age"] = "Unknown"
G.fields["species"] = "Human"
G.fields["photo_front"] = new /icon()
@@ -584,12 +565,14 @@ What a mess.*/
if(!canUseSecurityRecordsConsole(usr, t1, a1))
return
active1.fields["fingerprint"] = t1
if("sex")
if("gender")
if(istype(active1, /datum/data/record))
if(active1.fields["sex"] == "Male")
active1.fields["sex"] = "Female"
if(active1.fields["gender"] == "Male")
active1.fields["gender"] = "Female"
else if(active1.fields["gender"] == "Female")
active1.fields["gender"] = "Other"
else
active1.fields["sex"] = "Male"
active1.fields["gender"] = "Male"
if("age")
if(istype(active1, /datum/data/record))
var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num
@@ -767,19 +750,14 @@ What a mess.*/
P = user.get_active_held_item()
return P
/obj/machinery/computer/secure_data/proc/print_photo(icon/temp, name)
/obj/machinery/computer/secure_data/proc/print_photo(icon/temp, person_name)
if (printing)
return
printing = TRUE
sleep(20)
var/obj/item/photo/P = new/obj/item/photo(drop_location())
var/icon/small_img = icon(temp)
var/icon/ic = icon('icons/obj/items_and_weapons.dmi',"photo")
small_img.Scale(8, 8)
ic.Blend(small_img,ICON_OVERLAY, 13, 13)
P.icon = ic
P.picture.picture_image = temp
P.desc = "The photo on file for [name]."
var/datum/picture/toEmbed = new(name = person_name, desc = "The photo on file for [person_name].", image = temp)
P.set_picture(toEmbed, TRUE, TRUE)
P.pixel_x = rand(-10, 10)
P.pixel_y = rand(-10, 10)
printing = FALSE
@@ -799,7 +777,7 @@ What a mess.*/
else
R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]"
if(2)
R.fields["sex"] = pick("Male", "Female")
R.fields["gender"] = pick("Male", "Female", "Other")
if(3)
R.fields["age"] = rand(5, 85)
if(4)
@@ -823,7 +801,7 @@ What a mess.*/
/obj/machinery/computer/secure_data/proc/canUseSecurityRecordsConsole(mob/user, message1 = 0, record1, record2)
if(user)
if(authenticated)
if(user.canUseTopic(src))
if(user.canUseTopic(src, BE_CLOSE))
if(!trim(message1))
return 0
if(!record1 || record1 == active1)
@@ -831,22 +809,3 @@ What a mess.*/
return 1
return 0
/obj/machinery/computer/secure_data/AltClick(mob/user)
if(user.canUseTopic(src))
eject_id(user)
/obj/machinery/computer/secure_data/proc/eject_id(mob/user)
if(scan)
scan.forceMove(drop_location())
if(!issilicon(user) && Adjacent(user))
user.put_in_hands(scan)
scan = null
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
else //switching the ID with the one you're holding
if(issilicon(user) || !Adjacent(user))
return
var/obj/item/card/id/held_id = user.is_holding_item_of_type(/obj/item/card/id)
if(QDELETED(held_id) || !user.transferItemToLoc(held_id, src))
return
scan = held_id
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
+17 -14
View File
@@ -1280,20 +1280,23 @@
return !density || (check_access(ID) && !locked && hasPower())
/obj/machinery/door/airlock/emag_act(mob/user)
if(!operating && density && hasPower() && !(obj_flags & EMAGGED))
operating = TRUE
update_icon(AIRLOCK_EMAG, 1)
sleep(6)
if(QDELETED(src))
return
operating = FALSE
if(!open())
update_icon(AIRLOCK_CLOSED, 1)
obj_flags |= EMAGGED
lights = FALSE
locked = TRUE
loseMainPower()
loseBackupPower()
. = ..()
if(operating || !density || !hasPower() || obj_flags & EMAGGED)
return
operating = TRUE
update_icon(AIRLOCK_EMAG, 1)
addtimer(CALLBACK(src, .proc/open_sesame), 6)
return TRUE
/obj/machinery/door/airlock/proc/open_sesame()
operating = FALSE
if(!open())
update_icon(AIRLOCK_CLOSED, 1)
obj_flags |= EMAGGED
lights = FALSE
locked = TRUE
loseMainPower()
loseBackupPower()
/obj/machinery/door/airlock/attack_alien(mob/living/carbon/alien/humanoid/user)
add_fingerprint(user)
-3
View File
@@ -13,9 +13,6 @@
else
return ..()
/obj/machinery/door/unpowered/emag_act()
return
/obj/machinery/door/unpowered/shuttle
icon = 'icons/turf/shuttle.dmi'
name = "door"
+14 -9
View File
@@ -206,15 +206,20 @@
..()
/obj/machinery/door/window/emag_act(mob/user)
if(!operating && density && !(obj_flags & EMAGGED))
obj_flags |= EMAGGED
operating = TRUE
flick("[src.base_state]spark", src)
playsound(src, "sparks", 75, 1)
sleep(6)
operating = FALSE
desc += "<BR><span class='warning'>Its access panel is smoking slightly.</span>"
open(2)
. = ..()
if(operating || !density || obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
operating = TRUE
flick("[src.base_state]spark", src)
playsound(src, "sparks", 75, 1)
addtimer(CALLBACK(src, .proc/open_windows_me), 6)
return TRUE
/obj/machinery/door/window/proc/open_windows_me()
operating = FALSE
desc += "<BR><span class='warning'>Its access panel is smoking slightly.</span>"
open(2)
/obj/machinery/door/window/attackby(obj/item/I, mob/living/user, params)
@@ -26,6 +26,7 @@
findObjsByTag()
/obj/machinery/doorButtons/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -33,6 +34,7 @@
req_one_access = list()
playsound(src, "sparks", 100, 1)
to_chat(user, "<span class='warning'>You short out the access controller.</span>")
return TRUE
/obj/machinery/doorButtons/proc/removeMe()
+2
View File
@@ -97,6 +97,7 @@
alarm()
/obj/machinery/firealarm/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -104,6 +105,7 @@
user.visible_message("<span class='warning'>Sparks fly out of [src]!</span>",
"<span class='notice'>You emag [src], disabling its thermal sensors.</span>")
playsound(src, "sparks", 50, 1)
return TRUE
/obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume)
if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && (last_alarm+FIREALARM_COOLDOWN < world.time) && !(obj_flags & EMAGGED) && detecting && !stat)
+12 -31
View File
@@ -9,7 +9,6 @@
idle_power_usage = 100
active_power_usage = 2500
var/list/stored_items = list()
var/obj/item/card/id/prisoner/inserted_id = null
var/obj/machinery/gulag_teleporter/linked_teleporter = null
/obj/machinery/gulag_item_reclaimer/Destroy()
@@ -18,28 +17,15 @@
I.forceMove(get_turf(src))
if(linked_teleporter)
linked_teleporter.linked_reclaimer = null
if(inserted_id)
inserted_id.forceMove(get_turf(src))
inserted_id = null
return ..()
/obj/machinery/gulag_item_reclaimer/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED) // emagging lets anyone reclaim all the items
return
req_access = list()
obj_flags |= EMAGGED
/obj/machinery/gulag_item_reclaimer/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/card/id))
if(!inserted_id)
if(!user.transferItemToLoc(I, src))
return
inserted_id = I
to_chat(user, "<span class='notice'>You insert [I].</span>")
return
else
to_chat(user, "<span class='notice'>There's an ID inserted already.</span>")
return ..()
return TRUE
/obj/machinery/gulag_item_reclaimer/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)
@@ -55,15 +41,19 @@
if(allowed(user))
can_reclaim = TRUE
if(inserted_id)
data["id"] = inserted_id
data["id_name"] = inserted_id.registered_name
if(inserted_id.points >= inserted_id.goal)
var/obj/item/card/id/I = user.get_idcard(TRUE)
if(istype(I, /obj/item/card/id/prisoner))
var/obj/item/card/id/prisoner/P = I
if(P.points >= P.goal)
can_reclaim = TRUE
var/list/mobs = list()
for(var/i in stored_items)
var/mob/thismob = i
if(QDELETED(thismob))
say("Alert! Unable to locate vital signals of a previously processed prisoner. Ejecting equipment!")
drop_items(thismob)
continue
var/list/mob_info = list()
mob_info["name"] = thismob.real_name
mob_info["mob"] = "[REF(thismob)]"
@@ -78,16 +68,6 @@
/obj/machinery/gulag_item_reclaimer/ui_act(action, list/params)
switch(action)
if("handle_id")
if(inserted_id)
usr.put_in_hands(inserted_id)
inserted_id = null
else
var/obj/item/I = usr.is_holding_item_of_type(/obj/item/card/id)
if(I)
if(!usr.transferItemToLoc(I, src))
return
inserted_id = I
if("release_items")
var/mob/M = locate(params["mobref"])
if(M == usr || allowed(usr))
@@ -98,8 +78,9 @@
/obj/machinery/gulag_item_reclaimer/proc/drop_items(mob/user)
if(!stored_items[user])
return
var/drop_location = drop_location()
for(var/i in stored_items[user])
var/obj/item/W = i
stored_items[user] -= W
W.forceMove(get_turf(src))
W.forceMove(drop_location)
stored_items -= user
+2
View File
@@ -158,11 +158,13 @@
open_machine()
/obj/machinery/harvester/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
allow_living = TRUE
to_chat(user, "<span class='warning'>You overload [src]'s lifesign scanners.</span>")
return TRUE
/obj/machinery/harvester/container_resist(mob/living/user)
if(!harvesting)
+5 -1
View File
@@ -27,8 +27,10 @@
"human",
"lizard",
"fly",
"moth",
"insect",
"plasmaman",
"mammal",
"xeno",
"other"
)
@@ -215,6 +217,7 @@
return dat
/obj/machinery/limbgrower/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
for(var/id in SSresearch.techweb_designs)
@@ -223,3 +226,4 @@
stored_research.add_design(D)
to_chat(user, "<span class='warning'>A warning flashes onto the screen, stating that safety overrides have been deactivated!</span>")
obj_flags |= EMAGGED
return TRUE
@@ -290,6 +290,7 @@
return ..()
/obj/machinery/porta_turret/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "<span class='warning'>You short out [src]'s threat assessment circuits.</span>")
@@ -300,6 +301,7 @@
update_icon()
sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
on = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
return TRUE
/obj/machinery/porta_turret/emp_act(severity)
@@ -837,6 +839,7 @@
to_chat(user, "<span class='warning'>Access denied.</span>")
/obj/machinery/turretid/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "<span class='danger'>You short out the turret controls' access analysis module.</span>")
@@ -844,6 +847,7 @@
locked = FALSE
if(user && user.machine == src)
attack_hand(user)
return TRUE
/obj/machinery/turretid/attack_ai(mob/user)
if(!ailock || IsAdminGhost(user))
@@ -86,10 +86,13 @@
. = 0
/obj/machinery/porta_turret_cover/emag_act(mob/user)
if(!(parent_turret.obj_flags & EMAGGED))
to_chat(user, "<span class='notice'>You short out [parent_turret]'s threat assessment circuits.</span>")
visible_message("[parent_turret] hums oddly...")
parent_turret.obj_flags |= EMAGGED
parent_turret.on = 0
spawn(40)
parent_turret.on = 1
. = ..()
if(parent_turret.obj_flags & EMAGGED)
return
to_chat(user, "<span class='notice'>You short out [parent_turret]'s threat assessment circuits.</span>")
visible_message("[parent_turret] hums oddly...")
parent_turret.obj_flags |= EMAGGED
parent_turret.on = 0
spawn(40)
parent_turret.on = 1
return TRUE
+2
View File
@@ -65,6 +65,7 @@
return ..()
/obj/machinery/recycler/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -73,6 +74,7 @@
update_icon()
playsound(src, "sparks", 75, 1, -1)
to_chat(user, "<span class='notice'>You use the cryptographic sequencer on [src].</span>")
return TRUE
/obj/machinery/recycler/update_icon()
..()
+4
View File
@@ -195,6 +195,7 @@
return ..()
/obj/machinery/shieldgen/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
to_chat(user, "<span class='warning'>The access controller is damaged!</span>")
return
@@ -202,6 +203,7 @@
locked = FALSE
playsound(src, "sparks", 100, 1)
to_chat(user, "<span class='warning'>You short out the access controller.</span>")
return TRUE
/obj/machinery/shieldgen/update_icon()
if(active)
@@ -387,6 +389,7 @@
add_fingerprint(user)
/obj/machinery/shieldwallgen/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
to_chat(user, "<span class='warning'>The access controller is damaged!</span>")
return
@@ -394,6 +397,7 @@
locked = FALSE
playsound(src, "sparks", 100, 1)
to_chat(user, "<span class='warning'>You short out the access controller.</span>")
return TRUE
//////////////Containment Field START
/obj/machinery/shieldwall
+2
View File
@@ -99,6 +99,7 @@
return ..()
/obj/machinery/computer/slot_machine/emag_act()
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -106,6 +107,7 @@
spark_system.set_up(4, 0, src.loc)
spark_system.start()
playsound(src, "sparks", 50, 1)
return TRUE
/obj/machinery/computer/slot_machine/ui_interact(mob/living/user)
. = ..()
@@ -42,21 +42,23 @@
return ..()
/obj/machinery/computer/message_monitor/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
if(!isnull(linkedServer))
obj_flags |= EMAGGED
screen = 2
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
else
if(isnull(linkedServer))
to_chat(user, "<span class='notice'>A no server error appears on the screen.</span>")
return
obj_flags |= EMAGGED
screen = 2
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
return TRUE
/obj/machinery/computer/message_monitor/New()
. = ..()
@@ -419,6 +421,7 @@
"name" = "[customsender]",
"job" = "[customjob]",
"message" = custommessage,
"emoji_message" = emoji_parse(custommessage),
"targets" = list("[customrecepient.owner] ([customrecepient.ownjob])")
))
// this will log the signal and transmit it to the target
@@ -106,10 +106,11 @@
return "Everyone"
return data["targets"][1]
/datum/signal/subspace/pda/proc/format_message()
/datum/signal/subspace/pda/proc/format_message(emojify = FALSE)
var/message = emojify ? data["emoji_message"] : data["message"]
if (logged && data["photo"])
return "\"[data["message"]]\" (<a href='byond://?src=[REF(logged)];photo=1'>Photo</a>)"
return "\"[data["message"]]\""
return "\"[message]\" (<a href='byond://?src=[REF(logged)];photo=1'>Photo</a>)"
return "\"[message]\""
/datum/signal/subspace/pda/broadcast()
if (!logged) // Can only go through if a message server logs it
+3
View File
@@ -6,6 +6,7 @@
dir_in = 1 //Facing North.
max_integrity = 250
deflect_chance = 5
force = 20
armor = list("melee" = 25, "bullet" = 20, "laser" = 30, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
max_temperature = 25000
infra_luminosity = 6
@@ -13,6 +14,7 @@
internal_damage_threshold = 35
max_equip = 3
step_energy_drain = 3
leg_overload_coeff = 300
/obj/mecha/combat/gygax/dark
desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications."
@@ -20,6 +22,7 @@
icon_state = "darkgygax"
max_integrity = 300
deflect_chance = 15
force = 25
armor = list("melee" = 40, "bullet" = 40, "laser" = 50, "energy" = 35, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
max_temperature = 35000
leg_overload_coeff = 100
+5
View File
@@ -64,10 +64,15 @@
/obj/machinery/mecha_part_fabricator/emag_act()
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
req_access = list()
INVOKE_ASYNC(src, .proc/error_action_sucessful)
return TRUE
/obj/machinery/mecha_part_fabricator/proc/error_action_sucessful()
say("DB error \[Code 0x00F1\]")
sleep(10)
say("Attempting auto-repair...")

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