Add show/hide bomb

This commit is contained in:
zikaeroh 2020-05-24 00:06:20 -07:00
parent 8c4507f6b4
commit 14a81762ac
7 changed files with 166 additions and 22 deletions

View File

@ -35,6 +35,8 @@ function useSender(sendNote: (r: ClientNote) => void, version: number): Sender {
changeTurnTime: (seconds: number) => sendNote({ method: 'changeTurnTime', version, params: { seconds } }), changeTurnTime: (seconds: number) => sendNote({ method: 'changeTurnTime', version, params: { seconds } }),
addPacks: (packs: WordPack[]) => sendNote({ method: 'addPacks', version, params: { packs } }), addPacks: (packs: WordPack[]) => sendNote({ method: 'addPacks', version, params: { packs } }),
removePack: (num: number) => sendNote({ method: 'removePack', version, params: { num } }), removePack: (num: number) => sendNote({ method: 'removePack', version, params: { num } }),
changeHideBomb: (hideBomb: boolean) =>
sendNote({ method: 'changeHideBomb', version, params: { hideBomb } }),
}; };
}, [sendNote, version]); }, [sendNote, version]);
} }

View File

@ -12,7 +12,18 @@ import {
useTheme, useTheme,
} from '@material-ui/core'; } from '@material-ui/core';
import { green, orange } from '@material-ui/core/colors'; import { green, orange } from '@material-ui/core/colors';
import { Add, ArrowBack, Delete, Link, Person, Search, Timer, TimerOff } from '@material-ui/icons'; import {
Add,
ArrowBack,
Delete,
Link,
Person,
Search,
Timer,
TimerOff,
Visibility,
VisibilityOff,
} from '@material-ui/icons';
import { ok as assertTrue } from 'assert'; import { ok as assertTrue } from 'assert';
import isArray from 'lodash/isArray'; import isArray from 'lodash/isArray';
import range from 'lodash/range'; import range from 'lodash/range';
@ -39,6 +50,7 @@ export interface Sender {
changeTurnTime: (seconds: number) => void; changeTurnTime: (seconds: number) => void;
addPacks: (packs: { name: string; words: string[] }[]) => void; addPacks: (packs: { name: string; words: string[] }[]) => void;
removePack: (num: number) => void; removePack: (num: number) => void;
changeHideBomb: (HideBomb: boolean) => void;
} }
export interface GameViewProps { export interface GameViewProps {
@ -415,12 +427,9 @@ const Footer = ({ send, state, pState }: GameViewProps) => {
const end = isDefined(state.winner); const end = isDefined(state.winner);
return ( return (
<Grid container direction="row" justify="space-between" alignItems="flex-start" spacing={2}> <div style={{ display: 'flex', justifyContent: 'space-between', alignContent: 'flex-start', flexWrap: 'wrap' }}>
<Grid item xs style={{ textAlign: 'left' }}> <div style={{ display: 'flex', alignContent: 'flex-start', flexWrap: 'wrap' }}>
<ButtonGroup <ButtonGroup variant="outlined" style={{ marginBottom: '0.5rem', marginRight: '0.5rem' }}>
variant="outlined"
style={{ marginBottom: '0.5rem', marginRight: '0.5rem', display: 'inline' }}
>
<Button <Button
type="button" type="button"
variant={pState.spymaster ? undefined : 'contained'} variant={pState.spymaster ? undefined : 'contained'}
@ -440,10 +449,25 @@ const Footer = ({ send, state, pState }: GameViewProps) => {
Spymaster Spymaster
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<ButtonGroup <ButtonGroup variant="outlined" style={{ marginBottom: '0.5rem', marginRight: '0.5rem' }}>
variant="outlined" <Button
style={{ marginBottom: '0.5rem', marginRight: '0.5rem', display: 'inline' }} type="button"
variant={state.hideBomb ? undefined : 'contained'}
onClick={() => send.changeHideBomb(false)}
startIcon={<Visibility />}
> >
Show bomb
</Button>
<Button
type="button"
variant={state.hideBomb ? 'contained' : undefined}
onClick={() => send.changeHideBomb(true)}
startIcon={<VisibilityOff />}
>
Hide bomb
</Button>
</ButtonGroup>
<ButtonGroup variant="outlined" style={{ marginBottom: '0.5rem', marginRight: '0.5rem' }}>
<Button <Button
type="button" type="button"
variant={isDefined(state.timer) ? undefined : 'contained'} variant={isDefined(state.timer) ? undefined : 'contained'}
@ -459,8 +483,8 @@ const Footer = ({ send, state, pState }: GameViewProps) => {
<Timer /> <Timer />
</Button> </Button>
</ButtonGroup> </ButtonGroup>
</Grid> </div>
<Grid item xs style={{ textAlign: 'right' }}> <div>
<Button <Button
type="button" type="button"
variant={end ? 'contained' : 'outlined'} variant={end ? 'contained' : 'outlined'}
@ -470,8 +494,8 @@ const Footer = ({ send, state, pState }: GameViewProps) => {
> >
New game New game
</Button> </Button>
</Grid> </div>
</Grid> </div>
); );
}; };

View File

@ -317,6 +317,7 @@ const props = {
], ],
turnTime: 0, turnTime: 0,
turnEnd: null, turnEnd: null,
hideBomb: false,
}, },
pState: { pState: {
playerID: 'acb830de-80e2-4eba-9b56-81b089fd3f12', playerID: 'acb830de-80e2-4eba-9b56-81b089fd3f12',

View File

@ -76,6 +76,10 @@ export const ClientNote = myzod
method: myzod.literal('removePack'), method: myzod.literal('removePack'),
params: myzod.object({ num: myzod.number() }), params: myzod.object({ num: myzod.number() }),
}), }),
myzod.object({
method: myzod.literal('changeHideBomb'),
params: myzod.object({ hideBomb: myzod.boolean() }),
}),
]) ])
); );
@ -129,6 +133,7 @@ export const State = myzod.object({
}) })
), ),
timer: StateTimer.optional().nullable(), timer: StateTimer.optional().nullable(),
hideBomb: myzod.boolean(),
}); });
export type ServerNote = Infer<typeof ServerNote>; export type ServerNote = Infer<typeof ServerNote>;

