diff --git a/_maps/map_files/Mafia/mafia_ayylmao.dmm b/_maps/map_files/Mafia/mafia_ayylmao.dmm index b9d8582f3b0..6fdc04e3d09 100644 --- a/_maps/map_files/Mafia/mafia_ayylmao.dmm +++ b/_maps/map_files/Mafia/mafia_ayylmao.dmm @@ -9,6 +9,10 @@ /obj/effect/landmark/mafia, /turf/open/floor/plating/abductor, /area/centcom/mafia) +"f" = ( +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/closed/indestructible/alien, +/area/centcom/mafia) "g" = ( /obj/mafia_game_board, /obj/effect/mapping_helpers/broken_floor, @@ -48,15 +52,6 @@ /obj/item/abductor/gizmo, /turf/open/floor/plating/abductor2, /area/centcom/mafia) -"p" = ( -/obj/machinery/door/poddoor/preopen{ - desc = "When it's time to sleep, the lights will go out. Remember - no one in space can hear you scream."; - id = "mafia"; - max_integrity = 99999; - name = "Station Night Shutters" - }, -/turf/closed/indestructible/fakeglass, -/area/centcom/mafia) "q" = ( /turf/open/floor/plating/abductor, /area/centcom/mafia) @@ -83,8 +78,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/obj/structure/window/reinforced/plasma/plastitanium, -/turf/open/floor/plating/abductor2, +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/open/space/basic, /area/centcom/mafia) "z" = ( /obj/structure/grille/indestructible, @@ -350,7 +345,7 @@ i N o r -p +x m q x @@ -578,7 +573,7 @@ q b b r -b +f q b b diff --git a/_maps/map_files/Mafia/mafia_ball.dmm b/_maps/map_files/Mafia/mafia_ball.dmm index fb4dc490d36..e642cc78783 100644 --- a/_maps/map_files/Mafia/mafia_ball.dmm +++ b/_maps/map_files/Mafia/mafia_ball.dmm @@ -67,7 +67,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/fakeglass, +/obj/effect/spawner/structure/window/reinforced/indestructible, +/turf/open/space/basic, /area/centcom/mafia) "q" = ( /turf/open/floor/iron/dark, @@ -91,8 +92,12 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/centcom/mafia) +"E" = ( +/turf/template_noop, +/area/template_noop) (1,1,1) = {" +E a a a @@ -114,10 +119,10 @@ a a a a -a -a +E "} (2,1,1) = {" +E a b b @@ -138,14 +143,13 @@ b b b b -b -b a +E "} (3,1,1) = {" +E a b -b c c c @@ -164,13 +168,13 @@ c c c b -b a +E "} (4,1,1) = {" +E a b -b c g h @@ -189,12 +193,12 @@ h k c b -b a +E "} (5,1,1) = {" a -b +a b c h @@ -214,7 +218,7 @@ i h c b -b +a a "} (6,1,1) = {" @@ -544,7 +548,7 @@ a "} (19,1,1) = {" a -b +a b c h @@ -564,13 +568,13 @@ d h c b -b +a a "} (20,1,1) = {" +E a b -b c k h @@ -589,13 +593,13 @@ h v c b -b a +E "} (21,1,1) = {" +E a b -b c c c @@ -614,10 +618,11 @@ c c c b -b a +E "} (22,1,1) = {" +E a b b @@ -638,11 +643,11 @@ b b b b -b -b a +E "} (23,1,1) = {" +E a a a @@ -664,6 +669,5 @@ a a a a -a -a +E "} diff --git a/_maps/map_files/Mafia/mafia_gothic.dmm b/_maps/map_files/Mafia/mafia_gothic.dmm index 817e145d111..5dadad3d2c1 100644 --- a/_maps/map_files/Mafia/mafia_gothic.dmm +++ b/_maps/map_files/Mafia/mafia_gothic.dmm @@ -62,7 +62,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/opsglass, +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/open/space/basic, /area/centcom/mafia) "q" = ( /turf/open/floor/carpet/red, @@ -85,6 +86,9 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/centcom/mafia) +"y" = ( +/turf/template_noop, +/area/template_noop) "D" = ( /obj/effect/landmark/mafia, /turf/open/floor/iron/chapel{ @@ -131,6 +135,9 @@ dir = 8 }, /area/centcom/mafia) +"U" = ( +/turf/closed/wall/r_wall, +/area/centcom/mafia) "X" = ( /turf/open/floor/iron/chapel{ dir = 1 @@ -138,6 +145,7 @@ /area/centcom/mafia) (1,1,1) = {" +y a a a @@ -159,38 +167,37 @@ a a a a -a -a +y "} (2,1,1) = {" +y a -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U a +y "} (3,1,1) = {" +y a -b -b +U c c c @@ -208,14 +215,14 @@ c c c c -b -b +U a +y "} (4,1,1) = {" +y a -b -b +U c g h @@ -233,14 +240,14 @@ d h k c -b -b +U a +y "} (5,1,1) = {" a -b -b +a +U c h d @@ -258,14 +265,14 @@ d i h c -b -b +U +a a "} (6,1,1) = {" a -b -b +U +U c i b @@ -283,13 +290,13 @@ b b d c -b -b +U +U a "} (7,1,1) = {" a -b +U c c d @@ -309,12 +316,12 @@ b d c c -b +U a "} (8,1,1) = {" a -b +U c d d @@ -334,12 +341,12 @@ b d d c -b +U a "} (9,1,1) = {" a -b +U c d b @@ -359,12 +366,12 @@ b b d c -b +U a "} (10,1,1) = {" a -b +U c d b @@ -384,12 +391,12 @@ Q b d c -b +U a "} (11,1,1) = {" a -b +U c d j @@ -409,12 +416,12 @@ O j i c -b +U a "} (12,1,1) = {" a -b +U c i b @@ -434,12 +441,12 @@ b b d c -b +U a "} (13,1,1) = {" a -b +U c d j @@ -459,12 +466,12 @@ q j d c -b +U a "} (14,1,1) = {" a -b +U c d b @@ -484,12 +491,12 @@ l b i c -b +U a "} (15,1,1) = {" a -b +U c d b @@ -509,12 +516,12 @@ b b d c -b +U a "} (16,1,1) = {" a -b +U c f d @@ -534,12 +541,12 @@ b d d c -b +U a "} (17,1,1) = {" a -b +U c c d @@ -559,13 +566,13 @@ b d c c -b +U a "} (18,1,1) = {" a -b -b +U +U c d b @@ -583,14 +590,14 @@ b b d c -b -b +U +U a "} (19,1,1) = {" a -b -b +a +U c h i @@ -608,14 +615,14 @@ i d h c -b -b +U +a a "} (20,1,1) = {" +y a -b -b +U c k h @@ -633,14 +640,14 @@ d h v c -b -b +U a +y "} (21,1,1) = {" +y a -b -b +U c c c @@ -658,36 +665,37 @@ c c c c -b -b +U a +y "} (22,1,1) = {" +y a -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U +U a +y "} (23,1,1) = {" +y a a a @@ -709,6 +717,5 @@ a a a a -a -a +y "} diff --git a/_maps/map_files/Mafia/mafia_lavaland.dmm b/_maps/map_files/Mafia/mafia_lavaland.dmm index 96ddef90b5c..c6189750b0a 100644 --- a/_maps/map_files/Mafia/mafia_lavaland.dmm +++ b/_maps/map_files/Mafia/mafia_lavaland.dmm @@ -82,7 +82,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/fakeglass, +/obj/effect/spawner/structure/window/reinforced/indestructible, +/turf/open/space/basic, /area/centcom/mafia) "aq" = ( /turf/open/floor/fakebasalt, @@ -282,12 +283,16 @@ }, /turf/open/floor/iron/dark, /area/centcom/mafia) +"qp" = ( +/turf/template_noop, +/area/template_noop) "GL" = ( /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron/dark, /area/centcom/mafia) (1,1,1) = {" +qp aa aa aa @@ -309,10 +314,10 @@ aa aa aa aa -aa -aa +qp "} (2,1,1) = {" +qp aa aY aY @@ -333,14 +338,13 @@ aY aY aY aY -aY -aY aa +qp "} (3,1,1) = {" +qp aa aY -aY ac ac ac @@ -359,13 +363,13 @@ ac ac ac aY -aY aa +qp "} (4,1,1) = {" +qp aa aY -aY ac ag ah @@ -384,12 +388,12 @@ ah ak ac aY -aY aa +qp "} (5,1,1) = {" aa -aY +aa aY ac ah @@ -409,7 +413,7 @@ ai ah ac aY -aY +aa aa "} (6,1,1) = {" @@ -739,7 +743,7 @@ aa "} (19,1,1) = {" aa -aY +aa aY ac ah @@ -759,13 +763,13 @@ ad ah ac aY -aY +aa aa "} (20,1,1) = {" +qp aa aY -aY ac ak ah @@ -784,13 +788,13 @@ ah av ac aY -aY aa +qp "} (21,1,1) = {" +qp aa aY -aY ac ac ac @@ -809,10 +813,11 @@ ac ac ac aY -aY aa +qp "} (22,1,1) = {" +qp aa aY aY @@ -833,11 +838,11 @@ aY aY aY aY -aY -aY aa +qp "} (23,1,1) = {" +qp aa aa aa @@ -859,6 +864,5 @@ aa aa aa aa -aa -aa +qp "} diff --git a/_maps/map_files/Mafia/mafia_snow.dmm b/_maps/map_files/Mafia/mafia_snow.dmm index b8fbc0650b4..bbc5f958d75 100644 --- a/_maps/map_files/Mafia/mafia_snow.dmm +++ b/_maps/map_files/Mafia/mafia_snow.dmm @@ -71,7 +71,8 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/fakeglass, +/obj/effect/spawner/structure/window/ice, +/turf/open/space/basic, /area/centcom/mafia) "q" = ( /turf/open/floor/iron/dark, @@ -176,6 +177,9 @@ "K" = ( /turf/closed/indestructible/rock/snow, /area/centcom/mafia) +"L" = ( +/turf/template_noop, +/area/template_noop) "R" = ( /obj/effect/landmark/mafia, /turf/open/floor/iron, @@ -187,7 +191,7 @@ /area/centcom/mafia) (1,1,1) = {" -a +L a a a @@ -212,6 +216,7 @@ a a "} (2,1,1) = {" +L a b b @@ -222,7 +227,6 @@ b b b b -b s K K @@ -237,9 +241,9 @@ K a "} (3,1,1) = {" +L a b -b s s s @@ -262,9 +266,9 @@ K a "} (4,1,1) = {" +L a b -b s g h @@ -288,7 +292,7 @@ a "} (5,1,1) = {" a -b +a b s h @@ -375,8 +379,8 @@ s q s t -p -p +s +s z z p @@ -427,7 +431,7 @@ p p p p -p +s p D p @@ -467,7 +471,7 @@ b s i s -b +s p s p @@ -477,10 +481,10 @@ v t p p +s p -p -p -p +s +s w w K @@ -527,7 +531,7 @@ p p p p -p +s p D p @@ -575,8 +579,8 @@ s r s t -p -p +s +s z z p @@ -638,7 +642,7 @@ a "} (19,1,1) = {" a -b +a b s h @@ -662,9 +666,9 @@ K a "} (20,1,1) = {" +L a b -b s k h @@ -687,9 +691,9 @@ K a "} (21,1,1) = {" +L a b -b s s s @@ -712,6 +716,7 @@ K a "} (22,1,1) = {" +L a b b @@ -722,7 +727,6 @@ b b b b -b s K K @@ -737,7 +741,7 @@ K a "} (23,1,1) = {" -a +L a a a diff --git a/_maps/map_files/Mafia/mafia_spiderclan.dmm b/_maps/map_files/Mafia/mafia_spiderclan.dmm index ff83f8de3ec..a00e373c1a4 100644 --- a/_maps/map_files/Mafia/mafia_spiderclan.dmm +++ b/_maps/map_files/Mafia/mafia_spiderclan.dmm @@ -94,11 +94,15 @@ /obj/structure/showcase/katana, /turf/open/misc/beach/sand, /area/centcom/mafia) +"Q" = ( +/turf/template_noop, +/area/template_noop) "S" = ( /turf/closed/wall/mineral/wood, /area/centcom/mafia) (1,1,1) = {" +Q a a a @@ -120,10 +124,10 @@ a a a a -a -a +Q "} (2,1,1) = {" +Q a S S @@ -144,14 +148,13 @@ S S S S -S -S a +Q "} (3,1,1) = {" +Q a S -S c c c @@ -170,13 +173,13 @@ c c c S -S a +Q "} (4,1,1) = {" +Q a S -S c g h @@ -195,12 +198,12 @@ h k c S -S a +Q "} (5,1,1) = {" a -S +a S c h @@ -220,7 +223,7 @@ i h c S -S +a a "} (6,1,1) = {" @@ -550,7 +553,7 @@ a "} (19,1,1) = {" a -S +a S c h @@ -570,13 +573,13 @@ d h c S -S +a a "} (20,1,1) = {" +Q a S -S c k h @@ -595,13 +598,13 @@ h v c S -S a +Q "} (21,1,1) = {" +Q a S -S c c c @@ -620,10 +623,11 @@ c c c S -S a +Q "} (22,1,1) = {" +Q a S S @@ -644,11 +648,11 @@ S S S S -S -S a +Q "} (23,1,1) = {" +Q a a a @@ -670,6 +674,5 @@ a a a a -a -a +Q "} diff --git a/_maps/map_files/Mafia/mafia_syndie.dmm b/_maps/map_files/Mafia/mafia_syndie.dmm index 12287245828..4c275e2ef32 100644 --- a/_maps/map_files/Mafia/mafia_syndie.dmm +++ b/_maps/map_files/Mafia/mafia_syndie.dmm @@ -46,7 +46,6 @@ /turf/open/floor/plating, /area/centcom/mafia) "o" = ( -/obj/effect/turf_decal/tile/red/fourcorners, /turf/open/floor/iron/dark, /area/centcom/mafia) "p" = ( @@ -56,14 +55,14 @@ max_integrity = 99999; name = "Station Night Shutters" }, -/turf/closed/indestructible/opsglass, +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/open/space/basic, /area/centcom/mafia) "q" = ( /obj/structure/chair/office{ dir = 1; name = "tactical swivel chair" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/landmark/mafia, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -82,14 +81,13 @@ /turf/open/floor/plating, /area/centcom/mafia) "w" = ( -/turf/closed/indestructible/syndicate, +/turf/closed/wall/r_wall, /area/centcom/mafia) "x" = ( /obj/structure/chair/office{ dir = 4; name = "tactical swivel chair" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/landmark/mafia, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -104,7 +102,6 @@ /obj/structure/chair/office{ name = "tactical swivel chair" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/landmark/mafia, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -129,7 +126,6 @@ dir = 8; name = "tactical swivel chair" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/landmark/mafia, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -146,7 +142,6 @@ desc = "A storage closet for syndicate conflict resolution operatives."; name = "red closet" }, -/obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/spawner/random/clothing/syndie, /turf/open/floor/iron/dark, /area/centcom/mafia) @@ -156,8 +151,15 @@ "S" = ( /turf/open/floor/mineral/plastitanium/red, /area/centcom/mafia) +"W" = ( +/turf/closed/wall/mineral/plastitanium, +/area/centcom/mafia) +"Y" = ( +/turf/template_noop, +/area/template_noop) (1,1,1) = {" +Y a a a @@ -179,10 +181,10 @@ a a a a -a -a +Y "} (2,1,1) = {" +Y a w w @@ -203,14 +205,13 @@ w w w w -w -w a +Y "} (3,1,1) = {" +Y a w -w c c c @@ -229,13 +230,13 @@ c c c w -w a +Y "} (4,1,1) = {" +Y a w -w c g h @@ -254,32 +255,32 @@ h k c w -w a +Y "} (5,1,1) = {" a -w +a w c h d d i -w -w +W +W j -w +W j -w -w +W +W d d i h c w -w +a a "} (6,1,1) = {" @@ -288,19 +289,19 @@ w w c i -w -w +W +W j -w +W b r -w +W o G -w +W j -w -w +W +W d c w @@ -313,7 +314,7 @@ w c c d -w +W G o p @@ -325,7 +326,7 @@ o p r b -w +W d c c @@ -338,19 +339,19 @@ w c d d -w +W o o -w -w +W +W r -w +W o -w -w +W +W r r -w +W d d c @@ -362,8 +363,8 @@ a w c d -w -w +W +W p o x @@ -375,8 +376,8 @@ p B r p -w -w +W +W d c w @@ -387,10 +388,10 @@ a w c d -w +W b p -w +W p p p @@ -398,10 +399,10 @@ p p p p -w +W p G -w +W d c w @@ -437,10 +438,10 @@ a w c i -w -w +W +W p -w +W p p Q @@ -448,10 +449,10 @@ u Q p p -w +W p -w -w +W +W d c w @@ -487,10 +488,10 @@ a w c d -w +W G p -w +W p p p @@ -498,10 +499,10 @@ p p p p -w +W p b -w +W i c w @@ -512,8 +513,8 @@ a w c d -w -w +W +W p r A @@ -525,8 +526,8 @@ p C o p -w -w +W +W d c w @@ -538,19 +539,19 @@ w c f d -w +W r r -w -w +W +W o -w +W r -w -w +W +W o o -w +W d d c @@ -563,7 +564,7 @@ w c c d -w +W b r p @@ -575,7 +576,7 @@ r p o G -w +W d c c @@ -588,19 +589,19 @@ w w c d -w -w +W +W j -w +W G o -w +W r b -w +W j -w -w +W +W d c w @@ -609,33 +610,33 @@ a "} (19,1,1) = {" a -w +a w c h i d d -w -w +W +W j -w +W j -w -w +W +W d i d h c w -w +a a "} (20,1,1) = {" +Y a w -w c k h @@ -654,13 +655,13 @@ h v c w -w a +Y "} (21,1,1) = {" +Y a w -w c c c @@ -679,10 +680,11 @@ c c c w -w a +Y "} (22,1,1) = {" +Y a w w @@ -703,11 +705,11 @@ w w w w -w -w a +Y "} (23,1,1) = {" +Y a a a @@ -729,6 +731,5 @@ a a a a -a -a +Y "} diff --git a/_maps/map_files/Mafia/mafia_unit_test.dmm b/_maps/map_files/Mafia/mafia_unit_test.dmm new file mode 100644 index 00000000000..93fd1d176ee --- /dev/null +++ b/_maps/map_files/Mafia/mafia_unit_test.dmm @@ -0,0 +1,598 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"c" = ( +/turf/open/floor/iron, +/area/centcom/mafia) +"i" = ( +/obj/effect/landmark/mafia, +/turf/open/floor/iron, +/area/centcom/mafia) +"E" = ( +/obj/effect/landmark/mafia/town_center, +/turf/open/floor/iron, +/area/centcom/mafia) +"G" = ( +/turf/closed/indestructible, +/area/centcom/mafia) +"W" = ( +/obj/mafia_game_board, +/turf/open/floor/iron, +/area/centcom/mafia) +"Y" = ( +/turf/template_noop, +/area/template_noop) + +(1,1,1) = {" +G +G +G +G +G +G +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(2,1,1) = {" +G +W +i +i +i +W +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(3,1,1) = {" +G +i +c +c +c +i +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(4,1,1) = {" +G +i +c +E +c +i +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(5,1,1) = {" +G +i +c +c +c +i +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(6,1,1) = {" +G +W +i +i +i +W +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(7,1,1) = {" +G +G +G +G +G +G +G +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(8,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(9,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(10,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(11,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(12,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(13,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(14,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(15,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(16,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(17,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(18,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(19,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(20,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(21,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(22,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} +(23,1,1) = {" +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +Y +"} diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 32e4135b965..4ab974dd4a8 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -898,6 +898,13 @@ UNTYPED_LIST_ADD(keys, key) return keys +///Gets the total amount of everything in the associative list. +/proc/assoc_value_sum(list/input) + var/list/keys = list() + for(var/key in input) + keys += input[key] + return keys + ///compare two lists, returns TRUE if they are the same /proc/compare_list(list/l,list/d) if(!islist(l) || !islist(d)) diff --git a/code/datums/mapgen/_MapGenerator.dm b/code/datums/mapgen/_MapGenerator.dm deleted file mode 100644 index cecc0c65d1b..00000000000 --- a/code/datums/mapgen/_MapGenerator.dm +++ /dev/null @@ -1,10 +0,0 @@ -///This type is responsible for any map generation behavior that is done in areas, override this to allow for area-specific map generation. This generation is ran by areas in initialize. -/datum/map_generator - -///This proc will be ran by areas on Initialize, and provides the areas turfs as argument to allow for generation. -/datum/map_generator/proc/generate_terrain(list/turfs, area/generate_in) - return - -/// Populate terrain with flora, fauna, features and basically everything that isn't a turf -/datum/map_generator/proc/populate_terrain(list/turfs, area/generate_in) - return diff --git a/code/datums/mocking/client.dm b/code/datums/mocking/client.dm index 8e09883ae21..72a0eddd5da 100644 --- a/code/datums/mocking/client.dm +++ b/code/datums/mocking/client.dm @@ -27,14 +27,22 @@ var/tgui_say var/typing_indicators +/datum/client_interface/New() + ..() + var/static/mock_client_uid = 0 + mock_client_uid++ + + src.key = "[key]_[mock_client_uid]" + ckey = ckey(key) + + GLOB.directory[ckey] = src + +/datum/client_interface/Destroy(force, ...) + GLOB.directory -= ckey + return ..() + /datum/client_interface/proc/IsByondMember() return FALSE -/datum/client_interface/New(key) - ..() - if(key) - src.key = key - ckey = ckey(key) - /datum/client_interface/proc/set_macros() return diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm index 967ae9b39a3..5b68eb5ffa8 100644 --- a/code/modules/mafia/controller.dm +++ b/code/modules/mafia/controller.dm @@ -56,9 +56,6 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) ///current timer for phase var/next_phase_timer - ///used for debugging in testing (doesn't put people out of the game, some other shit i forgot, who knows just don't set this in live) honestly kinda deprecated - var/debug = FALSE - ///was our game forced to start early? var/early_start = FALSE @@ -110,6 +107,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) /datum/mafia_controller/Destroy(force, ...) . = ..() end_game() + player_role_lookup.Cut() QDEL_NULL(map_deleter) if(GLOB.mafia_game == src) GLOB.mafia_game = null @@ -126,10 +124,9 @@ 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_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. + * * ready_ghosts_and_pdas: list of filtered, sane (so not playing or disconnected) ghost ckeys & PDAs for the game to put into roles. */ -/datum/mafia_controller/proc/prepare_game(setup_list, ready_ghosts, ready_pdas) +/datum/mafia_controller/proc/prepare_game(setup_list, ready_ghosts_and_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) @@ -141,8 +138,11 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) var/list/bounds = current_map.load(spawn_area) if(!bounds) CRASH("Loading mafia map failed!") - map_deleter.defineRegion(spawn_area, locate(spawn_area.x + 23,spawn_area.y + 23,spawn_area.z), replace = TRUE) //so we're ready to mass delete when round ends - +#ifdef UNIT_TESTS //unit test map is smaller + map_deleter.defineRegion(spawn_area, locate(spawn_area.x + 7, spawn_area.y + 7, spawn_area.z), replace = TRUE) //so we're ready to mass delete when round ends +#else + map_deleter.defineRegion(spawn_area, locate(spawn_area.x + 23, spawn_area.y + 23, spawn_area.z), replace = TRUE) //so we're ready to mass delete when round ends +#endif if(!landmarks.len)//we grab town center when we grab landmarks, if there is none (the first game signed up for let's grab them post load) for(var/obj/effect/landmark/mafia/possible_spawn in GLOB.landmarks_list) if(istype(possible_spawn, /obj/effect/landmark/mafia/town_center)) @@ -161,23 +161,14 @@ 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) - if(length(ready_pdas)) - selected_player = pick(ready_pdas) - else - selected_player = pick(ready_ghosts) - else - 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 + var/selected_player //this can be a ckey or a PDA + selected_player = pick(ready_ghosts_and_pdas) + var/client/player_client = GLOB.directory[selected_player] + if(player_client) role.player_key = selected_player - ready_ghosts -= selected_player + else + role.player_pda = selected_player + ready_ghosts_and_pdas -= selected_player ///Sends a global message to all players, or just 'team' if set. /datum/mafia_controller/proc/send_message(msg, team, log_only = FALSE) @@ -405,6 +396,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) /** * The end of the game is in two procs, because we want a bit of time for players to see eachothers roles. * Because of how check_victory works, the game is halted in other places by this point. + * We won't delete ourselves in a certain amount of time in unit tests, as the unit test will handle our deletion instead. * * What players do in this phase: * * See everyone's role postgame @@ -419,7 +411,9 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) roles.mafia_alert.update_text("[message]") roles.reveal_role(src) phase = MAFIA_PHASE_VICTORY_LAP +#ifndef UNIT_TESTS next_phase_timer = QDEL_IN_STOPPABLE(src, VICTORY_LAP_PERIOD_LENGTH) +#endif /** * Cleans up the game, resetting variables back to the beginning and removing the map with the generator. @@ -586,7 +580,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) if(phase != MAFIA_PHASE_VOTING) return - var/v = get_vote_count(player_role_lookup[source],"Day") + var/v = get_vote_count(get_role_player(source),"Day") var/mutable_appearance/MA = mutable_appearance('icons/obj/mafia.dmi',"vote_[v > 12 ? "over_12" : v]") overlay_list += MA @@ -612,310 +606,59 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) H.equipOutfit(outfit_to_distribute) H.status_flags |= GODMODE 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 + player_role_lookup[role.player_key] = role var/client/player_client = GLOB.directory[role.player_key] if(player_client) role.put_player_in_body(player_client) role.greet() -/datum/mafia_controller/ui_static_data(atom/user) - var/list/data = list() - - 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( - "role" = user_role.name, - "desc" = user_role.desc, - "hud_icon" = user_role.hud_icon, - "revealed_icon" = user_role.revealed_icon, - ) - - return data - -/datum/mafia_controller/ui_data(atom/user) - var/list/data = list() - - data["phase"] = phase - if(turn) - data["turn"] = " - Day [turn]" - - if(phase == MAFIA_PHASE_SETUP) - data["lobbydata"] = list() - 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 - - 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) - var/list/player_info = list() - player_info["name"] = role.body.real_name - player_info["ref"] = REF(role) - player_info["alive"] = role.game_status == MAFIA_ALIVE - player_info["possible_actions"] = list() - - if(user_role) //not observer - for(var/datum/mafia_ability/action as anything in user_role.role_unique_actions) - if(action.validate_action_target(src, potential_target = role, silent = TRUE)) - player_info["possible_actions"] += list(list("name" = action, "ref" = REF(action))) - - data["players"] += list(player_info) - - return data - -/datum/mafia_controller/ui_assets(mob/user) - return list( - get_asset_datum(/datum/asset/spritesheet/mafia), - ) - -/datum/mafia_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() - if(.) - return - var/datum/mafia_role/user_role = player_role_lookup[usr] - var/obj/item/modular_computer/modpc = ui.src_object +///From a 'user' (Either a mob or ModPC) or TGUI UI, will try to find the Mafia role from 'player_role_lookup'. +/datum/mafia_controller/proc/get_role_player(atom/user, datum/tgui/ui) + var/obj/item/modular_computer/modpc = ui?.src_object || user if(istype(modpc)) - user_role = player_role_lookup[modpc] + return player_role_lookup[modpc] + var/mob/mob_user = user + if(!istype(mob_user)) + CRASH("[user] is not a modPC nor a mob, but we are trying to find their role.") + return player_role_lookup[mob_user.ckey] + +/** + * Signs the player up for Mafia, or removes them from the list if they are already + * signed up. + * Args: + * - ghost_client: is the client of the observer signing up. This can be null in favor of modpc. + * - modpc: is a living player signing up through a PDA. This can be null in favor of ghost_client. + */ +/datum/mafia_controller/proc/signup_mafia(mob/user, client/ghost_client, obj/item/modular_computer/modpc) + if(!SSticker.HasRoundStarted()) + to_chat(user, span_warning("Wait for the round to start.")) + return FALSE + 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(user, span_notice("You unregister from Mafia.")) + else + GLOB.mafia_signup[ghost_client.ckey] = TRUE + to_chat(user, span_notice("You sign up for Mafia.")) else - modpc = null - //Admin actions - if(ui.user.client.holder) - switch(action) - if("new_game") - if(phase == MAFIA_PHASE_SETUP) - return - basic_setup() - if("nuke") - qdel(src) - if("next_phase") - if(phase == MAFIA_PHASE_SETUP) - return - var/datum/timedevent/timer = SStimer.timer_id_dict[next_phase_timer] - if(!timer.spent) - var/datum/callback/tc = timer.callBack - deltimer(next_phase_timer) - tc.InvokeAsync() - return TRUE - if("players_home") - var/list/failed = list() - for(var/datum/mafia_role/player in all_roles) - if(!player.body) - failed += player - continue - 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/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 - var/done = FALSE - - while(!done) - to_chat(usr, "You have a total player count of [assoc_value_sum(debug_setup)] in this setup.") - var/chosen_role_name = tgui_input_list(usr, "Select a role!", "Custom Setup Creation", rolelist_dict) - if(!chosen_role_name) - return - switch(chosen_role_name) - if("CANCEL") - done = TRUE - return - if("FINISH") - done = TRUE - break - else - var/found_path = rolelist_dict[chosen_role_name] - var/role_count = tgui_input_number(usr, "How many? Zero to cancel.", "Custom Setup Creation", 0, 12) - if(role_count > 0) - debug_setup[found_path] = role_count - custom_setup = debug_setup - early_start = TRUE - try_autostart()//don't worry, this fails if there's a game in progress - if("cancel_setup") - custom_setup = list() - if("start_now") - forced_setup() - - switch(action) //both living and dead - if("mf_lookup") - var/role_lookup = params["role_name"] - var/datum/mafia_role/helper - for(var/datum/mafia_role/role as anything in all_roles) - if(role_lookup == role.name) - helper = role - break - helper.show_help(usr) - - if(!user_role)//just the dead - switch(action) - if("mf_signup") - var/client/ghost_client = ui.user.client - if(!SSticker.HasRoundStarted()) - to_chat(usr, span_warning("Wait for the round to start.")) - return - 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 - 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/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(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 - 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) - return - - //User actions (just living) - switch(action) - if("change_notes") - if(user_role.game_status == MAFIA_DEAD) - return TRUE - user_role.written_notes = sanitize_text(params["new_notes"]) - user_role.send_message_to_player("notes saved", balloon_alert = TRUE) + 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(user, span_notice("You unregister from Mafia.")) 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) - return TRUE - if(phase == MAFIA_PHASE_NIGHT) - return TRUE - if(!COOLDOWN_FINISHED(user_role, note_chat_sending_cooldown)) - return FALSE - COOLDOWN_START(user_role, note_chat_sending_cooldown, MAFIA_NOTE_SENDING_COOLDOWN) - user_role.body.say("[user_role.written_notes]", forced = "mafia notes sending") - return TRUE - if("perform_action") - var/datum/mafia_role/target = locate(params["target"]) in all_roles - if(!istype(target)) - return - var/datum/mafia_ability/used_action = locate(params["action_ref"]) in user_role.role_unique_actions - if(!used_action) - return - switch(phase) - if(MAFIA_PHASE_DAY, MAFIA_PHASE_VOTING) - used_action.using_ability = TRUE - used_action.perform_action_target(src, target) - if(MAFIA_PHASE_NIGHT) - used_action.set_target(src, target) - return TRUE - - if(user_role != on_trial) - switch(action) - if("vote_abstain") - if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_abstain_votes)) - return - 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 - 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 - 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 - -/datum/mafia_controller/ui_state(mob/user) - return GLOB.always_state - -/datum/mafia_controller/ui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, null) - if(!ui) - ui = new(user, src, "MafiaPanel") - ui.open() - -/proc/assoc_value_sum(list/L) - . = 0 - for(var/key in L) - . += L[key] + else + GLOB.pda_mafia_signup[modpc] = TRUE + to_chat(user, span_notice("You sign up for Mafia.")) + if(phase == MAFIA_PHASE_SETUP) + check_signups() + try_autostart() + return TRUE /** * Returns a standard setup, with certain important/unique roles guaranteed. @@ -960,18 +703,16 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) /datum/mafia_controller/proc/basic_setup() var/req_players = MAFIA_MAX_PLAYER_COUNT var/list/setup = custom_setup - if(setup.len) + if(length(setup)) 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) + length(filtered_pdas) + var/list/filtered_keys_and_pdas = filter_players(req_players) - 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, filtered_pdas) + //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. + if(!length(setup)) + setup = generate_standard_setup(length(filtered_keys_and_pdas)) + prepare_game(setup, filtered_keys_and_pdas) start_game() /** @@ -982,17 +723,15 @@ 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) + length(filtered_pdas) - - if(!req_players) //If we have nobody signed up, we give up on starting + var/players_needed = GLOB.mafia_signup.len + GLOB.pda_mafia_signup.len + var/list/filtered_keys_and_pdas = filter_players(players_needed) + if(!length(filtered_keys_and_pdas)) //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!") return - var/list/setup = generate_standard_setup(req_players) + var/list/setup = generate_standard_setup(length(filtered_keys_and_pdas)) - prepare_game(setup, filtered_keys, filtered_pdas) + prepare_game(setup, filtered_keys_and_pdas) early_start = TRUE start_game() @@ -1006,10 +745,10 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) /datum/mafia_controller/proc/check_start_votes() check_signups() //Same as before. What a useful proc. - if(length(GLOB.mafia_signup) < MAFIA_MIN_PLAYER_COUNT) + if(length(GLOB.mafia_signup + GLOB.pda_mafia_signup) < MAFIA_MIN_PLAYER_COUNT) return FALSE //Make sure we have the minimum playercount to host a game first. - if(length(GLOB.mafia_early_votes) < round(length(GLOB.mafia_signup) / 2)) + if(length(GLOB.mafia_early_votes) < round(length(GLOB.mafia_signup + GLOB.pda_mafia_signup) / 2)) return FALSE return TRUE @@ -1023,38 +762,44 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) * This should only be run as we are in the process of starting a game. * * max_players - The maximum number of keys to put in our return list before we start telling people they're not getting in. - * filtered_keys - A list of player ckeys, to be included in the game. + * filtered_keys_and_pdas - A list of player ckeys and PDAs, to be included in the game. */ /datum/mafia_controller/proc/filter_players(max_players) //final list for all the players who will be in this game - var/list/filtered_keys = list() + var/list/filtered_keys_and_pdas = list() //cuts invalid players from signups (disconnected/not a ghost) - var/list/possible_keys = list() + var/list/possible_players = list() for(var/key in GLOB.mafia_signup) if(GLOB.directory[key]) var/client/C = GLOB.directory[key] if(isobserver(C.mob)) - possible_keys += key + possible_players += key continue GLOB.mafia_signup -= key //not valid to play when we checked so remove them from signups - //If we're not over capacity and don't need to notify anyone of their exclusion, return early. - if(length(possible_keys) < max_players) - return filtered_keys + for(var/obj/item/modular_computer/pda/pdas as anything in GLOB.pda_mafia_signup) + possible_players += pdas //if there were too many players, still start but only make filtered keys as big as it needs to be (cut excess) //also removes people who do get into final player list from the signup so they have to sign up again when game ends for(var/i in 1 to max_players) - var/chosen_key = pick_n_take(possible_keys) - filtered_keys += chosen_key - GLOB.mafia_signup -= chosen_key + if(!length(possible_players)) + break + var/chosen_key = pick_n_take(possible_players) + filtered_keys_and_pdas += chosen_key + if(chosen_key in GLOB.pda_mafia_signup) + GLOB.pda_mafia_signup -= chosen_key + else if(chosen_key in GLOB.mafia_signup) + GLOB.mafia_signup -= chosen_key //small message about not getting into this game for clarity on why they didn't get in - for(var/unpicked in possible_keys) + for(var/unpicked in possible_players) + if(!(unpicked in GLOB.mafia_signup)) + continue var/client/unpicked_client = GLOB.directory[unpicked] to_chat(unpicked_client, span_danger("Sorry, the starting mafia game has too many players and you were not picked.")) to_chat(unpicked_client, span_warning("You're still signed up, getting messages from the current round, and have another chance to join when the one starting now finishes.")) - return filtered_keys + return filtered_keys_and_pdas /** * Called when someone signs up, and sees if there are enough people in the signup list to begin. @@ -1073,6 +818,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) * If a disconnected player gets a non-ghost mob and reconnects, they will be first put back into mafia_signup then filtered by that. */ /datum/mafia_controller/proc/check_signups() +#ifndef UNIT_TESTS for(var/bad_key in GLOB.mafia_bad_signup) if(GLOB.directory[bad_key])//they have reconnected if we can search their key and get a client GLOB.mafia_bad_signup -= bad_key @@ -1086,6 +832,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) if(!isobserver(C.mob)) //they are back to playing the game, remove them from the signups GLOB.mafia_signup -= key +#endif /datum/action/innate/mafia_panel name = "Mafia Panel" @@ -1099,6 +846,10 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) . = ..() controller_panel = controller +/datum/action/innate/mafia_panel/Destroy() + . = ..() + controller_panel = null + /datum/action/innate/mafia_panel/Activate() controller_panel.ui_interact(owner) diff --git a/code/modules/mafia/controller_ui.dm b/code/modules/mafia/controller_ui.dm new file mode 100644 index 00000000000..9caa25d9f74 --- /dev/null +++ b/code/modules/mafia/controller_ui.dm @@ -0,0 +1,261 @@ +// 'user' can be a modPC, hence why it's pathed to the atom +/datum/mafia_controller/ui_static_data(atom/user) + var/list/data = list() + + 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 = get_role_player(user) + if(user_role) + data["roleinfo"] = list( + "role" = user_role.name, + "desc" = user_role.desc, + "hud_icon" = user_role.hud_icon, + "revealed_icon" = user_role.revealed_icon, + ) + + return data + +// 'user' can be a modPC, hence why it's pathed to the atom +/datum/mafia_controller/ui_data(atom/user) + var/list/data = list() + + data["phase"] = phase + if(turn) + data["turn"] = " - Day [turn]" + + if(phase == MAFIA_PHASE_SETUP) + data["lobbydata"] = list() + 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 + + var/datum/mafia_role/user_role = get_role_player(user) + if(user_role) + data["user_notes"] = user_role.written_notes + 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) + var/list/player_info = list() + player_info["name"] = role.body.real_name + player_info["ref"] = REF(role) + player_info["alive"] = role.game_status == MAFIA_ALIVE + player_info["possible_actions"] = list() + + if(user_role) //not observer + for(var/datum/mafia_ability/action as anything in user_role.role_unique_actions) + if(action.validate_action_target(src, potential_target = role, silent = TRUE)) + player_info["possible_actions"] += list(list("name" = action, "ref" = REF(action))) + + data["players"] += list(player_info) + + return data + +/datum/mafia_controller/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/mafia), + ) + +/datum/mafia_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + var/datum/mafia_role/user_role = get_role_player(usr, ui) + var/obj/item/modular_computer/modpc = ui.src_object + if(!istype(modpc)) + modpc = null + //Admin actions + if(ui.user.client.holder) + switch(action) + if("new_game") + if(phase == MAFIA_PHASE_SETUP) + return + basic_setup() + if("nuke") + qdel(src) + if("next_phase") + if(phase == MAFIA_PHASE_SETUP) + return + var/datum/timedevent/timer = SStimer.timer_id_dict[next_phase_timer] + if(!timer.spent) + var/datum/callback/tc = timer.callBack + deltimer(next_phase_timer) + tc.InvokeAsync() + return TRUE + if("players_home") + var/list/failed = list() + for(var/datum/mafia_role/player in all_roles) + if(!player.body) + failed += player + continue + 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/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 + var/done = FALSE + + while(!done) + to_chat(usr, "You have a total player count of [assoc_value_sum(debug_setup)] in this setup.") + var/chosen_role_name = tgui_input_list(usr, "Select a role!", "Custom Setup Creation", rolelist_dict) + if(!chosen_role_name) + return + switch(chosen_role_name) + if("CANCEL") + done = TRUE + return + if("FINISH") + done = TRUE + break + else + var/found_path = rolelist_dict[chosen_role_name] + var/role_count = tgui_input_number(usr, "How many? Zero to cancel.", "Custom Setup Creation", 0, 12) + if(role_count > 0) + debug_setup[found_path] = role_count + custom_setup = debug_setup + early_start = TRUE + try_autostart()//don't worry, this fails if there's a game in progress + if("cancel_setup") + custom_setup = list() + if("start_now") + forced_setup() + + switch(action) //both living and dead + if("mf_lookup") + var/role_lookup = params["role_name"] + var/datum/mafia_role/helper + for(var/datum/mafia_role/role as anything in all_roles) + if(role_lookup == role.name) + helper = role + break + helper.show_help(usr) + + if(!user_role)//just the dead + switch(action) + if("mf_signup") + if(signup_mafia(usr, ui.user.client, modpc)) + return TRUE + if("vote_to_start") + 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(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 + GLOB.pda_mafia_signup) / 2), round(MAFIA_MIN_PLAYER_COUNT / 2))]).")) + if(check_start_votes()) //See if we have enough votes to start + forced_setup() + else + 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 + GLOB.pda_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) + return + + //User actions (just living) + switch(action) + if("change_notes") + if(user_role.game_status == MAFIA_DEAD) + return TRUE + 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) + return TRUE + if(phase == MAFIA_PHASE_NIGHT) + return TRUE + if(!COOLDOWN_FINISHED(user_role, note_chat_sending_cooldown)) + return FALSE + COOLDOWN_START(user_role, note_chat_sending_cooldown, MAFIA_NOTE_SENDING_COOLDOWN) + user_role.body.say("[user_role.written_notes]", forced = "mafia notes sending") + return TRUE + if("perform_action") + var/datum/mafia_role/target = locate(params["target"]) in all_roles + if(!istype(target)) + return + var/datum/mafia_ability/used_action = locate(params["action_ref"]) in user_role.role_unique_actions + if(!used_action) + return + switch(phase) + if(MAFIA_PHASE_DAY, MAFIA_PHASE_VOTING) + used_action.using_ability = TRUE + used_action.perform_action_target(src, target) + if(MAFIA_PHASE_NIGHT) + used_action.set_target(src, target) + return TRUE + + if(user_role != on_trial) + switch(action) + if("vote_abstain") + if(phase != MAFIA_PHASE_JUDGEMENT || (user_role in judgement_abstain_votes)) + return + 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 + 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 + 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 + +/datum/mafia_controller/ui_state(mob/user) + return GLOB.always_state + +/datum/mafia_controller/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, null) + if(!ui) + ui = new(user, src, "MafiaPanel") + ui.open() diff --git a/code/modules/mafia/map_pieces.dm b/code/modules/mafia/map_pieces.dm index 0d27d6cd1b5..f3a6baced78 100644 --- a/code/modules/mafia/map_pieces.dm +++ b/code/modules/mafia/map_pieces.dm @@ -28,48 +28,65 @@ /datum/map_template/mafia should_place_on_top = FALSE + ///The map suffix to put onto the mappath. + var/map_suffix ///A brief background tidbit var/description = "" ///What costume will this map force players to start with? var/custom_outfit +/datum/map_template/mafia/New(path = null, rename = null, cache = FALSE) + path = "_maps/map_files/Mafia/" + map_suffix + return ..() + +//we only have one map in unit tests for consistency. +#ifdef UNIT_TESTS +/datum/map_template/mafia/unit_test + name = "Mafia Unit Test" + description = "A map designed specifically for Unit Testing to ensure the game runs properly." + map_suffix = "mafia_unit_test.dmm" + +#else + /datum/map_template/mafia/summerball name = "Summerball 2020" description = "The original, the OG. The 2020 Summer ball was where mafia came from, with this map." - mappath = "_maps/map_files/Mafia/mafia_ball.dmm" - -/datum/map_template/mafia/syndicate - name = "Syndicate Megastation" - description = "Yes, it's a very confusing day at the Megastation. Will the syndicate conflict resolution operatives succeed?" - mappath = "_maps/map_files/Mafia/mafia_syndie.dmm" - custom_outfit = /datum/outfit/mafia/syndie - -/datum/map_template/mafia/lavaland - name = "Lavaland Excursion" - description = "The station has no idea what's going down on lavaland right now, we got changelings... traitors, and worst of all... lawyers roleblocking you every night." - mappath = "_maps/map_files/Mafia/mafia_lavaland.dmm" - custom_outfit = /datum/outfit/mafia/lavaland + map_suffix = "mafia_ball.dmm" /datum/map_template/mafia/ufo name = "Alien Mothership" description = "The haunted ghost UFO tour has gone south and now it's up to our fine townies and scare seekers to kill the actual real alien changelings..." - mappath = "_maps/map_files/Mafia/mafia_ayylmao.dmm" + map_suffix = "mafia_ayylmao.dmm" custom_outfit = /datum/outfit/mafia/abductee /datum/map_template/mafia/spider_clan name = "Spider Clan Kidnapping" description = "New and improved spider clan kidnappings are a lot less boring and have a lot more lynching. Damn westaboos!" - mappath = "_maps/map_files/Mafia/mafia_spiderclan.dmm" + map_suffix = "mafia_spiderclan.dmm" custom_outfit = /datum/outfit/mafia/ninja -/datum/map_template/mafia/snowy - name = "Snowdin" - description = "Based off of the icy moon map of the same name, the guy who reworked it did a good enough job to recieve a derivative piece of work based on it. Cool!" - mappath = "_maps/map_files/Mafia/mafia_snow.dmm" - custom_outfit = /datum/outfit/mafia/snowy - /datum/map_template/mafia/gothic name = "Vampire's Castle" description = "Vampires and changelings clash to find out who's the superior bloodsucking monster in this creepy castle map." - mappath = "_maps/map_files/Mafia/mafia_gothic.dmm" + map_suffix = "mafia_gothic.dmm" custom_outfit = /datum/outfit/mafia/gothic + +/datum/map_template/mafia/syndicate + name = "Syndicate Megastation" + description = "Yes, it's a very confusing day at the Megastation. Will the syndicate conflict resolution operatives succeed?" + map_suffix = "mafia_syndie.dmm" + custom_outfit = /datum/outfit/mafia/syndie + +/datum/map_template/mafia/snowy + name = "Snowdin" + description = "Based off of the icy moon map of the same name, the guy who reworked it did a good enough job to recieve a derivative piece of work based on it. Cool!" + map_suffix = "mafia_snow.dmm" + custom_outfit = /datum/outfit/mafia/snowy + +/datum/map_template/mafia/lavaland + name = "Lavaland Excursion" + description = "The station has no idea what's going down on lavaland right now, we got changelings... traitors, and worst of all... lawyers roleblocking you every night." + map_suffix = "mafia_lavaland.dmm" + custom_outfit = /datum/outfit/mafia/lavaland + +#endif diff --git a/code/modules/mafia/roles/roles.dm b/code/modules/mafia/roles/roles.dm index efe0d25c5b9..f301a8ac02a 100644 --- a/code/modules/mafia/roles/roles.dm +++ b/code/modules/mafia/roles/roles.dm @@ -27,6 +27,9 @@ var/mob/living/carbon/human/body var/obj/effect/landmark/mafia/assigned_landmark + ///The Mafia innate action panel that allows players to view the game's state. + var/datum/action/innate/mafia_panel/mafia_panel + ///how many votes submitted when you vote. used in voting and deciding victory. var/vote_power = 1 ///what they get equipped with when they are revealed @@ -49,6 +52,7 @@ /datum/mafia_role/New(datum/mafia_controller/game) . = ..() + mafia_panel = new(null, game) for(var/datum/mafia_ability/abilities as anything in role_unique_actions + /datum/mafia_ability/voting) role_unique_actions += new abilities(game, src) role_unique_actions -= abilities @@ -56,14 +60,21 @@ /datum/mafia_role/Destroy(force, ...) UnregisterSignal(body, COMSIG_MOB_SAY) QDEL_NULL(mafia_alert) - QDEL_NULL(body) + QDEL_NULL(mafia_panel) QDEL_LIST(role_unique_actions) - role_messages = null + //we null these instead of qdel because Mafia controller's mapdeleter deletes it all. + assigned_landmark = null + body = null + role_messages.Cut() return ..() /datum/mafia_role/proc/register_body(mob/living/carbon/human/new_body) + if(body) + UnregisterSignal(new_body, COMSIG_MOB_SAY) + mafia_panel.Remove(body) body = new_body RegisterSignal(new_body, COMSIG_MOB_SAY, PROC_REF(handle_speech)) + mafia_panel.Grant(new_body) /** * send_message_to_player @@ -118,14 +129,15 @@ * * Does not count as visiting, see visit proc. */ -/datum/mafia_role/proc/kill(datum/mafia_controller/game, datum/mafia_role/attacker, lynch=FALSE) +/datum/mafia_role/proc/kill(datum/mafia_controller/game, datum/mafia_role/attacker, lynch = FALSE) + if(game_status == MAFIA_DEAD) + return FALSE if(attacker && (attacker.role_flags & ROLE_ROLEBLOCKED)) return FALSE if(SEND_SIGNAL(src, COMSIG_MAFIA_ON_KILL, game, attacker, lynch) & MAFIA_PREVENT_KILL) return FALSE - if(game_status != MAFIA_DEAD) - game_status = MAFIA_DEAD - body.death() + game_status = MAFIA_DEAD + body.death() if(lynch) reveal_role(game, verbose = TRUE) game.living_roles -= src diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index 7917da4d542..47dca7b438e 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -29,6 +29,8 @@ var/list/ceiling_baseturfs = list() /datum/map_template/New(path = null, rename = null, cache = FALSE) + SHOULD_CALL_PARENT(TRUE) + . = ..() if(path) mappath = path if(mappath) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index e5ddcf1f0ae..ec8f0f629f1 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -28,7 +28,7 @@ if(client) stack_trace("Mob with client has been deleted.") else if(ckey) - stack_trace("Mob without client but with associated ckey has been deleted.") + stack_trace("Mob without client but with associated ckey, [ckey], has been deleted.") remove_from_mob_list() remove_from_dead_mob_list() @@ -46,7 +46,7 @@ qdel(hud_used) QDEL_LIST(client_colours) - ghostize() //False, since we're deleting it currently + ghostize(can_reenter_corpse = FALSE) //False, since we're deleting it currently if(mind?.current == src) //Let's just be safe yeah? This will occasionally be cleared, but not always. Can't do it with ghostize without changing behavior mind.set_current(null) diff --git a/code/modules/modular_computers/computers/item/laptop_presets.dm b/code/modules/modular_computers/computers/item/laptop_presets.dm index 1eebf9f2387..4239a33dfd7 100644 --- a/code/modules/modular_computers/computers/item/laptop_presets.dm +++ b/code/modules/modular_computers/computers/item/laptop_presets.dm @@ -3,3 +3,9 @@ starting_programs = list( /datum/computer_file/program/chatclient, ) + +//Used for Mafia testing purposes. +/obj/item/modular_computer/laptop/preset/mafia + starting_programs = list( + /datum/computer_file/program/mafia, + ) diff --git a/code/modules/modular_computers/file_system/programs/mafia_ntos.dm b/code/modules/modular_computers/file_system/programs/mafia_ntos.dm index 7bd5b81a240..bbcdd39d32c 100644 --- a/code/modules/modular_computers/file_system/programs/mafia_ntos.dm +++ b/code/modules/modular_computers/file_system/programs/mafia_ntos.dm @@ -16,11 +16,11 @@ /datum/computer_file/program/mafia/Destroy(force) var/datum/mafia_controller/game = GLOB.mafia_game if(!game) - return + return ..() UnregisterSignal(game, COMSIG_MAFIA_GAME_END) - var/datum/mafia_role/pda_role = game.player_role_lookup[computer] + var/datum/mafia_role/pda_role = game.get_role_player(computer) if(!pda_role) - return + 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 ..() @@ -60,7 +60,7 @@ SIGNAL_HANDLER RegisterSignal(game, COMSIG_MAFIA_GAME_END, PROC_REF(on_game_end)) ui_header = "mafia.gif" - if(game.player_role_lookup[computer]) + if(game.get_role_player(computer)) alert_pending = TRUE computer.alert_call(src, "Mafia game started!") diff --git a/code/modules/procedural_mapping/mapGenerator.dm b/code/modules/procedural_mapping/mapGenerator.dm index 4a79ad4c305..8408e1d97b7 100644 --- a/code/modules/procedural_mapping/mapGenerator.dm +++ b/code/modules/procedural_mapping/mapGenerator.dm @@ -1,10 +1,12 @@ +///This type is responsible for any map generation behavior that is done in areas, override this to allow for +///area-specific map generation. This generation is ran by areas in initialize. /datum/map_generator - //Map information - var/list/map = list() + ///Map information, such as the start and end turfs of the map generation. + var/list/turf/map = list() - //mapGeneratorModule information - var/list/modules = list() + ///The map generator modules that we will generate and sync to. + var/list/datum/map_generator_module/modules = list() var/buildmode_name = "Undocumented" @@ -14,6 +16,18 @@ buildmode_name = copytext_char("[type]", 20) // / d a t u m / m a p g e n e r a t o r / = 20 characters. initialiseModules() +/datum/map_generator/Destroy(force, ...) + . = ..() + QDEL_LIST(modules) + +///This proc will be ran by areas on Initialize, and provides the areas turfs as argument to allow for generation. +/datum/map_generator/proc/generate_terrain(list/turfs, area/generate_in) + return + +/// Populate terrain with flora, fauna, features and basically everything that isn't a turf. +/datum/map_generator/proc/populate_terrain(list/turfs, area/generate_in) + return + //Defines the region the map represents, sets map //Returns the map /datum/map_generator/proc/defineRegion(turf/Start, turf/End, replace = 0) @@ -22,7 +36,7 @@ if(replace) undefineRegion() - map |= block(Start,End) + map |= block(Start, End) return map @@ -56,7 +70,7 @@ theRadius = max(radius/max((2*abs(sphereMagic-i)),1),1) - map |= circle_range(locate(centerX,centerY,i),theRadius) + map |= circle_range(locate(centerX, centerY, i),theRadius) return map @@ -87,7 +101,7 @@ syncModules() if(!modules || !modules.len) return - for(var/datum/map_generator_module/mod in modules) + for(var/datum/map_generator_module/mod as anything in modules) INVOKE_ASYNC(mod, TYPE_PROC_REF(/datum/map_generator_module, generate)) @@ -98,7 +112,7 @@ syncModules() if(!modules || !modules.len) return - for(var/datum/map_generator_module/mod in modules) + for(var/datum/map_generator_module/mod as anything in modules) INVOKE_ASYNC(mod, TYPE_PROC_REF(/datum/map_generator_module, place), T) @@ -113,7 +127,7 @@ //Sync mapGeneratorModule(s) to mapGenerator /datum/map_generator/proc/syncModules() - for(var/datum/map_generator_module/mod in modules) + for(var/datum/map_generator_module/mod as anything in modules) mod.sync(src) @@ -127,12 +141,12 @@ set category = "Debug" var/datum/map_generator/nature/N = new() - var/startInput = input(usr,"Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null + var/startInput = input(usr, "Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null if (isnull(startInput)) return - var/endInput = input(usr,"End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text|null + var/endInput = input(usr, "End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text|null if (isnull(endInput)) return @@ -158,9 +172,18 @@ to_chat(src, "End Coords: [endCoords[1]] - [endCoords[2]] - [endCoords[3]]") return - var/list/clusters = list("None"=CLUSTER_CHECK_NONE,"All"=CLUSTER_CHECK_ALL,"Sames"=CLUSTER_CHECK_SAMES,"Differents"=CLUSTER_CHECK_DIFFERENTS, \ - "Same turfs"=CLUSTER_CHECK_SAME_TURFS, "Same atoms"=CLUSTER_CHECK_SAME_ATOMS, "Different turfs"=CLUSTER_CHECK_DIFFERENT_TURFS, \ - "Different atoms"=CLUSTER_CHECK_DIFFERENT_ATOMS, "All turfs"=CLUSTER_CHECK_ALL_TURFS,"All atoms"=CLUSTER_CHECK_ALL_ATOMS) + var/static/list/clusters = list( + "None" = CLUSTER_CHECK_NONE, + "All" = CLUSTER_CHECK_ALL, + "Sames" = CLUSTER_CHECK_SAMES, + "Differents" = CLUSTER_CHECK_DIFFERENTS, + "Same turfs" = CLUSTER_CHECK_SAME_TURFS, + "Same atoms" = CLUSTER_CHECK_SAME_ATOMS, + "Different turfs" = CLUSTER_CHECK_DIFFERENT_TURFS, + "Different atoms" = CLUSTER_CHECK_DIFFERENT_ATOMS, + "All turfs" = CLUSTER_CHECK_ALL_TURFS, + "All atoms" = CLUSTER_CHECK_ALL_ATOMS, + ) var/moduleClusters = input("Cluster Flags (Cancel to leave unchanged from defaults)","Map Gen Settings") as null|anything in clusters //null for default @@ -175,7 +198,7 @@ theCluster = CLUSTER_CHECK_NONE if(theCluster) - for(var/datum/map_generator_module/M in N.modules) + for(var/datum/map_generator_module/M as anything in N.modules) M.clusterCheckFlags = theCluster diff --git a/code/modules/procedural_mapping/mapGeneratorModule.dm b/code/modules/procedural_mapping/mapGeneratorModule.dm index d5742fdb85a..aa3f0f0e93c 100644 --- a/code/modules/procedural_mapping/mapGeneratorModule.dm +++ b/code/modules/procedural_mapping/mapGeneratorModule.dm @@ -8,6 +8,9 @@ var/clusterCheckFlags = CLUSTER_CHECK_SAME_ATOMS var/allowAtomsOnSpace = FALSE +/datum/map_generator_module/Destroy(force, ...) + mother = null + return ..() //Syncs the module up with its mother /datum/map_generator_module/proc/sync(datum/map_generator/mum) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 914f902baf2..db33db6572a 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -168,6 +168,7 @@ #include "load_map_security.dm" #include "lungs.dm" #include "machine_disassembly.dm" +#include "mafia.dm" #include "map_landmarks.dm" #include "mapload_space_verification.dm" #include "mapping.dm" diff --git a/code/modules/unit_tests/mafia.dm b/code/modules/unit_tests/mafia.dm new file mode 100644 index 00000000000..85fa5084293 --- /dev/null +++ b/code/modules/unit_tests/mafia.dm @@ -0,0 +1,48 @@ +///Checks if a Mafia game with a Modular Computer and a Ghost will run with 'basic_setup', which is the default +///way the game is ran, without admin-intervention. +///The game should immediately end in a Town Victory due to lack of evils, but we can verify that both the PDA and the ghost +///successfully managed to get into the round. +/datum/unit_test/mafia + ///Boolean on whether the Mafia game started or not. Will Fail if it hasn't. + var/mafia_game_started = FALSE + +/datum/unit_test/mafia/Run() + RegisterSignal(SSdcs, COMSIG_MAFIA_GAME_START, PROC_REF(on_mafia_start)) + var/datum/mafia_controller/controller = GLOB.mafia_game || new() + + TEST_ASSERT(controller, "No Mafia game was found, nor was it able to be created properly.") + + //spawn human and give them a laptop. + var/mob/living/carbon/human/consistent/living_player = allocate(/mob/living/carbon/human/consistent) + var/obj/item/modular_computer/laptop/preset/mafia/modpc_player = allocate(/obj/item/modular_computer/laptop/preset/mafia) + living_player.put_in_active_hand(modpc_player, TRUE) + + //make the laptop run Mafia app. + var/datum/computer_file/program/mafia/mafia_program = locate() in modpc_player.stored_files + TEST_ASSERT(mafia_program, "Mafia program was unable to be found on [modpc_player].") + modpc_player.active_program = mafia_program + + //Spawn a ghost and make them eligible to use the Mafia UI (just to be safe). + var/mob/dead/observer/ghost_player = allocate(/mob/dead/observer) + var/datum/client_interface/mock_client = new() + ghost_player.mock_client = mock_client + mock_client.mob = ghost_player + ADD_TRAIT(ghost_player, TRAIT_PRESERVE_UI_WITHOUT_CLIENT, TRAIT_SOURCE_UNIT_TESTS) + + //First make the human sign up for Mafia, then the ghost, then we'll auto-start it. + controller.signup_mafia(living_player, modpc = modpc_player) + controller.signup_mafia(ghost_player, ghost_client = mock_client) + + controller.basic_setup() + + TEST_ASSERT(mafia_game_started, "Mafia game did not start despite basic_setup being called.") + TEST_ASSERT_NOTNULL(controller.player_role_lookup[modpc_player], "The Modular Computer was unable to join a game of Mafia.") + TEST_ASSERT_NOTNULL(controller.player_role_lookup[mock_client.ckey], "The Mock client wasn't put into a game of Mafia.") + + mock_client.mob = null + + qdel(controller) + +/datum/unit_test/mafia/proc/on_mafia_start(datum/controller/subsystem/processing/dcs/source, datum/mafia_controller/game) + SIGNAL_HANDLER + mafia_game_started = TRUE diff --git a/tgstation.dme b/tgstation.dme index f1784fcb4f9..24f2dd0e0e7 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1575,7 +1575,6 @@ #include "code\datums\looping_sounds\music.dm" #include "code\datums\looping_sounds\vents.dm" #include "code\datums\looping_sounds\weather.dm" -#include "code\datums\mapgen\_MapGenerator.dm" #include "code\datums\mapgen\CaveGenerator.dm" #include "code\datums\mapgen\JungleGenerator.dm" #include "code\datums\mapgen\biomes\_biome.dm" @@ -4282,6 +4281,7 @@ #include "code\modules\logging\categories\log_category_uplink.dm" #include "code\modules\mafia\_defines.dm" #include "code\modules\mafia\controller.dm" +#include "code\modules\mafia\controller_ui.dm" #include "code\modules\mafia\map_pieces.dm" #include "code\modules\mafia\outfits.dm" #include "code\modules\mafia\abilities\abilities.dm"