Compare commits

..

5 Commits

Author SHA1 Message Date
Dominic Zimmer
cc55cbbe6b Restrict random buttons, Change button press highlight 2022-10-30 13:23:23 +01:00
Dominic Zimmer
58f102af60 Fix anarchy crash on empty inputs 2022-10-30 11:44:03 +01:00
Dominic Zimmer
dfbe9f6603 Implement timeouts 2022-10-30 11:25:24 +01:00
Dominic Zimmer
cb9494c89a Update frontend 2022-10-29 16:20:58 +02:00
Dominic Zimmer
cb5a143623 Add random mode 2022-10-29 15:26:12 +02:00
4 changed files with 132 additions and 41 deletions

View File

@@ -20,6 +20,8 @@ class GameMode:
name: str name: str
mode_function: ModeFunction mode_function: ModeFunction
allow_multitouch: bool allow_multitouch: bool
min_time: int
max_time: int
@dataclass @dataclass
@@ -62,9 +64,9 @@ class Arbiter:
self.modeswitch_time = None self.modeswitch_time = None
self.clients: dict[WebSocket, ClientState] = dict() self.clients: dict[WebSocket, ClientState] = dict()
def mode(self, name: str, allow_multitouch: bool = True): def mode(self, name: str, allow_multitouch: bool = True, min_time=10, max_time=90):
def inner(f: ModeFunction): def inner(f: ModeFunction):
self.modes.append(GameMode(name, f, allow_multitouch)) self.modes.append(GameMode(name, f, allow_multitouch, min_time, max_time))
return inner return inner
@@ -118,7 +120,7 @@ class Arbiter:
self.state.mode = self.current_mode.name self.state.mode = self.current_mode.name
self.update_next_mode() self.update_next_mode()
self.modeswitch_time = datetime.now() + timedelta( self.modeswitch_time = datetime.now() + timedelta(
seconds=settings.arbiter_mode_switch_cycle seconds=random.randint(self.current_mode.min_time, self.current_mode.max_time)
) )
if self.current_mode_task: if self.current_mode_task:
@@ -151,7 +153,7 @@ class Arbiter:
arbiter = Arbiter() arbiter = Arbiter()
@arbiter.mode("democracy", allow_multitouch=False) @arbiter.mode("democracy", allow_multitouch=False, min_time=5*60, max_time=10*60)
async def _(get_input: InputGetter, set_output: OutputSetter): async def _(get_input: InputGetter, set_output: OutputSetter):
while True: while True:
await asyncio.sleep(settings.democracy_vote_cycle) await asyncio.sleep(settings.democracy_vote_cycle)
@@ -188,19 +190,36 @@ async def _(get_input: InputGetter, set_output: OutputSetter):
set_output(output) set_output(output)
@arbiter.mode("anarchy", allow_multitouch=False) @arbiter.mode("anarchy", allow_multitouch=False, min_time=5*60, max_time=10*60)
async def _(get_input: InputGetter, set_output: OutputSetter): async def _(get_input: InputGetter, set_output: OutputSetter):
while True: while True:
await asyncio.sleep(settings.democracy_vote_cycle) await asyncio.sleep(settings.democracy_vote_cycle)
inputs: list[Input] = await get_input() inputs: list[Input] = await get_input()
the_input = random.choice(inputs) if not inputs:
if not the_input:
set_output(EMPTY_INPUT) set_output(EMPTY_INPUT)
continue continue
the_input = random.choice(inputs)
output = {button: the_input[button] for button in Button} output = {button: the_input[button] for button in Button}
set_output(output) set_output(output)
random_buttons : list[Button]= ["up", "down", "left", "right", "a", "b"];
@arbiter.mode("random", allow_multitouch=False, min_time=30, max_time=90)
async def _(get_input: InputGetter, set_output: OutputSetter):
while True:
await asyncio.sleep(settings.democracy_vote_cycle)
the_choice = random.choice([button for button in random_buttons])
if not the_choice:
set_output(EMPTY_INPUT)
continue
output = {button: (button == the_choice) for button in Button}
set_output(output)

View File