View File

@ -174,6 +174,13 @@ type ServerNote struct {
Params interface{} `json:"params"` Params interface{} `json:"params"`
} }
const ChangeHideBombMethod = ClientMethod("changeHideBomb")
//easyjson:json
type ChangeHideBombParams struct {
HideBomb bool `json:"hideBomb"`
}
func StateNote(s *State) ServerNote { func StateNote(s *State) ServerNote {
return ServerNote{ return ServerNote{
Method: "state", Method: "state",
@ -191,6 +198,7 @@ type State struct {
WordsLeft []int `json:"wordsLeft"` WordsLeft []int `json:"wordsLeft"`
Lists []*StateWordList `json:"lists"` Lists []*StateWordList `json:"lists"`
Timer *StateTimer `json:"timer"` Timer *StateTimer `json:"timer"`
HideBomb bool `json:"hideBomb"`
} }
//easyjson:json //easyjson:json

View File

@ -804,6 +804,8 @@ func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol7(in *jlexer.L
} }
(*out.Timer).UnmarshalEasyJSON(in) (*out.Timer).UnmarshalEasyJSON(in)
} }
case "hideBomb":
out.HideBomb = bool(in.Bool())
default: default:
in.AddError(&jlexer.LexerError{ in.AddError(&jlexer.LexerError{
Offset: in.GetPos(), Offset: in.GetPos(),
@ -948,6 +950,11 @@ func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol7(out *jwriter
(*in.Timer).MarshalEasyJSON(out) (*in.Timer).MarshalEasyJSON(out)
} }
} }
{
const prefix string = ",\"hideBomb\":"
out.RawString(prefix)
out.Bool(bool(in.HideBomb))
}
out.RawByte('}') out.RawByte('}')
} }
@ -2093,7 +2100,77 @@ func (v *ChangeNicknameParams) UnmarshalJSON(data []byte) error {
func (v *ChangeNicknameParams) UnmarshalEasyJSON(l *jlexer.Lexer) { func (v *ChangeNicknameParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol22(l, v) easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol22(l, v)
} }
func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol23(in *jlexer.Lexer, out *AddPacksParams) { func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol23(in *jlexer.Lexer, out *ChangeHideBombParams) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "hideBomb":
out.HideBomb = bool(in.Bool())
default:
in.AddError(&jlexer.LexerError{
Offset: in.GetPos(),
Reason: "unknown field",
Data: key,
})
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol23(out *jwriter.Writer, in ChangeHideBombParams) {
out.RawByte('{')
first := true
_ = first
{
const prefix string = ",\"hideBomb\":"
out.RawString(prefix[1:])
out.Bool(bool(in.HideBomb))
}
out.RawByte('}')
}
// MarshalJSON supports json.Marshaler interface
func (v ChangeHideBombParams) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol23(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
func (v ChangeHideBombParams) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol23(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
func (v *ChangeHideBombParams) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol23(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *ChangeHideBombParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol23(l, v)
}
func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol24(in *jlexer.Lexer, out *AddPacksParams) {
isTopLevel := in.IsStart() isTopLevel := in.IsStart()
if in.IsNull() { if in.IsNull() {
if isTopLevel { if isTopLevel {
@ -2158,7 +2235,7 @@ func easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol23(in *jlexer.
in.Consumed() in.Consumed()
} }
} }
func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol23(out *jwriter.Writer, in AddPacksParams) { func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol24(out *jwriter.Writer, in AddPacksParams) {
out.RawByte('{') out.RawByte('{')
first := true first := true
_ = first _ = first
@ -2184,25 +2261,25 @@ func easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol23(out *jwrite
// MarshalJSON supports json.Marshaler interface // MarshalJSON supports json.Marshaler interface
func (v AddPacksParams) MarshalJSON() ([]byte, error) { func (v AddPacksParams) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{} w := jwriter.Writer{}
easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol23(&w, v) easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol24(&w, v)
return w.Buffer.BuildBytes(), w.Error return w.Buffer.BuildBytes(), w.Error
} }
// MarshalEasyJSON supports easyjson.Marshaler interface // MarshalEasyJSON supports easyjson.Marshaler interface
func (v AddPacksParams) MarshalEasyJSON(w *jwriter.Writer) { func (v AddPacksParams) MarshalEasyJSON(w *jwriter.Writer) {
easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol23(w, v) easyjsonE4425964EncodeGithubComZikaerohCodiesInternalProtocol24(w, v)
} }
// UnmarshalJSON supports json.Unmarshaler interface // UnmarshalJSON supports json.Unmarshaler interface
func (v *AddPacksParams) UnmarshalJSON(data []byte) error { func (v *AddPacksParams) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data} r := jlexer.Lexer{Data: data}
easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol23(&r, v) easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol24(&r, v)
return r.Error() return r.Error()
} }
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *AddPacksParams) UnmarshalEasyJSON(l *jlexer.Lexer) { func (v *AddPacksParams) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol23(l, v) easyjsonE4425964DecodeGithubComZikaerohCodiesInternalProtocol24(l, v)
} }
func easyjsonE4425964Decode(in *jlexer.Lexer, out *struct { func easyjsonE4425964Decode(in *jlexer.Lexer, out *struct {
Name string `json:"name"` Name string `json:"name"`

View File

@ -214,6 +214,8 @@ type Room struct {
turnSeconds int turnSeconds int
turnDeadline *time.Time turnDeadline *time.Time
turnTimer *time.Timer turnTimer *time.Timer
hideBomb bool
} }
type noteSender func(protocol.ServerNote) type noteSender func(protocol.ServerNote)
@ -411,6 +413,13 @@ func (r *Room) handleNote(playerID game.PlayerID, note *protocol.ClientNote) err
} }
r.room.RemovePack(params.Num) r.room.RemovePack(params.Num)
case protocol.ChangeHideBombMethod:
var params protocol.ChangeHideBombParams
if err := json.Unmarshal(note.Params, &params); err != nil {
return err
}
r.changeHideBomb(params.HideBomb)
default: default:
log.Printf("unhandled method: %s", note.Method) log.Printf("unhandled method: %s", note.Method)
} }
@ -469,6 +478,7 @@ func (r *Room) createRoomState(spymaster bool) *protocol.State {
Board: make([][]*protocol.StateTile, room.Board.Rows), Board: make([][]*protocol.StateTile, room.Board.Rows),
WordsLeft: room.Board.WordCounts, WordsLeft: room.Board.WordCounts,
Lists: make([]*protocol.StateWordList, len(room.WordLists)), Lists: make([]*protocol.StateWordList, len(room.WordLists)),
HideBomb: r.hideBomb,
} }
if r.turnDeadline != nil { if r.turnDeadline != nil {
@ -503,11 +513,17 @@ func (r *Room) createRoomState(spymaster bool) *protocol.State {
} }
if spymaster || tile.Revealed || room.Winner != nil { if spymaster || tile.Revealed || room.Winner != nil {
sTile.View = &protocol.StateView{ view := &protocol.StateView{
Team: tile.Team, Team: tile.Team,
Neutral: tile.Neutral, Neutral: tile.Neutral,
Bomb: tile.Bomb, Bomb: tile.Bomb,
} }
if !tile.Revealed && room.Winner != nil && r.hideBomb {
view.Bomb = false
}
sTile.View = view
} }
tiles[col] = sTile tiles[col] = sTile
@ -608,3 +624,14 @@ func (r *Room) startTimer() {
r.turnDeadline = &deadline r.turnDeadline = &deadline
r.turnTimer = time.AfterFunc(dur, r.timerEndTurn) r.turnTimer = time.AfterFunc(dur, r.timerEndTurn)
} }
// Must be called with r.mu locked.
func (r *Room) changeHideBomb(HideBomb bool) {
if r.hideBomb == HideBomb {
return
}
r.hideBomb = true
r.room.Version++
r.sendAll()
}