diff --git a/_maps/map_files/Mafia/mafia_ayylmao.dmm b/_maps/map_files/Mafia/mafia_ayylmao.dmm
index 0f0a9c0e433..b9d8582f3b0 100644
--- a/_maps/map_files/Mafia/mafia_ayylmao.dmm
+++ b/_maps/map_files/Mafia/mafia_ayylmao.dmm
@@ -5,6 +5,10 @@
"b" = (
/turf/closed/indestructible/alien,
/area/centcom/mafia)
+"d" = (
+/obj/effect/landmark/mafia,
+/turf/open/floor/plating/abductor,
+/area/centcom/mafia)
"g" = (
/obj/mafia_game_board,
/obj/effect/mapping_helpers/broken_floor,
@@ -32,12 +36,10 @@
/turf/open/floor/plating/abductor,
/area/centcom/mafia)
"m" = (
-/obj/effect/landmark/mafia,
/obj/structure/bed/abductor,
/turf/open/floor/plating/abductor,
/area/centcom/mafia)
"n" = (
-/obj/effect/landmark/mafia,
/obj/structure/bed/abductor,
/turf/open/floor/plating/abductor2,
/area/centcom/mafia)
@@ -146,6 +148,10 @@
icon_state = "alien21"
},
/area/centcom/mafia)
+"O" = (
+/obj/effect/landmark/mafia,
+/turf/open/floor/plating/abductor2,
+/area/centcom/mafia)
"P" = (
/turf/closed/indestructible/abductor,
/area/centcom/mafia)
@@ -394,13 +400,13 @@ W
G
x
r
-r
+O
x
-q
+d
x
-r
+O
x
-q
+d
q
x
E
@@ -444,13 +450,13 @@ j
m
q
q
-q
+d
x
t
t
t
x
-r
+O
r
r
n
@@ -494,13 +500,13 @@ j
n
r
r
-r
+O
x
t
t
t
x
-q
+d
q
q
m
@@ -544,13 +550,13 @@ I
J
x
q
-q
+d
x
-r
+O
x
-q
+d
x
-r
+O
r
x
Y
diff --git a/_maps/map_files/Mafia/mafia_ball.dmm b/_maps/map_files/Mafia/mafia_ball.dmm
index 2991fb8d78f..fb4dc490d36 100644
--- a/_maps/map_files/Mafia/mafia_ball.dmm
+++ b/_maps/map_files/Mafia/mafia_ball.dmm
@@ -252,11 +252,11 @@ b
o
r
p
-m
+q
q
p
r
-n
+r
p
q
l
@@ -274,7 +274,7 @@ c
d
d
b
-n
+r
r
b
b
@@ -284,7 +284,7 @@ r
b
b
q
-m
+q
b
d
d
@@ -301,13 +301,13 @@ b
b
p
r
-r
+n
p
-q
+m
p
-r
+n
p
-q
+m
q
p
b
@@ -348,19 +348,19 @@ b
c
d
j
-m
q
q
q
+m
p
s
t
s
p
+n
r
r
r
-n
j
i
c
@@ -398,19 +398,19 @@ b
c
d
j
-n
r
r
r
+n
p
s
t
s
p
+m
q
q
q
-m
j
d
c
@@ -451,13 +451,13 @@ b
b
p
q
-q
+m
p
-r
+n
p
-q
+m
p
-r
+n
r
p
b
@@ -474,7 +474,7 @@ c
f
d
b
-m
+q
q
b
b
@@ -484,7 +484,7 @@ q
b
b
r
-n
+r
b
d
d
@@ -502,11 +502,11 @@ b
l
q
p
-n
+r
r
p
q
-m
+q
p
r
o
diff --git a/_maps/map_files/Mafia/mafia_gothic.dmm b/_maps/map_files/Mafia/mafia_gothic.dmm
index 4dd3c89f22a..817e145d111 100644
--- a/_maps/map_files/Mafia/mafia_gothic.dmm
+++ b/_maps/map_files/Mafia/mafia_gothic.dmm
@@ -297,11 +297,11 @@ b
J
r
p
-m
+q
q
p
E
-N
+O
p
q
l
@@ -319,7 +319,7 @@ c
d
d
b
-D
+E
O
b
b
@@ -329,7 +329,7 @@ r
b
b
q
-m
+q
b
d
d
@@ -346,13 +346,13 @@ b
b
p
X
-r
+M
p
-q
+m
p
-O
+N
p
-q
+m
q
p
b
@@ -393,19 +393,19 @@ b
c
d
j
-m
q
q
q
+m
p
t
t
t
p
-X
+n
r
E
-N
+O
j
i
c
@@ -443,19 +443,19 @@ b
c
d
j
-n
+X
r
E
-O
+N
p
t
t
t
p
+m
q
q
q
-m
j
d
c
@@ -496,13 +496,13 @@ b
b
p
q
-q
+m
p
-X
+n
p
-q
+m
p
-E
+D
O
p
b
@@ -519,7 +519,7 @@ c
f
d
b
-m
+q
q
b
b
@@ -529,7 +529,7 @@ q
b
b
X
-M
+r
b
d
d
@@ -547,11 +547,11 @@ b
l
q
p
-n
+X
r
p
q
-m
+q
p
E
P
diff --git a/_maps/map_files/Mafia/mafia_lavaland.dmm b/_maps/map_files/Mafia/mafia_lavaland.dmm
index a3729fe8a6e..96ddef90b5c 100644
--- a/_maps/map_files/Mafia/mafia_lavaland.dmm
+++ b/_maps/map_files/Mafia/mafia_lavaland.dmm
@@ -60,7 +60,6 @@
/turf/open/floor/fakebasalt,
/area/centcom/mafia)
"an" = (
-/obj/effect/landmark/mafia,
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 9
},
@@ -126,6 +125,7 @@
/obj/effect/turf_decal/trimline/brown/filled/end{
dir = 4
},
+/obj/effect/landmark/mafia,
/turf/open/floor/iron,
/area/centcom/mafia)
"az" = (
@@ -137,17 +137,11 @@
/obj/structure/closet/secure_closet/miner/unlocked,
/turf/open/floor/iron,
/area/centcom/mafia)
-"aA" = (
-/obj/effect/landmark/mafia,
-/obj/effect/turf_decal/trimline/brown/filled/line{
- dir = 6
- },
-/turf/open/floor/iron,
-/area/centcom/mafia)
"aB" = (
/obj/effect/turf_decal/trimline/brown/filled/end{
dir = 1
},
+/obj/effect/landmark/mafia,
/turf/open/floor/iron,
/area/centcom/mafia)
"aC" = (
@@ -183,13 +177,6 @@
},
/turf/open/floor/iron,
/area/centcom/mafia)
-"aG" = (
-/obj/effect/landmark/mafia,
-/obj/effect/turf_decal/trimline/brown/filled/line{
- dir = 10
- },
-/turf/open/floor/iron,
-/area/centcom/mafia)
"aH" = (
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 10
@@ -209,7 +196,6 @@
/turf/open/floor/iron,
/area/centcom/mafia)
"aJ" = (
-/obj/effect/landmark/mafia,
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 6
},
@@ -227,13 +213,6 @@
/obj/structure/closet/secure_closet/miner/unlocked,
/turf/open/floor/iron,
/area/centcom/mafia)
-"aL" = (
-/obj/effect/landmark/mafia,
-/obj/effect/turf_decal/trimline/brown/filled/line{
- dir = 5
- },
-/turf/open/floor/iron,
-/area/centcom/mafia)
"aM" = (
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 10
@@ -258,13 +237,7 @@
/area/centcom/mafia)
"aP" = (
/obj/effect/turf_decal/trimline/brown/filled/end,
-/turf/open/floor/iron,
-/area/centcom/mafia)
-"aQ" = (
/obj/effect/landmark/mafia,
-/obj/effect/turf_decal/trimline/brown/filled/line{
- dir = 9
- },
/turf/open/floor/iron,
/area/centcom/mafia)
"aR" = (
@@ -277,6 +250,7 @@
/obj/effect/turf_decal/trimline/brown/filled/end{
dir = 8
},
+/obj/effect/landmark/mafia,
/turf/open/floor/iron,
/area/centcom/mafia)
"aT" = (
@@ -473,11 +447,11 @@ aY
ar
aM
ap
-am
+aq
aq
ap
aw
-aA
+aV
ap
aq
al
@@ -495,7 +469,7 @@ ac
ad
ad
aY
-aL
+aF
aN
aY
aY
@@ -505,7 +479,7 @@ ax
aY
aY
aq
-am
+aq
aY
ad
ad
@@ -524,11 +498,11 @@ ap
aO
aP
ap
-aq
+am
ap
ay
ap
-aq
+am
aq
ap
aY
@@ -569,10 +543,10 @@ aY
ac
ad
aj
-am
aq
aq
aq
+am
ap
aq
aZ
@@ -628,10 +602,10 @@ aq
ab
aq
ap
+am
aq
aq
aq
-am
aj
ad
ac
@@ -672,11 +646,11 @@ aY
aY
ap
aq
-aq
+am
ap
aS
ap
-aq
+am
ap
aB
aD
@@ -695,7 +669,7 @@ ac
af
ad
aY
-am
+aq
aq
aY
aY
@@ -705,7 +679,7 @@ aq
aY
aY
aE
-aG
+aM
aY
ad
ad
@@ -723,11 +697,11 @@ aY
al
aq
ap
-aQ
+as
aU
ap
aq
-am
+aq
ap
aF
aI
diff --git a/_maps/map_files/Mafia/mafia_snow.dmm b/_maps/map_files/Mafia/mafia_snow.dmm
index 0a4001a6b0f..b8fbc0650b4 100644
--- a/_maps/map_files/Mafia/mafia_snow.dmm
+++ b/_maps/map_files/Mafia/mafia_snow.dmm
@@ -8,6 +8,10 @@
"d" = (
/turf/open/floor/plating,
/area/centcom/mafia)
+"e" = (
+/obj/effect/landmark/mafia,
+/turf/open/floor/iron/dark,
+/area/centcom/mafia)
"f" = (
/obj/effect/mapping_helpers/burnt_floor,
/turf/open/floor/plating,
@@ -46,10 +50,6 @@
},
/turf/open/floor/holofloor/wood,
/area/centcom/mafia)
-"m" = (
-/obj/effect/landmark/mafia,
-/turf/open/floor/holofloor/wood,
-/area/centcom/mafia)
"n" = (
/obj/item/bedsheet/green,
/obj/structure/bed,
@@ -133,11 +133,6 @@
},
/turf/open/floor/iron,
/area/centcom/mafia)
-"B" = (
-/obj/effect/landmark/mafia,
-/obj/structure/lattice/catwalk,
-/turf/open/lava/plasma/mafia,
-/area/centcom/mafia)
"C" = (
/obj/mafia_game_board,
/turf/open/floor/holofloor/snow,
@@ -181,6 +176,15 @@
"K" = (
/turf/closed/indestructible/rock/snow,
/area/centcom/mafia)
+"R" = (
+/obj/effect/landmark/mafia,
+/turf/open/floor/iron,
+/area/centcom/mafia)
+"W" = (
+/obj/structure/lattice/catwalk,
+/obj/effect/landmark/mafia,
+/turf/open/lava/plasma/mafia,
+/area/centcom/mafia)
(1,1,1) = {"
a
@@ -342,11 +346,11 @@ s
o
F
p
-m
+F
q
p
t
-y
+t
p
z
E
@@ -364,7 +368,7 @@ s
d
d
s
-m
+F
r
s
s
@@ -374,7 +378,7 @@ t
p
p
z
-B
+z
p
w
w
@@ -391,13 +395,13 @@ s
s
p
r
-r
+R
p
-q
+e
p
-t
+y
p
-z
+W
z
p
p
@@ -438,19 +442,19 @@ b
s
d
j
-m
+F
F
q
-q
+e
x
J
t
t
p
+y
t
t
t
-y
p
w
t
@@ -488,19 +492,19 @@ b
s
d
j
-m
+F
F
r
-r
+R
A
J
t
t
p
+y
t
t
t
-y
p
w
w
@@ -541,13 +545,13 @@ s
s
p
q
-q
+e
p
-r
+R
p
-t
+y
p
-z
+W
z
p
p
@@ -564,7 +568,7 @@ s
f
d
s
-m
+F
q
s
s
@@ -574,7 +578,7 @@ t
p
p
z
-B
+z
p
w
w
@@ -592,11 +596,11 @@ s
G
F
p
-m
+F
r
p
t
-y
+t
p
z
E
diff --git a/_maps/map_files/Mafia/mafia_spiderclan.dmm b/_maps/map_files/Mafia/mafia_spiderclan.dmm
index 090f2d27efb..ff83f8de3ec 100644
--- a/_maps/map_files/Mafia/mafia_spiderclan.dmm
+++ b/_maps/map_files/Mafia/mafia_spiderclan.dmm
@@ -258,11 +258,11 @@ S
b
r
p
-m
+q
q
p
r
-n
+r
p
q
o
@@ -280,7 +280,7 @@ c
d
d
S
-n
+r
r
S
S
@@ -290,7 +290,7 @@ r
S
S
q
-m
+q
S
d
d
@@ -307,13 +307,13 @@ S
S
p
r
-r
+n
p
-q
+m
p
-r
+n
p
-q
+m
q
p
S
@@ -354,19 +354,19 @@ S
c
d
j
-m
q
q
q
+m
p
t
t
t
p
+n
r
r
r
-n
j
i
c
@@ -404,19 +404,19 @@ S
c
d
j
-n
r
r
r
+n
p
t
t
t
p
+m
q
q
q
-m
j
d
c
@@ -457,13 +457,13 @@ S
S
p
q
-q
+m
p
-r
+n
p
-q
+m
p
-r
+n
r
p
S
@@ -480,7 +480,7 @@ c
f
d
S
-m
+q
q
S
S
@@ -490,7 +490,7 @@ q
S
S
r
-n
+r
S
d
d
@@ -508,11 +508,11 @@ S
o
q
p
-n
+r
r
p
q
-m
+q
p
r
b
diff --git a/_maps/map_files/Mafia/mafia_syndie.dmm b/_maps/map_files/Mafia/mafia_syndie.dmm
index e8e49e65c10..12287245828 100644
--- a/_maps/map_files/Mafia/mafia_syndie.dmm
+++ b/_maps/map_files/Mafia/mafia_syndie.dmm
@@ -45,10 +45,6 @@
/obj/mafia_game_board,
/turf/open/floor/plating,
/area/centcom/mafia)
-"n" = (
-/obj/effect/landmark/mafia,
-/turf/open/floor/mineral/plastitanium,
-/area/centcom/mafia)
"o" = (
/obj/effect/turf_decal/tile/red/fourcorners,
/turf/open/floor/iron/dark,
@@ -68,6 +64,7 @@
name = "tactical swivel chair"
},
/obj/effect/turf_decal/tile/red/fourcorners,
+/obj/effect/landmark/mafia,
/turf/open/floor/iron/dark,
/area/centcom/mafia)
"r" = (
@@ -93,12 +90,14 @@
name = "tactical swivel chair"
},
/obj/effect/turf_decal/tile/red/fourcorners,
+/obj/effect/landmark/mafia,
/turf/open/floor/iron/dark,
/area/centcom/mafia)
"y" = (
/obj/structure/chair/office{
name = "tactical swivel chair"
},
+/obj/effect/landmark/mafia,
/turf/open/floor/mineral/plastitanium,
/area/centcom/mafia)
"z" = (
@@ -106,6 +105,7 @@
name = "tactical swivel chair"
},
/obj/effect/turf_decal/tile/red/fourcorners,
+/obj/effect/landmark/mafia,
/turf/open/floor/iron/dark,
/area/centcom/mafia)
"A" = (
@@ -113,6 +113,7 @@
dir = 8;
name = "tactical swivel chair"
},
+/obj/effect/landmark/mafia,
/turf/open/floor/mineral/plastitanium,
/area/centcom/mafia)
"B" = (
@@ -120,6 +121,7 @@
dir = 4;
name = "tactical swivel chair"
},
+/obj/effect/landmark/mafia,
/turf/open/floor/mineral/plastitanium,
/area/centcom/mafia)
"C" = (
@@ -128,6 +130,7 @@
name = "tactical swivel chair"
},
/obj/effect/turf_decal/tile/red/fourcorners,
+/obj/effect/landmark/mafia,
/turf/open/floor/iron/dark,
/area/centcom/mafia)
"E" = (
@@ -135,6 +138,7 @@
dir = 1;
name = "tactical swivel chair"
},
+/obj/effect/landmark/mafia,
/turf/open/floor/mineral/plastitanium,
/area/centcom/mafia)
"G" = (
@@ -146,11 +150,6 @@
/obj/effect/spawner/random/clothing/syndie,
/turf/open/floor/iron/dark,
/area/centcom/mafia)
-"H" = (
-/obj/effect/landmark/mafia,
-/obj/effect/turf_decal/tile/red/fourcorners,
-/turf/open/floor/iron/dark,
-/area/centcom/mafia)
"Q" = (
/turf/open/floor/circuit/red,
/area/centcom/mafia)
@@ -318,11 +317,11 @@ w
G
o
p
-n
+r
r
p
o
-H
+o
p
r
b
@@ -340,7 +339,7 @@ c
d
d
w
-H
+o
o
w
w
@@ -350,7 +349,7 @@ o
w
w
r
-n
+r
w
d
d
@@ -414,7 +413,7 @@ w
c
d
j
-n
+r
r
r
y
@@ -426,7 +425,7 @@ p
q
o
o
-H
+o
j
i
c
@@ -464,7 +463,7 @@ w
c
d
j
-H
+o
o
o
z
@@ -476,7 +475,7 @@ p
E
r
r
-n
+r
j
d
c
@@ -540,7 +539,7 @@ c
f
d
w
-n
+r
r
w
w
@@ -550,7 +549,7 @@ r
w
w
o
-H
+o
w
d
d
@@ -568,11 +567,11 @@ w
b
r
p
-H
+o
o
p
r
-n
+r
p
o
G
diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm
index 78ec5e6af38..52e22aeaef8 100644
--- a/code/datums/saymode.dm
+++ b/code/datums/saymode.dm
@@ -96,17 +96,3 @@
AI.holopad_talk(message, language)
return FALSE
return TRUE
-
-/datum/saymode/mafia
- key = "j"
- mode = MODE_MAFIA
-
-/datum/saymode/mafia/handle_message(mob/living/user, message, datum/language/language)
- var/datum/mafia_controller/MF = GLOB.mafia_game
- if (!MF)
- return TRUE
- var/datum/mafia_role/R = MF.player_role_lookup[user]
- if(!R || R.team != "mafia")
- return TRUE
- MF.send_message(span_changeling("[R.body.real_name]: [message]"), "mafia")
- return FALSE
diff --git a/code/game/area/areas/centcom.dm b/code/game/area/areas/centcom.dm
index 1c40347e481..f5ac4fac78e 100644
--- a/code/game/area/areas/centcom.dm
+++ b/code/game/area/areas/centcom.dm
@@ -213,6 +213,18 @@
name = "Syndicate Elite Squad"
icon_state = "syndie-elite"
+//MAFIA
+/area/centcom/mafia
+ name = "Mafia Minigame"
+ icon_state = "mafia"
+ static_lighting = FALSE
+
+ base_lighting_alpha = 255
+ requires_power = FALSE
+ has_gravity = STANDARD_GRAVITY
+ flags_1 = NONE
+ area_flags = BLOCK_SUICIDE | UNIQUE_AREA
+
//CAPTURE THE FLAG
/area/centcom/ctf
name = "Capture the Flag"
diff --git a/code/modules/antagonists/obsessed/obsessed.dm b/code/modules/antagonists/obsessed/obsessed.dm
index 7c921fdd228..92b3140d47b 100644
--- a/code/modules/antagonists/obsessed/obsessed.dm
+++ b/code/modules/antagonists/obsessed/obsessed.dm
@@ -62,6 +62,7 @@
mask = /obj/item/clothing/mask/surgical
neck = /obj/item/camera
suit = /obj/item/clothing/suit/apron
+ shoes = /obj/item/clothing/shoes/sneakers/black
/datum/outfit/obsessed/post_equip(mob/living/carbon/human/H)
for(var/obj/item/carried_item in H.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE))
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index 20ded165fc0..f453fba3a16 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -382,6 +382,7 @@
mask = /obj/item/clothing/mask/gas
l_hand = /obj/item/melee/energy/sword
r_hand = /obj/item/gun/energy/recharge/ebow
+ shoes = /obj/item/clothing/shoes/magboots/advance
/datum/outfit/traitor/post_equip(mob/living/carbon/human/H, visualsOnly)
var/obj/item/melee/energy/sword/sword = locate() in H.held_items
diff --git a/code/modules/asset_cache/assets/headers.dm b/code/modules/asset_cache/assets/headers.dm
index e8f34dfd3f9..62c7fc532e6 100644
--- a/code/modules/asset_cache/assets/headers.dm
+++ b/code/modules/asset_cache/assets/headers.dm
@@ -27,4 +27,5 @@
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
"borg_mon.gif" = 'icons/program_icons/borg_mon.gif',
"robotact.gif" = 'icons/program_icons/robotact.gif',
+ "mafia.gif" = 'icons/program_icons/mafia.gif',
)
diff --git a/code/modules/mafia/_defines.dm b/code/modules/mafia/_defines.dm
index 835aff9d63d..ef24645bb05 100644
--- a/code/modules/mafia/_defines.dm
+++ b/code/modules/mafia/_defines.dm
@@ -100,6 +100,8 @@
/// now clearing refs to prepare for the next day. Do not do any actions here, it's just for ref clearing.
#define COMSIG_MAFIA_NIGHT_END "night_end"
+/// signal sent to roles when the game is confirmed starting
+#define COMSIG_MAFIA_GAME_START "game_start"
/// signal sent to roles when the game is confirmed ending
#define COMSIG_MAFIA_GAME_END "game_end"
@@ -107,6 +109,8 @@
GLOBAL_LIST_EMPTY(mafia_signup)
/// list of ghosts who want to play mafia that have since disconnected. They are kept in the lobby, but not counted for starting a game.
GLOBAL_LIST_EMPTY(mafia_bad_signup)
+/// list of PDAs who want to play mafia, every time someone enters the list it checks to see if enough are in
+GLOBAL_LIST_EMPTY(pda_mafia_signup)
/// the current global mafia game running.
GLOBAL_VAR(mafia_game)
/// list of ghosts in mafia_signup who have voted to start early
diff --git a/code/modules/mafia/abilities/abilities.dm b/code/modules/mafia/abilities/abilities.dm
index 59ee7570c32..3c8e643a427 100644
--- a/code/modules/mafia/abilities/abilities.dm
+++ b/code/modules/mafia/abilities/abilities.dm
@@ -29,6 +29,11 @@
target_role = null
return ..()
+///Handles special messagese sent by ability-specific stuff (such as changeling chat).
+/datum/mafia_ability/proc/handle_speech(datum/source, list/speech_args)
+ SIGNAL_HANDLER
+ return FALSE
+
/**
* Called when refs need to be cleared, when the target is no longer set.
*/
@@ -52,21 +57,28 @@
if(game.phase != valid_use_period)
return FALSE
if(host_role.role_flags & ROLE_ROLEBLOCKED)
- to_chat(host_role.body, span_warning("You were roleblocked!"))
+ host_role.send_message_to_player(span_warning("You were roleblocked!"))
+ return FALSE
+ if(host_role.game_status == MAFIA_DEAD)
return FALSE
if(potential_target)
- if((use_flags & CAN_USE_ON_DEAD) && (potential_target.game_status != MAFIA_DEAD))
+ if(use_flags & CAN_USE_ON_DEAD)
+ if(potential_target.game_status != MAFIA_DEAD)
+ if(!silent)
+ host_role.send_message_to_player(span_notice("This can only be used on dead players."))
+ return FALSE
+ else if(potential_target.game_status == MAFIA_DEAD)
if(!silent)
- to_chat(host_role.body, span_notice("This can only be used on dead players."))
+ host_role.send_message_to_player(span_notice("This can only be used on living players."))
return FALSE
if(!(use_flags & CAN_USE_ON_SELF) && (potential_target == host_role))
if(!silent)
- to_chat(host_role.body, span_notice("This can only be used on others."))
+ host_role.send_message_to_player(span_notice("This can only be used on others."))
return FALSE
if(!(use_flags & CAN_USE_ON_OTHERS) && (potential_target != host_role))
if(!silent)
- to_chat(host_role.body, span_notice("This can only be used on yourself."))
+ host_role.send_message_to_player(span_notice("This can only be used on yourself."))
return FALSE
return TRUE
@@ -90,7 +102,7 @@
if(target_role)
if(SEND_SIGNAL(target_role, COMSIG_MAFIA_ON_VISIT, game, host_role) & MAFIA_VISIT_INTERRUPTED) //visited a warden. something that prevents you by visiting that person
- to_chat(host_role.body, span_danger("Your [name] was interrupted!"))
+ host_role.send_message_to_player(span_danger("Your [name] was interrupted!"))
return FALSE
return TRUE
@@ -121,5 +133,5 @@
target_role = new_target
feedback_text = replacetext(feedback_text, "%WILL_PERFORM%", "now")
- to_chat(host_role.body, span_notice(feedback_text))
+ host_role.send_message_to_player(span_notice(feedback_text))
return TRUE
diff --git a/code/modules/mafia/abilities/investigative/investigate.dm b/code/modules/mafia/abilities/investigative/investigate.dm
index 0af1ed674b8..d23b51f9813 100644
--- a/code/modules/mafia/abilities/investigative/investigate.dm
+++ b/code/modules/mafia/abilities/investigative/investigate.dm
@@ -20,5 +20,5 @@
if(MAFIA_TEAM_SOLO)
fluff = "rogue, with their own objectives..."
- to_chat(host_role.body, span_warning("Your investigations reveal that [target_role.body.real_name] is [fluff]"))
+ host_role.send_message_to_player(span_warning("Your investigations reveal that [target_role.body.real_name] is [fluff]"))
return TRUE
diff --git a/code/modules/mafia/abilities/investigative/pray.dm b/code/modules/mafia/abilities/investigative/pray.dm
index b5bd6ee7e88..cbf8459f9f2 100644
--- a/code/modules/mafia/abilities/investigative/pray.dm
+++ b/code/modules/mafia/abilities/investigative/pray.dm
@@ -14,5 +14,5 @@
if(!.)
return FALSE
- to_chat(host_role.body, span_warning("You invoke spirit of [target_role.body.real_name] and learn their role was [target_role.name]."))
+ host_role.send_message_to_player(span_warning("You invoke spirit of [target_role.body.real_name] and learn their role was [target_role.name]."))
return TRUE
diff --git a/code/modules/mafia/abilities/investigative/reveal.dm b/code/modules/mafia/abilities/investigative/reveal.dm
index db48b552b62..5e38d3c9faf 100644
--- a/code/modules/mafia/abilities/investigative/reveal.dm
+++ b/code/modules/mafia/abilities/investigative/reveal.dm
@@ -13,7 +13,7 @@
if(!.)
return FALSE
- to_chat(host_role.body, span_warning("You have revealed the true nature of the [target_role]!"))
+ host_role.send_message_to_player(span_warning("You have revealed the true nature of the [target_role]!"))
target_role.reveal_role(game, verbose = TRUE)
return TRUE
diff --git a/code/modules/mafia/abilities/investigative/thoughtfeed.dm b/code/modules/mafia/abilities/investigative/thoughtfeed.dm
index 48d465173cd..f0eb49f2b4d 100644
--- a/code/modules/mafia/abilities/investigative/thoughtfeed.dm
+++ b/code/modules/mafia/abilities/investigative/thoughtfeed.dm
@@ -13,7 +13,7 @@
return FALSE
if((target_role.role_flags & ROLE_UNDETECTABLE))
- to_chat(host_role.body,span_warning("[target_role.body.real_name]'s memories reveal that they are the [pick(game.all_roles - target_role)]."))
+ host_role.send_message_to_player(span_warning("[target_role.body.real_name]'s memories reveal that they are the [pick(game.all_roles - target_role)]."))
else
- to_chat(host_role.body,span_warning("[target_role.body.real_name]'s memories reveal that they are the [target_role.name]."))
+ host_role.send_message_to_player(span_warning("[target_role.body.real_name]'s memories reveal that they are the [target_role.name]."))
return TRUE
diff --git a/code/modules/mafia/abilities/killing/alert.dm b/code/modules/mafia/abilities/killing/alert.dm
index 7af38f9befa..74710087137 100644
--- a/code/modules/mafia/abilities/killing/alert.dm
+++ b/code/modules/mafia/abilities/killing/alert.dm
@@ -22,8 +22,8 @@
SIGNAL_HANDLER
if(attacker == host_role)
return
- to_chat(host_role.body, span_userdanger("You have shot a visitor!"))
- to_chat(attacker.body, span_userdanger("You have visited the warden!"))
+ host_role.send_message_to_player(span_userdanger("You have shot a visitor!"))
+ attacker.send_message_to_player(span_userdanger("You have visited the warden!"))
attacker.kill(game, host_role, lynch = FALSE)
return MAFIA_VISIT_INTERRUPTED
diff --git a/code/modules/mafia/abilities/killing/flicker_rampage.dm b/code/modules/mafia/abilities/killing/flicker_rampage.dm
index 08a18e78778..10331d47986 100644
--- a/code/modules/mafia/abilities/killing/flicker_rampage.dm
+++ b/code/modules/mafia/abilities/killing/flicker_rampage.dm
@@ -22,11 +22,11 @@
return FALSE
if(!(target_role in darkened_players))
- to_chat(target_role.body, span_userdanger("The lights begin to flicker and dim. You're in danger."))
+ target_role.send_message_to_player(span_userdanger("The lights begin to flicker and dim. You're in danger."))
darkened_players += target_role
else
for(var/datum/mafia_role/dead_players as anything in darkened_players)
- to_chat(dead_players.body, span_userdanger("A shadowy figure appears out of the darkness!"))
+ dead_players.send_message_to_player(span_userdanger("A shadowy figure appears out of the darkness!"))
dead_players.kill(game, host_role, FALSE)
darkened_players -= dead_players
return TRUE
@@ -37,6 +37,6 @@
return //no chance man, that's a town lynch
if(attacker in darkened_players)
- to_chat(host_role.body, span_userdanger("You were attacked by someone in a flickering room. You have danced in the shadows, evading them."))
+ host_role.send_message_to_player(span_userdanger("You were attacked by someone in a flickering room. You have danced in the shadows, evading them."))
return MAFIA_PREVENT_KILL
diff --git a/code/modules/mafia/abilities/killing/kill.dm b/code/modules/mafia/abilities/killing/kill.dm
index 2c09c7525eb..d02fd6c287d 100644
--- a/code/modules/mafia/abilities/killing/kill.dm
+++ b/code/modules/mafia/abilities/killing/kill.dm
@@ -18,17 +18,17 @@
return FALSE
if(!target_role.kill(game, host_role, FALSE))
- to_chat(host_role.body, span_danger("Your attempt at killing [target_role.body.real_name] was prevented!"))
+ host_role.send_message_to_player(span_danger("Your attempt at killing [target_role.body.real_name] was prevented!"))
else
- to_chat(target_role.body, span_userdanger("You have been [attack_action] \a [host_role.name]!"))
+ target_role.send_message_to_player(span_userdanger("You have been [attack_action] \a [host_role.name]!"))
if(honorable && (target_role.team != MAFIA_TEAM_TOWN))
- to_chat(host_role.body, span_userdanger("You have killed an innocent crewmember. You will die tomorrow night."))
+ host_role.send_message_to_player(span_userdanger("You have killed an innocent crewmember. You will die tomorrow night."))
RegisterSignal(game, COMSIG_MAFIA_SUNDOWN, PROC_REF(internal_affairs))
return TRUE
/datum/mafia_ability/attack_player/proc/internal_affairs(datum/mafia_controller/game)
SIGNAL_HANDLER
- to_chat(host_role.body, span_userdanger("You have been killed by Nanotrasen Internal Affairs!"))
+ host_role.send_message_to_player(span_userdanger("You have been killed by Nanotrasen Internal Affairs!"))
host_role.reveal_role(game, verbose = TRUE)
host_role.kill(game, host_role, FALSE) //you technically kill yourself but that shouldn't matter
diff --git a/code/modules/mafia/abilities/protective/heal.dm b/code/modules/mafia/abilities/protective/heal.dm
index 65cd26ad0a1..4c47d1c85ab 100644
--- a/code/modules/mafia/abilities/protective/heal.dm
+++ b/code/modules/mafia/abilities/protective/heal.dm
@@ -18,7 +18,7 @@
if(!.)
return FALSE
if(new_target.role_flags & ROLE_VULNERABLE)
- to_chat(host_role.body, span_notice("[new_target] can't be protected."))
+ host_role.send_message_to_player(span_notice("[new_target] can't be protected."))
return FALSE
/datum/mafia_ability/heal/perform_action_target(datum/mafia_controller/game, datum/mafia_role/day_target)
@@ -39,10 +39,10 @@
/datum/mafia_ability/heal/proc/prevent_kill(datum/source, datum/mafia_controller/game, datum/mafia_role/attacker, lynch)
SIGNAL_HANDLER
if(host_role == target_role)
- to_chat(host_role.body, span_warning("You were attacked last night!"))
+ host_role.send_message_to_player(span_warning("You were attacked last night!"))
return MAFIA_PREVENT_KILL
- to_chat(host_role.body, span_warning("The person you protected tonight was attacked!"))
- to_chat(target_role.body, span_greentext("You were attacked last night, but [saving_message]!"))
+ host_role.send_message_to_player(span_warning("The person you protected tonight was attacked!"))
+ target_role.send_message_to_player(span_greentext("You were attacked last night, but [saving_message]!"))
return MAFIA_PREVENT_KILL
/**
@@ -60,6 +60,6 @@
return FALSE
if(attacker.kill(game, host_role, FALSE)) //you attack the attacker
- to_chat(attacker.body, span_userdanger("You have been ambushed by Security!"))
+ attacker.send_message_to_player(span_userdanger("You have been ambushed by Security!"))
host_role.kill(game, attacker, FALSE) //the attacker attacks you, they were able to attack the target so they can attack you.
return FALSE
diff --git a/code/modules/mafia/abilities/protective/vest.dm b/code/modules/mafia/abilities/protective/vest.dm
index 2c65202dd43..b65a8cb73ba 100644
--- a/code/modules/mafia/abilities/protective/vest.dm
+++ b/code/modules/mafia/abilities/protective/vest.dm
@@ -33,7 +33,7 @@
/datum/mafia_ability/vest/proc/self_defense(datum/source, datum/mafia_controller/game, datum/mafia_role/attacker, lynch)
SIGNAL_HANDLER
- to_chat(host_role.body, span_greentext("Your vest saved you!"))
+ host_role.send_message_to_player(span_greentext("Your vest saved you!"))
return MAFIA_PREVENT_KILL
/datum/mafia_ability/vest/proc/end_protection(datum/mafia_controller/game)
diff --git a/code/modules/mafia/abilities/voting/changeling_kill.dm b/code/modules/mafia/abilities/voting/changeling_kill.dm
index 0e851d78a95..bb1b1e76c81 100644
--- a/code/modules/mafia/abilities/voting/changeling_kill.dm
+++ b/code/modules/mafia/abilities/voting/changeling_kill.dm
@@ -30,12 +30,32 @@
ling_sent = TRUE
if(target_role.kill(game, host_role, FALSE))
- to_chat(target_role.body, span_userdanger("You have been killed by a Changeling!"))
+ target_role.send_message_to_player(span_userdanger("You have been killed by a Changeling!"))
game.send_message(span_danger("[host_role.body.real_name] was selected to attack [target_role.body.real_name] tonight!"), MAFIA_TEAM_MAFIA)
return TRUE
/datum/mafia_ability/changeling_kill/set_target(datum/mafia_controller/game, datum/mafia_role/new_target)
+ if(new_target.team == MAFIA_TEAM_MAFIA)
+ return FALSE
if(!validate_action_target(game, new_target))
return FALSE
using_ability = TRUE
game.vote_for(host_role, new_target, "Mafia", MAFIA_TEAM_MAFIA)
+
+/**
+ * handle_message
+ *
+ * During the night, Changelings talking will instead redirect it to Changeling chat.
+ */
+/datum/mafia_ability/changeling_kill/handle_speech(datum/source, list/speech_args)
+ . = ..()
+ var/datum/mafia_controller/mafia_game = GLOB.mafia_game
+ if(!mafia_game)
+ return FALSE
+ if (mafia_game.phase != MAFIA_PHASE_NIGHT)
+ return FALSE
+
+ var/phrase = html_decode(speech_args[SPEECH_MESSAGE])
+ mafia_game.send_message(span_changeling("[host_role.body.real_name]: [phrase]"), MAFIA_TEAM_MAFIA)
+ speech_args[SPEECH_MESSAGE] = ""
+ return TRUE
diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm
index f8d9db13106..967ae9b39a3 100644
--- a/code/modules/mafia/controller.dm
+++ b/code/modules/mafia/controller.dm
@@ -2,6 +2,9 @@ GLOBAL_LIST_INIT(mafia_roles_by_name, setup_mafia_roles_by_name())
GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
+///How many votes are needed to unlock the 'Universally Hated' achievement.
+#define UNIVERSALLY_HATED_REQUIREMENT 12
+
/**
* The mafia controller handles the mafia minigame in progress.
* It is first created when the first ghost signs up to play.
@@ -11,7 +14,8 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
var/list/datum/mafia_role/all_roles = list()
///all living roles in the game, removed on death.
var/list/datum/mafia_role/living_roles = list()
- ///exists to speed up role retrieval, it's a dict. `player_role_lookup[player ckey]` will give you the role they play
+ ///exists to speed up role retrieval, it's a dict.
+ /// `player_role_lookup[player ckey/PDA]` will give you the role they play
var/list/player_role_lookup = list()
///what part of the game you're playing in. day phases, night phases, judgement phases, etc.
var/phase = MAFIA_PHASE_SETUP
@@ -105,10 +109,10 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
/datum/mafia_controller/Destroy(force, ...)
. = ..()
- if(GLOB.mafia_game == src)
- GLOB.mafia_game = null
end_game()
QDEL_NULL(map_deleter)
+ if(GLOB.mafia_game == src)
+ GLOB.mafia_game = null
/**
* Triggers at beginning of the game when there is a confirmed list of valid, ready players.
@@ -122,9 +126,10 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
* * Puts players in each role randomly
* Arguments:
* * setup_list: list of all the datum setups (fancy list of roles) that would work for the game
- * * ready_players: list of filtered, sane players (so not playing or disconnected) for the game to put into roles
+ * * ready_ghosts: list of filtered, sane players (so not playing or disconnected) for the game to put into roles
+ * * ready_pdas: list of PDAs wanting to play the Mafia game.
*/
-/datum/mafia_controller/proc/prepare_game(setup_list, ready_players)
+/datum/mafia_controller/proc/prepare_game(setup_list, ready_ghosts, ready_pdas)
var/static/list/possible_maps = subtypesof(/datum/map_template/mafia)
var/turf/spawn_area = get_turf(locate(/obj/effect/landmark/mafia_game_area) in GLOB.landmarks_list)
@@ -156,16 +161,32 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
var/list/spawnpoints = landmarks.Copy()
for(var/datum/mafia_role/role as anything in all_roles)
role.assigned_landmark = pick_n_take(spawnpoints)
+ var/selected_player
if(!debug)
- role.player_key = pick_n_take(ready_players)
+ if(length(ready_pdas))
+ selected_player = pick(ready_pdas)
+ else
+ selected_player = pick(ready_ghosts)
else
- role.player_key = pop(ready_players)
+ if(length(ready_pdas))
+ selected_player = peek(ready_pdas)
+ else
+ selected_player = peek(ready_ghosts)
+ if(selected_player in ready_pdas)
+ role.player_pda = selected_player
+ ready_pdas -= selected_player
+ else
+ role.player_key = selected_player
+ ready_ghosts -= selected_player
-/datum/mafia_controller/proc/send_message(msg, team)
+///Sends a global message to all players, or just 'team' if set.
+/datum/mafia_controller/proc/send_message(msg, team, log_only = FALSE)
for(var/datum/mafia_role/role as anything in all_roles)
if(team && role.team != team)
continue
- to_chat(role.body, msg)
+ role.role_messages += msg
+ if(!log_only)
+ to_chat(role.body, msg)
/**
* The game by this point is now all set up, and so we can put people in their bodies and start the first phase.
@@ -176,10 +197,16 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
*/
/datum/mafia_controller/proc/start_game()
create_bodies()
+ SEND_GLOBAL_SIGNAL(COMSIG_MAFIA_GAME_START, src)
start_day(can_vote = FALSE)
- send_message(span_notice("The selected map is [current_map.name]![current_map.description]"))
+ send_message(span_notice("The selected map is [current_map.name]! [current_map.description]"))
send_message("Day [turn] started! There is no voting on the first day. Say hello to everybody!")
next_phase_timer = addtimer(CALLBACK(src, PROC_REF(check_trial), FALSE), (FIRST_DAY_PERIOD_LENGTH / time_speedup), TIMER_STOPPABLE) //no voting period = no votes = instant night
+ for(var/datum/mafia_role/roles as anything in all_roles)
+ var/obj/item/modular_computer/modpc = roles.player_pda
+ if(!modpc)
+ continue
+ modpc.update_static_data_for_all_viewers()
/**
* How every day starts.
@@ -229,7 +256,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
var/datum/mafia_role/loser = get_vote_winner("Day")//, majority_of_town = TRUE)
var/loser_votes = get_vote_count(loser, "Day")
if(loser)
- if(loser_votes > 12)
+ if(loser_votes > UNIVERSALLY_HATED_REQUIREMENT)
award_role(/datum/award/achievement/mafia/universally_hated, loser)
//refresh the lists
judgement_abstain_votes = list()
@@ -369,8 +396,11 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
* * role: mafia_role datum to reward.
*/
/datum/mafia_controller/proc/award_role(award, datum/mafia_role/rewarded)
- var/client/role_client = rewarded.body.client
- role_client?.give_award(award, rewarded.body)
+ rewarded.body?.client?.give_award(award, rewarded.body)
+ if(!rewarded.player_pda)
+ return
+ for(var/datum/tgui/window as anything in rewarded.player_pda.open_uis)
+ window.user?.client?.give_award(award, rewarded.body)
/**
* The end of the game is in two procs, because we want a bit of time for players to see eachothers roles.
@@ -584,21 +614,28 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
RegisterSignal(H, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(display_votes))
var/datum/action/innate/mafia_panel/mafia_panel = new(null,src)
mafia_panel.Grant(H)
+ var/obj/item/modular_computer/modpc = role.player_pda
+ role.register_body(H)
+ if(modpc)
+ player_role_lookup[modpc] = role
+ else
+ player_role_lookup[H] = role
var/client/player_client = GLOB.directory[role.player_key]
if(player_client)
- player_client.prefs.safe_transfer_prefs_to(H, is_antag = TRUE)
- role.body = H
- player_role_lookup[H] = role
- role.put_player_in_body(player_client)
+ role.put_player_in_body(player_client)
role.greet()
-/datum/mafia_controller/ui_static_data(mob/user)
+/datum/mafia_controller/ui_static_data(atom/user)
var/list/data = list()
- if(user.client?.holder)
+ if(usr.client?.holder)
data["admin_controls"] = TRUE //show admin buttons to start/setup/stop
+ data["is_observer"] = isobserver(user)
data["all_roles"] = current_setup_text
+ if(phase == MAFIA_PHASE_SETUP)
+ return data
+
var/datum/mafia_role/user_role = player_role_lookup[user]
if(user_role)
data["roleinfo"] = list(
@@ -610,7 +647,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
return data
-/datum/mafia_controller/ui_data(mob/user)
+/datum/mafia_controller/ui_data(atom/user)
var/list/data = list()
data["phase"] = phase
@@ -619,18 +656,25 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
if(phase == MAFIA_PHASE_SETUP)
data["lobbydata"] = list()
- for(var/key in GLOB.mafia_signup + GLOB.mafia_bad_signup)
+ for(var/key in GLOB.mafia_signup + GLOB.mafia_bad_signup + GLOB.pda_mafia_signup)
var/list/lobby_member = list()
lobby_member["name"] = key
lobby_member["status"] = (key in GLOB.mafia_bad_signup) ? "Disconnected" : "Ready"
data["lobbydata"] += list(lobby_member)
return data
- data["timeleft"] = next_phase_timer ? timeleft(next_phase_timer) : 0 //the tgui menu counts this down.
+ data["timeleft"] = next_phase_timer ? timeleft(next_phase_timer) : 0
var/datum/mafia_role/user_role = player_role_lookup[user]
if(user_role)
data["user_notes"] = user_role.written_notes
+ data["messages"] = list()
+ var/list/ui_messages = list()
+ for(var/i = user_role.role_messages.len to 1 step -1)
+ ui_messages.Add(list(list(
+ "msg" = user_role.role_messages[i],
+ )))
+ data["messages"] = ui_messages
data["players"] = list()
for(var/datum/mafia_role/role as anything in all_roles)
@@ -659,8 +703,13 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
if(.)
return
var/datum/mafia_role/user_role = player_role_lookup[usr]
+ var/obj/item/modular_computer/modpc = ui.src_object
+ if(istype(modpc))
+ user_role = player_role_lookup[modpc]
+ else
+ modpc = null
//Admin actions
- if(usr.client?.holder)
+ if(ui.user.client.holder)
switch(action)
if("new_game")
if(phase == MAFIA_PHASE_SETUP)
@@ -686,9 +735,8 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
player.body.forceMove(get_turf(player.assigned_landmark))
if(failed.len)
to_chat(usr, "List of players who no longer had a body (if you see this, the game is runtiming anyway so just hit \"New Game\" to end it)")
- for(var/i in failed)
- var/datum/mafia_role/fail = i
- to_chat(usr, fail.player_key)
+ for(var/datum/mafia_role/fail as anything in failed)
+ to_chat(usr, fail.player_key || fail.player_pda)
if("debug_setup")
var/list/debug_setup = list()
var/list/rolelist_dict = list("CANCEL", "FINISH") + GLOB.mafia_roles_by_name
@@ -732,38 +780,61 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
if(!user_role)//just the dead
switch(action)
if("mf_signup")
- var/client/C = ui.user.client
+ var/client/ghost_client = ui.user.client
if(!SSticker.HasRoundStarted())
to_chat(usr, span_warning("Wait for the round to start."))
return
- if(GLOB.mafia_signup[C.ckey])
- GLOB.mafia_signup -= C.ckey
- GLOB.mafia_early_votes -= C.ckey //Remove their early start vote as well
- to_chat(usr, span_notice("You unregister from Mafia."))
- return TRUE
+ if(isnull(modpc))
+ if(GLOB.mafia_signup[ghost_client.ckey])
+ GLOB.mafia_signup -= ghost_client.ckey
+ GLOB.mafia_early_votes -= ghost_client.ckey //Remove their early start vote as well
+ to_chat(usr, span_notice("You unregister from Mafia."))
+ return TRUE
+ else
+ GLOB.mafia_signup[ghost_client.ckey] = TRUE
+ to_chat(usr, span_notice("You sign up for Mafia."))
else
- GLOB.mafia_signup[C.ckey] = TRUE
- to_chat(usr, span_notice("You sign up for Mafia."))
+ if(GLOB.pda_mafia_signup[modpc])
+ GLOB.pda_mafia_signup -= modpc
+ GLOB.mafia_early_votes -= modpc //Remove their early start vote as well
+ to_chat(usr, span_notice("You unregister from Mafia."))
+ return TRUE
+ else
+ GLOB.pda_mafia_signup[modpc] = TRUE
+ to_chat(usr, span_notice("You sign up for Mafia."))
if(phase == MAFIA_PHASE_SETUP)
check_signups()
try_autostart()
return TRUE
if("vote_to_start")
- var/client/C = ui.user.client
+ var/client/ghost_client = ui.user.client
if(phase != MAFIA_PHASE_SETUP)
to_chat(usr, span_notice("You cannot vote to start while a game is underway!"))
return
- if(!GLOB.mafia_signup[C.ckey])
- to_chat(usr, span_notice("You must be signed up for this game to vote!"))
- return
- if(GLOB.mafia_early_votes[C.ckey])
- GLOB.mafia_early_votes -= C.ckey
- to_chat(usr, span_notice("You are no longer voting to start the game early."))
+ if(isnull(modpc))
+ if(!GLOB.mafia_signup[ghost_client.ckey])
+ to_chat(usr, span_notice("You must be signed up for this game to vote!"))
+ return
+ if(GLOB.mafia_early_votes[ghost_client.ckey])
+ GLOB.mafia_early_votes -= ghost_client.ckey
+ to_chat(usr, span_notice("You are no longer voting to start the game early."))
+ else
+ GLOB.mafia_early_votes[ghost_client.ckey] = ghost_client
+ to_chat(usr, span_notice("You vote to start the game early ([length(GLOB.mafia_early_votes)] out of [max(round(length(GLOB.mafia_signup) / 2), round(MAFIA_MIN_PLAYER_COUNT / 2))])."))
+ if(check_start_votes()) //See if we have enough votes to start
+ forced_setup()
else
- GLOB.mafia_early_votes[C.ckey] = C
- to_chat(usr, span_notice("You vote to start the game early ([length(GLOB.mafia_early_votes)] out of [max(round(length(GLOB.mafia_signup) / 2), round(MAFIA_MIN_PLAYER_COUNT / 2))])."))
- if(check_start_votes()) //See if we have enough votes to start
- forced_setup()
+ if(!GLOB.pda_mafia_signup[modpc])
+ to_chat(usr, span_notice("You must be signed up for this game to vote!"))
+ return
+ if(GLOB.mafia_early_votes[modpc])
+ GLOB.mafia_early_votes -= modpc
+ to_chat(usr, span_notice("You are no longer voting to start the game early."))
+ else
+ GLOB.mafia_early_votes[modpc] = modpc
+ to_chat(usr, span_notice("You vote to start the game early ([length(GLOB.mafia_early_votes)] out of [max(round(length(GLOB.mafia_signup) / 2), round(MAFIA_MIN_PLAYER_COUNT / 2))])."))
+ if(check_start_votes()) //See if we have enough votes to start
+ forced_setup()
return TRUE
if(user_role && user_role.game_status == MAFIA_DEAD)
@@ -774,8 +845,14 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
if("change_notes")
if(user_role.game_status == MAFIA_DEAD)
return TRUE
- user_role.written_notes = params["new_notes"]
- user_role.body.balloon_alert(user_role.body, "notes saved")
+ user_role.written_notes = sanitize_text(params["new_notes"])
+ user_role.send_message_to_player("notes saved", balloon_alert = TRUE)
+ return TRUE
+ if("send_message_to_chat")
+ if(user_role.game_status == MAFIA_DEAD)
+ return TRUE
+ var/message_said = sanitize_text(params["message"])
+ user_role.body.say(message_said, forced = "mafia chat (sent by [ui.user.client])")
return TRUE
if("send_notes_to_chat")
if(user_role.game_status == MAFIA_DEAD || !user_role.written_notes)
@@ -807,21 +884,21 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
if("vote_abstain")
if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_abstain_votes))
return
- to_chat(user_role.body,"You have decided to abstain.")
+ user_role.send_message_to_player("You have decided to abstain.")
judgement_innocent_votes -= user_role
judgement_guilty_votes -= user_role
judgement_abstain_votes += user_role
if("vote_innocent")
if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_innocent_votes))
return
- to_chat(user_role.body,"Your vote on [on_trial.body.real_name] submitted as INNOCENT!")
+ user_role.send_message_to_player("Your vote on [on_trial.body.real_name] submitted as INNOCENT!")
judgement_abstain_votes -= user_role//no fakers, and...
judgement_guilty_votes -= user_role//no radical centrism
judgement_innocent_votes += user_role
if("vote_guilty")
if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_guilty_votes))
return
- to_chat(user_role.body,"Your vote on [on_trial.body.real_name] submitted as GUILTY!")
+ user_role.send_message_to_player("Your vote on [on_trial.body.real_name] submitted as GUILTY!")
judgement_abstain_votes -= user_role//no fakers, and...
judgement_innocent_votes -= user_role//no radical centrism
judgement_guilty_votes += user_role
@@ -886,12 +963,15 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
if(setup.len)
req_players = assoc_value_sum(setup)
+ var/list/filtered_pdas = GLOB.pda_mafia_signup
+ if(!isnull(filtered_pdas)) //pdas get priority
+ req_players -= length(GLOB.pda_mafia_signup)
var/list/filtered_keys = filter_players(req_players)
- var/needed_players = length(filtered_keys)
+ var/needed_players = length(filtered_keys) + length(filtered_pdas)
if(!setup.len) //don't actually have one yet, so generate a max player random setup. it's good to do this here instead of above so it doesn't generate one every time a game could possibly start.
setup = generate_standard_setup(needed_players)
- prepare_game(setup, filtered_keys)
+ prepare_game(setup, filtered_keys, filtered_pdas)
start_game()
/**
@@ -902,8 +982,9 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
/datum/mafia_controller/proc/forced_setup()
check_signups() //Refresh the signup list, so our numbers are accurate and we only take active players into consideration.
+ var/list/filtered_pdas = GLOB.pda_mafia_signup
var/list/filtered_keys = filter_players(length(GLOB.mafia_signup))
- var/req_players = length(filtered_keys)
+ var/req_players = length(filtered_keys) + length(filtered_pdas)
if(!req_players) //If we have nobody signed up, we give up on starting
log_admin("Attempted to force a mafia game to start with nobody signed up!")
@@ -911,7 +992,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
var/list/setup = generate_standard_setup(req_players)
- prepare_game(setup, filtered_keys)
+ prepare_game(setup, filtered_keys, filtered_pdas)
early_start = TRUE
start_game()
@@ -983,7 +1064,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
/datum/mafia_controller/proc/try_autostart()
if(phase != MAFIA_PHASE_SETUP || !(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME))
return
- if(GLOB.mafia_signup.len >= MAFIA_MAX_PLAYER_COUNT || custom_setup)//enough people to try and make something (or debug mode)
+ if((GLOB.mafia_signup.len + GLOB.pda_mafia_signup.len) >= MAFIA_MAX_PLAYER_COUNT || custom_setup)//enough people to try and make something (or debug mode)
basic_setup()
/**
@@ -1034,7 +1115,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
maptext_height = 480
maptext_width = 480
///The client that owns the popup.
- var/datum/mafia_role/mafia/owner
+ var/datum/mafia_role/owner
/atom/movable/screen/mafia_popup/Initialize(mapload, datum/mafia_role/mafia)
. = ..()
@@ -1045,6 +1126,9 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
return ..()
/atom/movable/screen/mafia_popup/proc/update_text(text)
+ owner.role_messages += text
+ if(!owner.body.client)
+ return
maptext = MAPTEXT(" [text]")
maptext_width = view_to_pixels(owner.body.client?.view_size.getView())[1]
owner.body.client?.screen += src
@@ -1063,3 +1147,5 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment())
QDEL_NULL(GLOB.mafia_game)
var/datum/mafia_controller/new_controller = new()
return new_controller
+
+#undef UNIVERSALLY_HATED_REQUIREMENT
diff --git a/code/modules/mafia/map_pieces.dm b/code/modules/mafia/map_pieces.dm
index 342f4a9045a..0d27d6cd1b5 100644
--- a/code/modules/mafia/map_pieces.dm
+++ b/code/modules/mafia/map_pieces.dm
@@ -26,17 +26,6 @@
MF = create_mafia_game()
MF.ui_interact(user)
-/area/centcom/mafia
- name = "Mafia Minigame"
- icon_state = "mafia"
- static_lighting = FALSE
-
- base_lighting_alpha = 255
- requires_power = FALSE
- has_gravity = STANDARD_GRAVITY
- flags_1 = NONE
- area_flags = BLOCK_SUICIDE | UNIQUE_AREA
-
/datum/map_template/mafia
should_place_on_top = FALSE
///A brief background tidbit
diff --git a/code/modules/mafia/roles/changelings/changeling.dm b/code/modules/mafia/roles/changelings/changeling.dm
index 2415e39f8ee..8e650515ffb 100644
--- a/code/modules/mafia/roles/changelings/changeling.dm
+++ b/code/modules/mafia/roles/changelings/changeling.dm
@@ -1,6 +1,6 @@
/datum/mafia_role/mafia
name = "Changeling"
- desc = "You're a member of the changeling hive. Use ':j' talk prefix to talk to your fellow lings."
+ desc = "You're a member of the changeling hive. You may speak with your fellow Changelings at night."
team = MAFIA_TEAM_MAFIA
role_type = MAFIA_REGULAR
role_flags = ROLE_CAN_KILL
diff --git a/code/modules/mafia/roles/roles.dm b/code/modules/mafia/roles/roles.dm
index e8b5f8a63ab..efe0d25c5b9 100644
--- a/code/modules/mafia/roles/roles.dm
+++ b/code/modules/mafia/roles/roles.dm
@@ -15,7 +15,15 @@
///The player's written notes, that they can send to chat at any time.
var/written_notes
+ ///The ckey of the person playing as this Mafia role, CAN BE NULL IN FAVOR OF player_pda.
var/player_key
+ ///The PDA of the person playing as this Mafia role, CAN BE NULL IN FAVOR OF player_key.
+ var/obj/item/modular_computer/player_pda
+
+ ///List of all messages this role got throughout the game.
+ var/list/role_messages = list()
+
+
var/mob/living/carbon/human/body
var/obj/effect/landmark/mafia/assigned_landmark
@@ -46,11 +54,52 @@
role_unique_actions -= abilities
/datum/mafia_role/Destroy(force, ...)
+ UnregisterSignal(body, COMSIG_MOB_SAY)
QDEL_NULL(mafia_alert)
QDEL_NULL(body)
QDEL_LIST(role_unique_actions)
+ role_messages = null
return ..()
+/datum/mafia_role/proc/register_body(mob/living/carbon/human/new_body)
+ body = new_body
+ RegisterSignal(new_body, COMSIG_MOB_SAY, PROC_REF(handle_speech))
+
+/**
+ * send_message_to_player
+ *
+ * Sends a message to a player, checking if they are playing through a PDA or not.
+ * Args:
+ * * message - The message to send to the person
+ * * balloon_alert - Whether it should be as a balloon alert, only if it's to a non-PDA user.
+ */
+/datum/mafia_role/proc/send_message_to_player(message, balloon_alert = FALSE)
+ if(player_pda)
+ role_messages += message
+ return
+ if(balloon_alert)
+ body.balloon_alert(body, message)
+ return
+ to_chat(body, message)
+
+/**
+ * handle_speech
+ *
+ * Handles Mafia roles talking in chat.
+ * First it will go through their abilities for Ability-specific speech,
+ * if none affects it, we will go to day chat.
+ */
+/datum/mafia_role/proc/handle_speech(datum/source, list/speech_args)
+ SIGNAL_HANDLER
+ for(var/datum/mafia_ability/abilities as anything in role_unique_actions)
+ if(abilities.handle_speech(source, speech_args))
+ return
+ var/datum/mafia_controller/mafia_game = GLOB.mafia_game
+ if(!mafia_game || mafia_game.phase == MAFIA_PHASE_NIGHT)
+ return
+ var/message = "[source]: [html_decode(speech_args[SPEECH_MESSAGE])]"
+ mafia_game.send_message(message, log_only = TRUE)
+
/**
* Puts the player in their body and keeps track of their previous one to put them back in later.
* Adds the playing_mafia trait so people examining them will know why they're currently lacking a soul.
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index 0de25b903ab..89e6eca3293 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -500,7 +500,7 @@
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext) //Yeah, we're checking alert_able. No, you don't get to make alerts that the user can't silence.
return FALSE
playsound(src, sound, 50, TRUE)
- loc.visible_message(span_notice("[icon2html(src)] [span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]")]"))
+ physical.loc.visible_message(span_notice("[icon2html(physical, viewers(physical.loc))] \The [src] displays a [caller.filedesc] notification: [alerttext]"))
/obj/item/modular_computer/proc/ring(ringtone) // bring bring
if(HAS_TRAIT(SSstation, STATION_TRAIT_PDA_GLITCHED))
@@ -517,7 +517,6 @@
var/list/data = list()
data["PC_device_theme"] = device_theme
- data["PC_showbatteryicon"] = !!internal_cell
if(internal_cell)
switch(internal_cell.percent())
@@ -535,8 +534,8 @@
data["PC_batteryicon"] = "batt_5.gif"
data["PC_batterypercent"] = "[round(internal_cell.percent())]%"
else
- data["PC_batteryicon"] = "batt_5.gif"
- data["PC_batterypercent"] = "N/C"
+ data["PC_batteryicon"] = null
+ data["PC_batterypercent"] = null
switch(get_ntnet_status())
if(NTNET_NO_SIGNAL)
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index 6f693b5bf99..8cb741d376e 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -132,7 +132,7 @@
if(isAdminGhostAI(user))
return TRUE
- if(!transfer && computer && (computer.obj_flags & EMAGGED)) //emags can bypass the execution locks but not the download ones.
+ if(computer && (computer.obj_flags & EMAGGED) && (available_on_syndinet || !transfer)) //emagged can run anything on syndinet, and can bypass execution locks, but not download.
return TRUE
// Defaults to required_access
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
index 339dd3175eb..856cc9b6b02 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
@@ -19,11 +19,11 @@
/datum/computer_file/program/ntnet_dos/process_tick(seconds_per_tick)
dos_speed = 0
switch(ntnet_status)
- if(1)
+ if(NTNET_LOW_SIGNAL)
dos_speed = NTNETSPEED_LOWSIGNAL * 10
- if(2)
+ if(NTNET_GOOD_SIGNAL)
dos_speed = NTNETSPEED_HIGHSIGNAL * 10
- if(3)
+ if(NTNET_ETHERNET_SIGNAL)
dos_speed = NTNETSPEED_ETHERNET * 10
if(target && executed)
target.dos_overload += dos_speed
diff --git a/code/modules/modular_computers/file_system/programs/frontier.dm b/code/modules/modular_computers/file_system/programs/frontier.dm
index b724892da7e..9c6e33bcde9 100644
--- a/code/modules/modular_computers/file_system/programs/frontier.dm
+++ b/code/modules/modular_computers/file_system/programs/frontier.dm
@@ -18,12 +18,9 @@
/// The file under consideration.
var/datum/computer_file/data/ordnance/selected_file
-/datum/computer_file/program/scipaper_program/New()
+/datum/computer_file/program/scipaper_program/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
. = ..()
paper_to_be = new
-
-/datum/computer_file/program/scipaper_program/on_start(mob/living/user)
- . = ..()
if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb)
CONNECT_TO_RND_SERVER_ROUNDSTART(linked_techweb, computer)
diff --git a/code/modules/modular_computers/file_system/programs/mafia_ntos.dm b/code/modules/modular_computers/file_system/programs/mafia_ntos.dm
new file mode 100644
index 00000000000..7bd5b81a240
--- /dev/null
+++ b/code/modules/modular_computers/file_system/programs/mafia_ntos.dm
@@ -0,0 +1,72 @@
+/datum/computer_file/program/mafia
+ filename = "mafia"
+ filedesc = "Mafia"
+ program_icon_state = "mafia"
+ extended_desc = "A program that allows you to play the infamous Mafia game, straight from your Modular PC."
+ requires_ntnet = FALSE
+ size = 6
+ tgui_id = "NtosMafiaPanel"
+ program_icon = "user-secret"
+ alert_able = TRUE
+
+/datum/computer_file/program/mafia/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
+ . = ..()
+ RegisterSignal(SSdcs, COMSIG_MAFIA_GAME_START, PROC_REF(on_game_start))
+
+/datum/computer_file/program/mafia/Destroy(force)
+ var/datum/mafia_controller/game = GLOB.mafia_game
+ if(!game)
+ return
+ UnregisterSignal(game, COMSIG_MAFIA_GAME_END)
+ var/datum/mafia_role/pda_role = game.player_role_lookup[computer]
+ if(!pda_role)
+ return
+ game.send_message(span_notice("[pda_role.body] has deleted the game from their PDA, and therefore has left the game."))
+ pda_role.kill(game)
+ return ..()
+
+/datum/computer_file/program/mafia/ui_static_data(mob/user)
+ var/list/data = list()
+ var/datum/mafia_controller/game = GLOB.mafia_game
+ if(!game)
+ game = create_mafia_game()
+ data += game.ui_static_data(computer)
+ return data
+
+/datum/computer_file/program/mafia/ui_data(mob/user)
+ var/list/data = list()
+ var/datum/mafia_controller/game = GLOB.mafia_game
+ if(!game)
+ game = create_mafia_game()
+ data += game.ui_data(computer)
+ return data
+
+/datum/computer_file/program/mafia/ui_assets(mob/user)
+ var/list/data = list()
+ var/datum/mafia_controller/game = GLOB.mafia_game
+ if(!game)
+ game = create_mafia_game()
+ data += game.ui_assets(user)
+ return data
+
+/datum/computer_file/program/mafia/ui_act(mob/user, params, datum/tgui/ui, datum/ui_state/state)
+ var/datum/mafia_controller/game = GLOB.mafia_game
+ if(!game)
+ game = create_mafia_game()
+ return game.ui_act(user, params, ui, state)
+
+///Called when a game of Mafia starts, sets the ui header to the proper one.
+/datum/computer_file/program/mafia/proc/on_game_start(datum/controller/subsystem/processing/dcs/source, datum/mafia_controller/game)
+ SIGNAL_HANDLER
+ RegisterSignal(game, COMSIG_MAFIA_GAME_END, PROC_REF(on_game_end))
+ ui_header = "mafia.gif"
+ if(game.player_role_lookup[computer])
+ alert_pending = TRUE
+ computer.alert_call(src, "Mafia game started!")
+
+///Called when a game of Mafia ends, deletes its ui header.
+/datum/computer_file/program/mafia/proc/on_game_end(datum/mafia_controller/game)
+ SIGNAL_HANDLER
+ UnregisterSignal(game, COMSIG_MAFIA_GAME_END)
+ ui_header = null
+ update_static_data_for_all_viewers()
diff --git a/code/modules/modular_computers/file_system/programs/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
index efa61b2630c..c9723d905b5 100644
--- a/code/modules/modular_computers/file_system/programs/ntdownloader.dm
+++ b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
@@ -7,19 +7,16 @@
size = 4
requires_ntnet = TRUE
available_on_ntnet = FALSE
- ui_header = "downloader_finished.gif"
tgui_id = "NtosNetDownloader"
program_icon = "download"
- var/datum/computer_file/program/downloaded_file = null
+ var/datum/computer_file/program/downloaded_file
var/hacked_download = FALSE
var/download_completion = FALSE //GQ of downloaded data.
var/download_netspeed = 0
var/downloaderror = ""
- var/list/main_repo
- var/list/antag_repo
- var/list/show_categories = list(
+ var/static/list/show_categories = list(
PROGRAM_CATEGORY_CREW,
PROGRAM_CATEGORY_ENGI,
PROGRAM_CATEGORY_SCI,
@@ -27,10 +24,9 @@
PROGRAM_CATEGORY_MISC,
)
-/datum/computer_file/program/ntnetdownload/on_start()
+/datum/computer_file/program/ntnetdownload/kill_program(mob/user)
. = ..()
- main_repo = SSmodular_computers.available_station_software
- antag_repo = SSmodular_computers.available_antag_software
+ ui_header = null
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename)
if(downloaded_file)
@@ -50,10 +46,10 @@
ui_header = "downloader_running.gif"
- if(PRG in main_repo)
+ if(PRG in SSmodular_computers.available_station_software)
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.")
hacked_download = FALSE
- else if(PRG in antag_repo)
+ else if(PRG in SSmodular_computers.available_antag_software)
generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.")
hacked_download = TRUE
else
@@ -68,7 +64,7 @@
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].")
downloaded_file = null
download_completion = FALSE
- ui_header = "downloader_finished.gif"
+ ui_header = null
/datum/computer_file/program/ntnetdownload/proc/complete_file_download()
if(!downloaded_file)
@@ -90,11 +86,11 @@
download_netspeed = 0
// Speed defines are found in misc.dm
switch(ntnet_status)
- if(1)
+ if(NTNET_LOW_SIGNAL)
download_netspeed = NTNETSPEED_LOWSIGNAL
- if(2)
+ if(NTNET_GOOD_SIGNAL)
download_netspeed = NTNETSPEED_HIGHSIGNAL
- if(3)
+ if(NTNET_ETHERNET_SIGNAL)
download_netspeed = NTNETSPEED_ETHERNET
download_completion += download_netspeed
@@ -132,7 +128,7 @@
data["disk_used"] = computer.used_capacity
data["emagged"] = (computer.obj_flags & EMAGGED)
- var/list/repo = antag_repo | main_repo
+ var/list/repo = SSmodular_computers.available_antag_software | SSmodular_computers.available_station_software
var/list/program_categories = list()
for(var/datum/computer_file/program/programs as anything in repo)
@@ -147,7 +143,7 @@
"installed" = !!computer.find_file_by_name(programs.filename),
"compatible" = check_compatibility(programs),
"size" = programs.size,
- "access" = (computer.obj_flags & EMAGGED) && programs.available_on_syndinet ? TRUE : programs.can_run(user, transfer = TRUE, access = access),
+ "access" = programs.can_run(user, transfer = TRUE, access = access),
"verifiedsource" = programs.available_on_ntnet,
))
diff --git a/code/modules/modular_computers/file_system/programs/techweb.dm b/code/modules/modular_computers/file_system/programs/techweb.dm
index dc9538cf358..77d0a0900e4 100644
--- a/code/modules/modular_computers/file_system/programs/techweb.dm
+++ b/code/modules/modular_computers/file_system/programs/techweb.dm
@@ -21,7 +21,7 @@
/// Sequence var for the id cache
var/id_cache_seq = 1
-/datum/computer_file/program/science/on_start(mob/living/user)
+/datum/computer_file/program/science/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
. = ..()
if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research)
CONNECT_TO_RND_SERVER_ROUNDSTART(stored_research, computer)
diff --git a/icons/obj/machines/modular_console.dmi b/icons/obj/machines/modular_console.dmi
index 86e3d713957..2677dbb7122 100644
Binary files a/icons/obj/machines/modular_console.dmi and b/icons/obj/machines/modular_console.dmi differ
diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi
index 22432826e92..ee275066d16 100644
Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ
diff --git a/icons/obj/modular_pda.dmi b/icons/obj/modular_pda.dmi
index 18df3249e62..b43be78e717 100644
Binary files a/icons/obj/modular_pda.dmi and b/icons/obj/modular_pda.dmi differ
diff --git a/icons/program_icons/mafia.gif b/icons/program_icons/mafia.gif
new file mode 100644
index 00000000000..5821f55e1e4
Binary files /dev/null and b/icons/program_icons/mafia.gif differ
diff --git a/tgstation.dme b/tgstation.dme
index 1e73952b6fd..aba28f0fd3a 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -4975,6 +4975,7 @@
#include "code\modules\modular_computers\file_system\programs\file_browser.dm"
#include "code\modules\modular_computers\file_system\programs\frontier.dm"
#include "code\modules\modular_computers\file_system\programs\jobmanagement.dm"
+#include "code\modules\modular_computers\file_system\programs\mafia_ntos.dm"
#include "code\modules\modular_computers\file_system\programs\newscasterapp.dm"
#include "code\modules\modular_computers\file_system\programs\notepad.dm"
#include "code\modules\modular_computers\file_system\programs\nt_pay.dm"
diff --git a/tgui/packages/tgui/interfaces/MafiaPanel.tsx b/tgui/packages/tgui/interfaces/MafiaPanel.tsx
index 2820822eaf4..528f6260b8d 100644
--- a/tgui/packages/tgui/interfaces/MafiaPanel.tsx
+++ b/tgui/packages/tgui/interfaces/MafiaPanel.tsx
@@ -1,4 +1,5 @@
import { classes } from 'common/react';
+import { decodeHtmlEntities } from 'common/string';
import { multiline } from 'common/string';
import { useBackend, useLocalState } from '../backend';
import { Box, Button, Collapsible, Flex, NoticeBox, Section, Stack, Tabs, TextArea } from '../components';
@@ -31,39 +32,58 @@ type LobbyData = {
status: string;
};
+type MessageData = {
+ msg: string;
+};
+
type MafiaData = {
players: PlayerInfo[];
lobbydata: LobbyData[];
+ messages: MessageData[];
user_notes: string;
roleinfo: RoleInfo;
phase: string;
turn: number;
timeleft: number;
+ is_observer: boolean;
all_roles: string[];
admin_controls: boolean;
};
-export const MafiaPanel = (props, context) => {
+export const MafiaPanelData = (props, context) => {
const { act, data } = useBackend(context);
- const { phase, roleinfo, admin_controls } = data;
+ const { phase, roleinfo, admin_controls, messages } = data;
const [mafia_tab, setMafiaMode] = useLocalState(
context,
'mafia_tab',
'Role list'
);
+
+ if (phase === 'No Game') {
+ return (
+
+
+
+
+
+
+ {!!admin_controls && }
+
+
+
+
+ );
+ }
+
return (
-
-
+
+ {!!roleinfo && (
+
+
+
+ )}
+
- {!roleinfo && (
-
-
-
- )}
{!!roleinfo && (
<>
@@ -76,65 +96,125 @@ export const MafiaPanel = (props, context) => {
)}
>
)}
- {!!admin_controls && }
+
+ {!!admin_controls && }
+
{phase !== 'No Game' && (
-
-
- <>
-
-
-
-
-
-
- setMafiaMode('Role list')}>
- Role list
-
+
- >
-
-
+ {mafia_tab === 'Role list' && }
+ {mafia_tab === 'Notes' && }
+
+ >
+
)}
+
+
+ );
+};
+
+export const MafiaPanel = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { roleinfo } = data;
+ return (
+
+
+
);
};
+const MafiaChat = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { messages } = data;
+ const [message_to_send, setMessagingBox] = useLocalState(context, 'Chat', '');
+ return (
+
+ {!!messages && (
+ <>
+ {' '}
+
+ {messages.map((message) => (
+ {decodeHtmlEntities(message.msg)}
+ ))}
+
+
+ );
+};
+
const MafiaLobby = (props, context) => {
const { act, data } = useBackend(context);
- const { lobbydata = [] } = data;
+ const { lobbydata = [], is_observer } = data;
const readyGhosts = lobbydata
? lobbydata.filter((player) => player.status === 'Ready')
: null;
@@ -173,18 +253,22 @@ const MafiaLobby = (props, context) => {
The lobby currently has {readyGhosts ? readyGhosts.length : '0'}/12
valid players signed up.
-
- Players who sign up for Mafia while dead will be returned to their
- bodies after the game finishes, allowing you to temporarily exit to play
- a match.
-
+ {!!is_observer && (
+
+ Players who sign up for Mafia while dead will be returned to their
+ bodies after the game finishes, allowing you to temporarily exit to
+ play a match.
+
+ )}
{lobbydata.map((lobbyist) => (
- {lobbyist.name}
+
+ {!is_observer ? 'Unknown Player' : lobbyist.name}
+ Status:
{lobbyist.status}
@@ -200,6 +284,7 @@ const MafiaRole = (props, context) => {
const { phase, turn, roleinfo, timeleft } = data;
return (
{
const { players } = data;
return (
-
+
{players?.map((player) => (
-
-
+
+
{player.name} {!player.alive && '(DEAD)'}
-
+
{player.votes !== undefined &&
!!player.alive &&
`Votes: ${player.votes}`}
-
+
{player.possible_actions?.map((action) => (
{
+ return (
+
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/layouts/NtosWindow.js b/tgui/packages/tgui/layouts/NtosWindow.js
index 25d853a3249..a8844accb16 100644
--- a/tgui/packages/tgui/layouts/NtosWindow.js
+++ b/tgui/packages/tgui/layouts/NtosWindow.js
@@ -15,7 +15,6 @@ export const NtosWindow = (props, context) => {
const {
PC_device_theme,
PC_batteryicon,
- PC_showbatteryicon,
PC_batterypercent,
PC_ntneticon,
PC_stationdate,
@@ -61,7 +60,7 @@ export const NtosWindow = (props, context) => {
/>
)}
- {!!(PC_showbatteryicon && PC_batteryicon) && (
+ {!!PC_batteryicon && (