From a4040ace26ef5f333e206e68e45c092e8d5c02fa Mon Sep 17 00:00:00 2001 From: Letter N <24603524+LetterN@users.noreply.github.com> Date: Mon, 10 Aug 2020 10:50:07 +0800 Subject: [PATCH] hewwo have you tried to work? --- code/modules/asset_cache/asset_list_items.dm | 6 + code/modules/mafia/_defines.dm | 2 + code/modules/mafia/controller.dm | 136 ++++- code/modules/mafia/roles.dm | 46 +- code/modules/mob/dead/observer/observer.dm | 16 + icons/obj/mafia.dmi | Bin 668 -> 13272 bytes tgui/packages/tgui/assets/bg-neutral.svg | 3 + tgui/packages/tgui/index.js | 1 + tgui/packages/tgui/interfaces/MafiaPanel.js | 527 ++++++++++++++---- tgui/packages/tgui/styles/themes/neutral.scss | 43 ++ 10 files changed, 634 insertions(+), 146 deletions(-) create mode 100644 tgui/packages/tgui/assets/bg-neutral.svg create mode 100644 tgui/packages/tgui/styles/themes/neutral.scss diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index d4ab7b5648..a8b4c93764 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -388,3 +388,9 @@ Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal") ..() +/datum/asset/spritesheet/mafia + name = "mafia" + +/datum/asset/spritesheet/mafia/register() + InsertAll("", 'icons/obj/mafia.dmi') + ..() diff --git a/code/modules/mafia/_defines.dm b/code/modules/mafia/_defines.dm index b862ce63c5..3833d5aefe 100644 --- a/code/modules/mafia/_defines.dm +++ b/code/modules/mafia/_defines.dm @@ -32,6 +32,8 @@ GLOBAL_LIST_EMPTY(mafia_signup) //the current global mafia game running. GLOBAL_VAR(mafia_game) +/// 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) GLOBAL_LIST_INIT(mafia_setups,generate_mafia_setups()) diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm index 172f9dca50..8c4006ef90 100644 --- a/code/modules/mafia/controller.dm +++ b/code/modules/mafia/controller.dm @@ -6,6 +6,8 @@ * It is first created when the first ghost signs up to play. */ /datum/mafia_controller + ///list of observers that should get game updates. + var/list/spectators = list() ///all roles in the game, dead or alive. check their game status if you only want living or dead. var/list/all_roles = list() ///exists to speed up role retrieval, it's a dict. player_role_lookup[player ckey] will give you the role they play @@ -48,7 +50,8 @@ ///group voting on one person, like putting people to trial or choosing who to kill as mafia var/list/votes = list() - ///and these (judgement_innocent_votes and judgement_guilty_votes) are the judgement phase votes, aka people sorting themselves into guilty and innocent lists. whichever has more wins! + ///and these (judgement_innocent_votes, judgement_abstain_votes and judgement_guilty_votes) are the judgement phase votes, aka people sorting themselves into guilty and innocent, and "eh, i don't really care" lists. whichever has more inno or guilty wins! + var/list/judgement_abstain_votes = list() var/list/judgement_innocent_votes = list() var/list/judgement_guilty_votes = list() ///current role on trial for the judgement phase, will die if guilty is greater than innocent @@ -129,7 +132,7 @@ var/team_suffix = team ? "([uppertext(team)] CHAT)" : "" for(var/M in GLOB.dead_mob_list) var/mob/spectator = M - if(spectator.ckey in GLOB.mafia_signup || player_role_lookup[spectator.mind.current] != null) //was in current game, or is signed up + if(spectator.ckey in spectators) //was in current game, or spectatin' (won't send to living) var/link = FOLLOW_LINK(M, town_center_landmark) to_chat(M, "[link] MAFIA: [msg] [team_suffix]") @@ -190,8 +193,19 @@ */ /datum/mafia_controller/proc/check_trial(verbose = TRUE) 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) + // loser.body.client?.give_award(/datum/award/achievement/mafia/universally_hated, loser.body) send_message("[loser.body.real_name] wins the day vote, Listen to their defense and vote \"INNOCENT\" or \"GUILTY\"!") + //refresh the lists + judgement_abstain_votes = list() + judgement_innocent_votes = list() + judgement_guilty_votes = list() + for(var/i in all_roles) + var/datum/mafia_role/abstainee = i + if(abstainee.game_status == MAFIA_ALIVE && abstainee != loser) + judgement_abstain_votes += abstainee on_trial = loser on_trial.body.forceMove(get_turf(town_center_landmark)) phase = MAFIA_PHASE_JUDGEMENT @@ -215,8 +229,11 @@ for(var/i in judgement_innocent_votes) var/datum/mafia_role/role = i send_message("[role.body.real_name] voted innocent.") - for(var/ii in judgement_guilty_votes) + for(var/ii in judgement_abstain_votes) var/datum/mafia_role/role = ii + send_message("[role.body.real_name] abstained.") + for(var/iii in judgement_guilty_votes) + var/datum/mafia_role/role = iii send_message("[role.body.real_name] voted guilty.") if(judgement_guilty_votes.len > judgement_innocent_votes.len) //strictly need majority guilty to lynch send_message("Guilty wins majority, [on_trial.body.real_name] has been lynched.") @@ -225,9 +242,6 @@ else send_message("Innocent wins majority, [on_trial.body.real_name] has been spared.") on_trial.body.forceMove(get_turf(on_trial.assigned_landmark)) - //by now clowns should have killed someone in guilty list, clear this out - judgement_innocent_votes = list() - judgement_guilty_votes = list() on_trial = null //day votes are already cleared, so this will skip the trial and check victory/lockdown/whatever else next_phase_timer = addtimer(CALLBACK(src, .proc/check_trial, FALSE),judgement_lynch_period,TIMER_STOPPABLE)// small pause to see the guy dead, no verbosity since we already did this @@ -320,10 +334,8 @@ /** * Cleans up the game, resetting variables back to the beginning and removing the map with the generator. */ -/datum/mafia_controller/proc/end_game() - +/datum/mafia_controller/proc/end_game( map_deleter.generate() //remove the map, it will be loaded at the start of the next one - QDEL_LIST(all_roles) turn = 0 votes = list() @@ -481,7 +493,7 @@ if(phase != MAFIA_PHASE_VOTING) return var/v = get_vote_count(player_role_lookup[source],"Day") - var/mutable_appearance/MA = mutable_appearance('icons/obj/mafia.dmi',"vote_[v]") + var/mutable_appearance/MA = mutable_appearance('icons/obj/mafia.dmi',"vote_[v > 12 ? "over_12" : v]") overlay_list += MA /** @@ -528,13 +540,26 @@ .["judgement_phase"] = FALSE var/datum/mafia_role/user_role = player_role_lookup[user] if(user_role) - .["roleinfo"] = list("role" = user_role.name,"desc" = user_role.desc, "action_log" = user_role.role_notes) + .["roleinfo"] = list("role" = user_role.name,"desc" = user_role.desc, "action_log" = user_role.role_notes, "hud_icon" = user_role.hud_icon, "revealed_icon" = user_role.revealed_icon) var/actions = list() for(var/action in user_role.actions) if(user_role.validate_action_target(src,action,null)) actions += action .["actions"] = actions .["role_theme"] = user_role.special_theme + else + var/list/lobby_data = list() + for(var/key in GLOB.mafia_signup + GLOB.mafia_bad_signup) + var/list/lobby_member = list() + lobby_member["name"] = key + lobby_member["status"] = "Ready" + if(key in GLOB.mafia_bad_signup) + lobby_member["status"] = "Disconnected" + lobby_member["spectating"] = "Ghost" + if(key in spectators) + lobby_member["spectating"] = "Spectator" + lobby_data += list(lobby_member) + .["lobbydata"] = lobby_data var/list/player_data = list() for(var/datum/mafia_role/R in all_roles) var/list/player_info = list() @@ -561,6 +586,11 @@ //Not sure on this, should this info be visible .["all_roles"] = current_setup_text +/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(.) @@ -606,7 +636,31 @@ helper = role break helper.show_help(usr) - if(!user_role || user_role.game_status == MAFIA_DEAD)//ghosts, dead people? + if(!user_role)//just the dead + var/client/C = ui.user.client + switch(action) + if("mf_signup") + if(!SSticker.HasRoundStarted()) + to_chat(usr, "Wait for the round to start.") + return + if(GLOB.mafia_signup[C.ckey]) + GLOB.mafia_signup -= C.ckey + to_chat(usr, "You unregister from Mafia.") + return + else + GLOB.mafia_signup[C.ckey] = C + to_chat(usr, "You sign up for Mafia.") + if(phase == MAFIA_PHASE_SETUP) + check_signups() + try_autostart() + if("mf_spectate") + if(C.ckey in spectators) + to_chat(usr, "You will no longer get messages from the game.") + spectators -= C.ckey + else + to_chat(usr, "You will now get messages from the game.") + spectators += C.ckey + if(user_role.game_status == MAFIA_DEAD) return var/self_voting = user_role == on_trial ? TRUE : FALSE //used to block people from voting themselves innocent or guilty //User actions @@ -637,20 +691,29 @@ return user_role.handle_action(src,params["atype"],target) return TRUE - if("vote_innocent") - if(phase != MAFIA_PHASE_JUDGEMENT && !self_voting) - return - to_chat(user_role.body,"Your vote on [on_trial.body.real_name] submitted as INNOCENT!") - judgement_innocent_votes -= user_role//no double voting - judgement_guilty_votes -= user_role//no radical centrism - judgement_innocent_votes += user_role - if("vote_guilty") - if(phase != MAFIA_PHASE_JUDGEMENT && !self_voting) - return - to_chat(user_role.body,"Your vote on [on_trial.body.real_name] submitted as GUILTY!") - judgement_innocent_votes -= user_role//no radical centrism - judgement_guilty_votes -= user_role//no double voting - judgement_guilty_votes += user_role + if(user_role != on_trial) + switch(action) + 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.") + 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!") + 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!") + 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 @@ -699,7 +762,7 @@ //cuts invalid players from signups (disconnected/not a ghost) var/list/possible_keys = list() for(var/key in GLOB.mafia_signup) - if(GLOB.directory[key] && GLOB.directory[key] == GLOB.mafia_signup[key]) + if(GLOB.directory[key]) var/client/C = GLOB.directory[key] if(isobserver(C.mob)) possible_keys += key @@ -739,6 +802,25 @@ if(GLOB.mafia_signup.len >= min_players)//enough people to try and make something basic_setup() +/** + * Filters inactive player into a different list until they reconnect, and removes players who are no longer ghosts. + * + * 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() + 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 + GLOB.mafia_signup += bad_key + for(var/key in GLOB.mafia_signup) + var/client/C = GLOB.directory[key] + if(!C)//vice versa but in a variable we use later + GLOB.mafia_signup -= key + GLOB.mafia_bad_signup += key + if(!isobserver(C.mob)) + //they are back to playing the game, remove them from the signups + GLOB.mafia_signup -= key + /datum/action/innate/mafia_panel name = "Mafia Panel" desc = "Use this to play." diff --git a/code/modules/mafia/roles.dm b/code/modules/mafia/roles.dm index 394d121005..914cbb0bd3 100644 --- a/code/modules/mafia/roles.dm +++ b/code/modules/mafia/roles.dm @@ -19,7 +19,12 @@ var/game_status = MAFIA_ALIVE - var/special_theme //set this to something cool for antagonists and their window will look different + ///icon state in the mafia dmi of the hud of the role, used in the mafia ui + var/hud_icon = "hudassistant" + ///icon state in the mafia dmi of the hud of the role, used in the mafia ui + var/revealed_icon = "assistant" + ///set this to something cool for antagonists and their window will look different + var/special_theme var/list/role_notes = list() @@ -34,6 +39,8 @@ body.death() if(lynch) reveal_role(game, verbose = TRUE) + if(!(player_key in game.spectators)) //people who played will want to see the end of the game more often than not + game.spectators += player_key return TRUE /datum/mafia_role/Destroy(force, ...) @@ -108,6 +115,9 @@ desc = "You can investigate a single person each night to learn their team." revealed_outfit = /datum/outfit/mafia/detective + hud_icon = "huddetective" + revealed_icon = "detective" + targeted_actions = list("Investigate") var/datum/mafia_role/current_investigation @@ -152,7 +162,8 @@ name = "Medical Doctor" desc = "You can protect a single person each night from killing." revealed_outfit = /datum/outfit/mafia/md // /mafia <- outfit must be readded (just make a new mafia outfits file for all of these) - + hud_icon = "hudmedicaldoctor" + revealed_icon = "medicaldoctor" targeted_actions = list("Protect") var/datum/mafia_role/current_protected @@ -194,7 +205,8 @@ name = "Chaplain" desc = "You can communicate with spirits of the dead each night to discover dead crewmember roles." revealed_outfit = /datum/outfit/mafia/chaplain - + hud_icon = "hudchaplain" + revealed_icon = "chaplain" targeted_actions = list("Pray") var/current_target @@ -222,8 +234,9 @@ /datum/mafia_role/lawyer name = "Lawyer" desc = "You can choose a person during the day to provide extensive legal advice to during the night, preventing night actions." - revealed_outfit = /datum/outfit/mafia/lawyer + hud_icon = "hudlawyer" + revealed_icon = "lawyer" targeted_actions = list("Advise") var/datum/mafia_role/current_target @@ -278,6 +291,9 @@ desc = "You can visit someone ONCE PER GAME to reveal their true role in the morning!" revealed_outfit = /datum/outfit/mafia/psychologist + hud_icon = "hudpsychologist" + revealed_icon = "psychologist" + targeted_actions = list("Reveal") var/datum/mafia_role/current_target var/can_use = TRUE @@ -313,6 +329,8 @@ desc = "You're a member of the changeling hive. Use ':j' talk prefix to talk to your fellow lings." team = MAFIA_TEAM_MAFIA revealed_outfit = /datum/outfit/mafia/changeling + hud_icon = "hudchangeling" + revealed_icon = "changeling" special_theme = "syndicate" win_condition = "become majority over the town and no solo killing role can stop them." @@ -332,7 +350,10 @@ team = MAFIA_TEAM_SOLO targeted_actions = list("Night Kill") revealed_outfit = /datum/outfit/mafia/traitor - special_theme = "syndicate" + + hud_icon = "hudtraitor" + revealed_icon = "traitor" + special_theme = "neutral" var/datum/mafia_role/current_victim @@ -384,6 +405,9 @@ var/protection_status = FUGITIVE_NOT_PRESERVING solo_counts_as_town = TRUE //should not count towards mafia victory, they should have the option to work with town revealed_outfit = /datum/outfit/mafia/fugitive + special_theme = "neutral" + hud_icon = "hudfugitive" + revealed_icon = "fugitive" /datum/mafia_role/fugitive/New(datum/mafia_controller/game) . = ..() @@ -434,7 +458,9 @@ win_condition = "lynch their obsession." team = MAFIA_TEAM_SOLO revealed_outfit = /datum/outfit/mafia/obsessed // /mafia <- outfit must be readded (just make a new mafia outfits file for all of these) - + special_theme = "neutral" + hud_icon = "hudobsessed" + revealed_icon = "obsessed" solo_counts_as_town = TRUE //after winning or whatever, can side with whoever. they've already done their objective! var/datum/mafia_role/obsession var/lynched_target = FALSE @@ -470,10 +496,14 @@ /datum/mafia_role/clown name = "Clown" - desc = "If you are lynched you take down one of your voters with you and win. HONK!" + desc = "If you are lynched you take down one of your voters (guilty or abstain) with you and win. HONK!" win_condition = "get themselves lynched!" revealed_outfit = /datum/outfit/mafia/clown + solo_counts_as_town = TRUE team = MAFIA_TEAM_SOLO + special_theme = "neutral" + hud_icon = "hudclown" + revealed_icon = "clown" /datum/mafia_role/clown/New(datum/mafia_controller/game) . = ..() @@ -481,7 +511,7 @@ /datum/mafia_role/clown/proc/prank(datum/source,datum/mafia_controller/game,lynch) if(lynch) - var/datum/mafia_role/victim = pick(game.judgement_guilty_votes) + var/datum/mafia_role/victim = pick(game.judgement_guilty_votes + game.judgement_abstain_votes) game.send_message("[body.real_name] WAS A CLOWN! HONK! They take down [victim.body.real_name] with their last prank.") game.send_message("!! CLOWN VICTORY !!") victim.kill(game,FALSE) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index bb39639ec1..a0df1ee938 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -905,6 +905,22 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp else to_chat(usr, "Can't become a pAI candidate while not dead!") +/mob/dead/observer/verb/mafia_game_signup() + set category = "Ghost" + set name = "Signup for Mafia" + set desc = "Sign up for a game of Mafia to pass the time while dead." + mafia_signup() +/mob/dead/observer/proc/mafia_signup() + if(!client) + return + if(!isobserver(src)) + to_chat(usr, "You must be a ghost to join mafia!") + return + var/datum/mafia_controller/game = GLOB.mafia_game //this needs to change if you want multiple mafia games up at once. + if(!game) + game = create_mafia_game("mafia") + game.ui_interact(usr) + /mob/dead/observer/CtrlShiftClick(mob/user) if(isobserver(user) && check_rights(R_SPAWN)) change_mob_type( /mob/living/carbon/human , null, null, TRUE) //always delmob, ghosts shouldn't be left lingering diff --git a/icons/obj/mafia.dmi b/icons/obj/mafia.dmi index fc0426a19fe6f4871c275acf461ebe6ff3a304bb..c44b80aba1118215bbb382cf89e3963ac5de5dfd 100644 GIT binary patch literal 13272 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

gh`%?3aKT~J5cq^avQ{IA~nNq}WI$s(d zlZZ&(#Do$Q85!9>I2hODSk%65z#^vHM7jwXiAN=7@29doj3NIZ>^>t(-O8q)hp*n6 z^QTx%qE%nH`?27^Kn8@vd_yj_P-4Tu(w`n594&NY91Vb`(|&b zOLEP|k>D4=HMpHX>;c##E~kPO&cL9^ECf0_g0){C$bO_Z_Lrh;4aWyG-$PcKl0xtX zjZi{DB47ZL03a+>Le3DN4X1{WpLq)|7?nifxkPQMjuwCn5Q2($!_VIP3r0FqUBaMq z*S`VD@S`QTS$197+1XDOM9p`M#h100_unJ3(VSf}Udk-!>CYnM-9+#XD7P0#(dOHO zq>!Z)T~fKV^avg{5clX$xA?i6EXo>I-tXMl{(FqVq-fDs;e)54wy223TeN85zwEZm zdTj3!>uqe)xL_Om^cG@b{% zaLqx98t&7n^Iz%6-R+9s-=czEssvR259&c(9d-No6rVw^6s@u~cw@S(wlJ zBw0ApD!6GANJ>gx=^sVs^1*L()%ra;^sQB&9V*jYKVDgN`kMX#D*hx-PB+CDLw~I% z6w{?Pk_~&$$5=`_y;4y&yrpl5&Of!fg~fWp7R1h;jZo6T9y&^8dJkP>5$wOy4?V6$ z-1V$sZQ~lBWu0d9s}`>3wTxQUh^I3C9e_}=&$lQqE~qc|tNe=PhVU4dY#$=;9o*9J zT-9E$v^s0a?BnC9bGw60-vy1Tq*Y>ldN_E03wut6(!(bF=O>%@*nlDi&d;Ae1Hb$F zVxbyV+wIBm75)0o*Y_ELsl2py$t7KI6R2fTAKrQZtAEt^lFZ;xa?VQ5vV&>(qch+x z{Epz#a$SgiUC$wj7?GAu{GJ08jqrxu`N@shg;ie)rsRP!z9PL=`yLxO;gA3j>wy{? zVpZbG4t$h99dT&?T?~V>Y~mr^QW$jJ5cR))Y`j1G{I zk+zbP!8-oM2MC_qUk*hHaq>9^=#;cQn0icn)5-M%r#0efrbRd*Orj z3UrTwYa`&^T*Y64{Hv!?eO*e)VVAx>Avz@ua|x5lvu&@vy9Zwzp;xZ={}we!M4E^L zQsQ@bcq;1Z0l?Xl)oV)t7BsE6^nWn=g|*X{6OUi+{g>MxC?;E;sx?iIpltV{uJE>& z-$`8Gsa);|mJysL_tjH(#p1CADz+tkHo)wLn$UdKIh{OLKHZGogCY^}`%nAuwkJW2 znyv$2dQQ%*Up4GR?f=XhZ1Ub&`rQ<_Kr@6V$0%A6>k_X1ZLJYc+*>rASFV z3JP^Kk~9&3LpB|TES|z96cCtyfjyHFJ>1tFU{AC{mvoHmxWJfnt`x%(k5cZONEQl+eI3Szof0 zy?GS(mz$;l1lR3>GuLH<00T~ge!UhviC>d_!(F~x_-)}AfdBi%(D2T05zG^3pgs~b z?rYb$Mu|~LL&NA-?r9EJ&DOI(kJYFP92z^|;^xj2NA~G-&c6SveHqmEQYirszuG5Y@;4O71JzF^Z0* z<`|OgkCW=Pr{>VwU&FO6sd67hFo*+D^%-S}*N&ptvh*rOX}afDT=T&G`X4Pn&1Oq!BkYW6!3Z2 ziRG1tr-#t6qhNy3bB{xrO!;0w{x{c2R~_`9|JpjO$?$}O|n_@wo$>h{z$zR4&eJsa(q3Na^O5JI1PPLxtzT$pM`PT6cF<+?F9B zm0$X&a`8OzrSW362msyCv450CGXg(4uf))?>AZn>b9X0IG&=$|ke`=hVPRo(9+kzFPf~<(V^SK1~BfMJYRg#+0-> zKYg;dw?}R8EK%t2o^SoJ5Y;1p=Zvsa!=^xtDQ;jv=jM66(Y^k3bVb8_6qdrhsaU+x zeY{r0nzxVY3HCr8jlv|v?j83{8K{y^R^y;Ym!!CnHB_#SF*B!{G#5)l7`l6br7`NR zPQKFYib;=&A$tQ5hMBBMB*H+R6W0W!u?c}?xN>0_n^pHpWcw9bbfeFawX2R#w7v{| zVw+*;*x;W<;biwJOe?IScB=kUlQG6rvADRi|bR<+WqAe@}K5H%&3Uoa3C3tTZcoyfe7F;dHq02TZ#a!<=_ zIX@RiBH#^98ym9tt$-D~t(fZ01BdC;^~&!*l?j+v0`pq1in|+eg+@RngNXb(M)e}4 zmB1&AAaJ70*3Z*W%I#T%zyOf`wO_Zt%^1nWz4s$FF1DD;8CVW?;0sLN-|OK$DZJ;( z`TZYyQ5eKzd+oqsspETWciqr{c#lcWnM)^f3voo6Th|*nQ)x_mW^5@7&h4H~?+Z`s z#I;FjMcv4Y@O}L0xXlE@pu&{9R{%DUgZ;?(5ov_UMJhSf>k& zqWxNDHaHAt1_md3ouctR<9Y&bX)sM_|{Rd$j_AoDbnaCCNU-)VscrLAh(l z)>|Qd)M0W2{>HTB0QaMs=W-QvSM6(4B=kh{lTV(iSY5#X)*6v+gYOQToF7Bb*`p~|qQ zMI~7F0~r2Zpb8)fkldw-KVv6G3p)E=v!jR3oX>dlr<>@mzeu=TdoLILI#oD${_NUz zRGV&3PA=LGTD^Cjf^YC0VMFCD_v-(~fArcMzRs_=Yq#4-4Gwaj9R-iHeLD!RXA7Se zF7wwZwmtnJp3P6sJFiz?BCXiEYxYVZS^1mZ`jCM(r`P+j=uXrg%CzvxleghPEbuQ! zF|{9i03Sw1N7g=fl~U-g#@Sx4zHXkRv|wc(F>WNuVF#1#$ih}_f8|QcgwbBr9g5wj zzcH>JawfO2`bLS#H@PP~%dYWkx9t34zy%Rk?rX2SJTF=bq7Va|SVR&$91|wml)pC9 z*Xv`ML6XT#flMYhBT=90Et&YYfUnek(Ja9jc<<1R1_v#{6mBRtpAcSjB^gh=|fd6-tBTqRUE}StL!-PF@;Hb(Ycn zj0|8Uw2uGY#mB~$u#Hc78m~O>>y|;ygOY^YUgnP4!2VoS%lgfH53q+S6FOK#|8O<` z;)_CA##GRT5_#UmLL=}Db+}LhZ|x*NwHdJ zNfCMogf?wc7w@508j5P=OLu>a9f_&|+6@c_h3CZUoRYwO?crw2S8_yh^R$=RbD z@e(*OVnvNIoKn5oPyWZMljr8znZm%ix$UIbVh_6`3F8^ECSC%jJA?K_-;WlIKAtZp zmWAW130YzTH3)JFw&`ifPV(Oy#xbRNpgJqG`Kidxg^Vcs<-pf{&DjO8>V#wsaKHRE zhuzKt1XBHvasqfSPUWida;FDTHxqW{49sk|N6Ro|WZ>Xt{^O2Y(7k^?&P>2o8`t(U z$|lb}8F1V)KvLoYDB7`K?5D2{`Y3M$3WcaVS&~$S(J-4Z+1poN{@Qv!r2`z;6!>EJ zhRECd+t-QG`JUxZ+9*Wn6t@$ESFqt>zldgcudS-RXhcLE+}!zB2_#(c`*3h@wIBut z1~#K}rB|yB*2x3(^8kw(cwC{@s7`-3n09|3QL}qgzBJ_a07HCkZwSzt%ozcGu>+Eo LRFbF^`{MsU$GWQs literal 668 zcmV;N0%QG&P)iS! zBsJbpiHkEOv#1y-V93RpR+N~V3SpxvGa^ozF>%UFh*M@toH8@wl$jH!%z`*&mc%JD zG$5$1I5R!3w1A+pr2NF96kMv56rloXjZiY`T3N}cUaHEtEYq&1DHOrq7UYgNB(u<4r#B^(I&r1OmGf>P9TjU#*aWk zOrzT%2?0YVf`}dIZj$#NwnB4OT?KMhwD6AG{(Nh6EyAO7j=fs>&CJ z9U&F^9U&H`PNSxK6t^w za&A<8@VVp$K-nCJM2babTp?}O8 z*{OpJhAL1GP!YUl4zw}}!rTL%1!f+cEAyL5EHDSYxnpJS0sN`$Tc(+398Hbf10)Dp znWr0453t}$`5elBO9(c1N})MSrlZQ!)br=U-^&;8W$>EcASp-y0000

- {!!roleinfo && ( - - - + width={650} // 414 or 415 / 444 or 445 + height={293 + playerAddedHeight}> + + {!roleinfo && ( + +
+ }> + + + The lobby currently has {readyGhosts.length} + /12 valid players signed up. + + + {!!lobbydata && lobbydata.map(lobbyist => ( + + + + {lobbyist.name} + + + STATUS: + + +
+ + {lobbyist.status} {lobbyist.spectating} + +
+
+
+
+ ))} +
+
+
+ )} + {!!roleinfo && ( +
- You are a {roleinfo.role} + {!!admin_controls && ( +
+ + + + + + +
+ )} {!!actions && actions.map(action => ( @@ -49,116 +147,323 @@ export const MafiaPanel = (props, context) => { ))} - {!!admin_controls && ( + {!!roleinfo && (
- THESE ARE DEBUG, THEY WILL BREAK THE GAME, DO NOT TOUCH
- Also because an admin did it: do not gib/delete/etc - anyone! It will runtime the game to death!
- - - -
- -
- )} -
- - {!!players && players.map(player => ( - - {!player.alive && (DEAD)} - {player.votes !== undefined && !!player.alive - && (Votes : {player.votes} )} - { - !!player.actions && player.actions.map(action => { - return ( - ); }) - } - ) - )} - -
- {!!judgement_phase && ( -
+ title="Judgement" + buttons={ + - Use these buttons to vote the accused innocent or guilty! + disabled={!judgement_phase} + onClick={() => act("vote_innocent")} /> + {!judgement_phase && ( + + There is nobody on trial at the moment. + + )} + {!!judgement_phase && ( + + It is now time to vote, vote the accused innocent or guilty! + + )} + disabled={!judgement_phase} + onClick={() => act("vote_guilty")} /> + + +
)} - - -
- {!!all_roles && all_roles.map(r => ( - - - {r} - ); }) + } + + + ) + )} + +
+
+ + +
+
-
- -
- {roleinfo !== undefined && !!roleinfo.action_log - && roleinfo.action_log.map(log_line => ( - - {log_line} - - ))} -
+ + {!!roleinfo && ( + +
+ {roleinfo !== undefined && !!roleinfo.action_log + && roleinfo.action_log.map(log_line => ( + + {log_line} + + ))} +
+
+ )} +
+ + + )} + + + {!!admin_controls && ( +
+ +
+ )}
); }; + +const LobbyDisplay = (props, context) => { + const { act, data } = useBackend(context); + const { + phase, + timeleft, + admin_controls, + } = data; + return ( + + [Phase = {phase} | ]{' '} +