@@ -27,10 +27,6 @@
--button-color: lightgrey; --button-color: lightgrey;
} }
body {
background-color: black;
}
.button { .button {
line-height: var(--button-height); line-height: var(--button-height);
height: var(--button-height); height: var(--button-height);
@@ -42,7 +38,7 @@ body {
} }
.button.pressed { .button.pressed {
filter: drop-shadow(2px 2px 6px black); filter: drop-shadow(2px 2px 6px white);
} }
.button-a, .button-b { .button-a, .button-b {
--button-height: 50px; --button-height: 50px;
@@ -157,5 +153,7 @@ body {
*/ */
.client { .client {
height: 100vh;
width: 100vw;
background-color: black; background-color: black;
} }

View File

@@ -2,12 +2,13 @@ span {
color: white; color: white;
} }
.stream > div { .stream > div {
width: 300px; width: 290px;
height: 1080px; height: 1070px;
background-color: black; background-color: black;
padding: 5px; padding: 5px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-around;
} }
.heading { .heading {
display: flex; display: flex;
@@ -81,7 +82,7 @@ span {
border-radius: 20px; border-radius: 20px;
padding: 4px; padding: 4px;
gap: 2px; gap: 2px;
margin: 15%; width: 200px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
@@ -90,3 +91,65 @@ span {
pre { pre {
color: white; color: white;
} }
.info {
height: 35%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}
.info .heading {
display: block;
font-weight: bold;
color: #e8ff37;
font-size: 30pt;
text-align: center;
}
.info .link {
display: block;
font-weight: bold;
color: #49ff4f;
font-size: 24pt;
text-align: center;
}
.info .text {
display: block;
font-weight: bold;
font-size: 24pt;
text-align: center;
}
.info hr {
width: 100%;
}
.scoreboard {
display: flex;
flex-direction: column;
align-items: center;
}
.pokeball {
height: 200px;
width: 200px;
position: relative;
}
.pokeball :first-child {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: red;
clip-path: polygon(0% 0%, 0% 50%, 100% 50%, 100% 0%);
border-radius: 50%;
}
.pokeball :last-child {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: white;
clip-path: polygon(0% 50%, 0% 100%, 100% 100%, 100% 50%);
border-radius: 50%;
}

View File

@@ -36,33 +36,44 @@ const TVMode = () => {
{state === undefined ? {state === undefined ?
<span>Loading...</span> : <span>Loading...</span> :
<div> <div>
<span className={`mode mode-${state.mode}`}>{state.mode}</span> <div className="info">
<div className="row"> <span className="heading">
<div> LAN-Party Plays Pokemon
<span> </span>
next:&nbsp; <span className="text">
</span> Join with your phone on
<span className={`subtitle mode-${state.nextMode}`}>{state.nextMode}</span> </span>
<span className="link">
http://pokemon.lan/
</span>
<span className="text">
and become the very best!
</span>
<hr />
</div>
<div className="scoreboard">
<span className={`mode mode-${state.mode}`}>{state.mode}</span>
<div className="row">
<div>
<span>
next:&nbsp;
</span>
<span className={`subtitle mode-${state.nextMode}`}>{state.nextMode}</span>
</div>
<span className="timer">{Math.round(state.timeUntilNextMode ?? 0)}s </span>
</div>
<div className="voting">
{voteList.flatMap(([b, numVotes], index) => {
const percentage = numVotes === 0 ? 0 : Math.round(numVotes / totalCount * 100);
return <div className="vote" style={{ "--vote-percentage": percentage + "%" } as CSSProperties} key={index}>
<div className="bar-wrap">
<div className="bar" style={{ "--vote-percentage": percentage + "%" } as CSSProperties} >{b}</div>
</div>
<span className="percentage">{percentage === 0 ? "" : `${percentage}%`}</span>
</div>;
})}
</div> </div>
<span className="timer">{Math.round(state.timeUntilNextMode ?? 0)}s </span>
</div> </div>
<div className="voting">
{voteList.flatMap(([b, numVotes], index) => {
const percentage = numVotes === 0 ? 0 : Math.round(numVotes / totalCount * 100);
return <div className="vote" style={{ "--vote-percentage": percentage + "%" } as CSSProperties} key={index}>
<div className="bar-wrap">
<div className="bar" style={{ "--vote-percentage": percentage + "%" } as CSSProperties} >{b}</div>
</div>
<span className="percentage">{percentage === 0 ? "" : `${percentage}%`}</span>
</div>;
})}
</div>
<div>
Current state: <pre>
{JSON.stringify(state, null, 4)}
</pre>
</div>
</div> </div>
} }
</div>; </div>;