X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;ds=sidebyside;f=empathy%2Fempathy.jsx;h=90bf0fd360829299facce85a1e3593c3a82db63a;hb=3259884cd8389a4467d8abc160b2eb64eb215323;hp=3869b3a249f12ff169a62e7dca85a789c4beb2da;hpb=533300fbcbfec8c219901cbde2d9c6f336939f97;p=lmno.games
diff --git a/empathy/empathy.jsx b/empathy/empathy.jsx
index 3869b3a..90bf0fd 100644
--- a/empathy/empathy.jsx
+++ b/empathy/empathy.jsx
@@ -48,7 +48,7 @@ events.addEventListener("player-enter", event => {
events.addEventListener("player-exit", event => {
const info = JSON.parse(event.data);
- window.game.remove_player(info);
+ window.game.disable_player(info);
});
events.addEventListener("player-update", event => {
@@ -227,23 +227,43 @@ const PlayerInfo = React.memo(props => {
if (! props.player.id)
return null;
- const all_players = [props.player, ...props.other_players];
+ const all_players = [{...props.player, active:true}, ...props.other_players];
const sorted_players = all_players.sort((a,b) => {
return b.score - a.score;
});
- const names_and_scores = sorted_players.map(player => {
- if (player.score)
- return `${player.name} (${player.score})`;
- else
- return player.name;
- }).join(', ');
+ /* Return a new array with the separator interspersed between
+ * each element of the array passed in as the argument.
+ */
+ function intersperse(arr, sep) {
+ return arr.reduce((acc, val) => [...acc, sep, val], []).slice(1);
+ }
+
+ let names_and_scores = sorted_players.map(player => {
+ if (player.score) {
+ return (
+
+ {player.name} ({player.score})
+
+ );
+ } else {
+ if (player.active)
+ return player.name;
+ else
+ return null;
+ }
+ }).filter(component => component != null);
+
+ names_and_scores = intersperse(names_and_scores, ", ");
return (
{[...this.props.votes].map(v => {
return (
@@ -570,25 +662,35 @@ class Ambiguities extends React.PureComponent {
}
let still_waiting = null;
- if (Object.keys(this.props.players_judging).length) {
- still_waiting = [
-
- Still waiting for the following players:
-
,
-
- {Object.keys(this.props.players_judging).map(player => {
- return (
- -
- {player}
- {this.props.players_judging[player] ?
- : null }
-
- );
- })}
-
- ];
+ const judging_players = Object.keys(this.props.players_judging);
+ if (judging_players.length) {
+ still_waiting = (
+
+
+ Still waiting for the following player
+ {judging_players.length > 1 ? 's' : '' }
+ :
+
+
+ {judging_players.map(player => {
+ return (
+ -
+ {player}{' '}
+
+ {'.'}{'.'}{'.'}
+
+
+ );
+ })}
+
+
+ );
}
if (this.props.players_judged.has(this.props.player.name)) {
@@ -613,11 +715,16 @@ class Ambiguities extends React.PureComponent {
Judging Answers
- Click on each pair of answers that should be scored as equivalent,
- (and click any word twice to split it out from a group). Remember,
+ Click/tap on each pair of answers that should be scored as equivalent,
+ (or click a word twice to split it out from a group). Remember,
what goes around comes around, so it's best to be generous when
judging.
+
+ Also, for an especially fun or witty answer, you can give kudos
+ by clicking the star on the right. You may only do this for one
+ word/group.
+
{this.props.prompt.prompt}
{this.state.word_sets.map(set => {
return (
@@ -637,6 +744,27 @@ class Ambiguities extends React.PureComponent {
);
})}
+
{
+ event.stopPropagation();
+ if (this.state.starred === set) {
+ this.setState({
+ starred: null
+ });
+ } else {
+ this.setState({
+ starred: set
+ });
+ }
+ }}
+ >
+ {this.state.starred === set ?
+ 'â
' : 'â'
+ }
+
);
})}
@@ -715,6 +843,39 @@ class ActivePrompt extends React.PureComponent {
}
render() {
+
+ let still_waiting = null;
+ const answering_players = Object.keys(this.props.players_answering);;
+ if (answering_players.length) {
+ still_waiting = (
+
+
+ Still waiting for the following player
+ {answering_players.length > 1 ? 's' : ''}
+ :
+
+
+ {answering_players.map(player => {
+ return (
+ -
+ {player}{' '}
+
+ {'.'}{'.'}{'.'}
+
+
+ );
+ })}
+
+
+ );
+ }
+
let move_on_button = null;
if (this.props.idle) {
move_on_button =(
@@ -722,7 +883,9 @@ class ActivePrompt extends React.PureComponent {
className="vote-button"
onClick={() => fetch_post_json(`end-answers/${this.props.prompt.id}`) }
>
- Move On
+ {answering_players.length ?
+ "Move On Without Their Answers" :
+ "Move On Without Anyone Else"}
{[...this.props.votes].map(v => {
return (
@@ -739,28 +902,6 @@ class ActivePrompt extends React.PureComponent {
);
}
- let still_waiting = null;
- if (Object.keys(this.props.players_answering).length) {
- still_waiting = [
-
- Still waiting for the following players:
-
,
-
- {Object.keys(this.props.players_answering).map(player => {
- return (
- -
- {player}
- {this.props.players_answering[player] ?
- : null }
-
- );
- })}
-
- ];
- }
-
if (this.props.players_answered.has(this.props.player.name)) {
return (
@@ -867,9 +1008,16 @@ class Game extends React.PureComponent {
});
}
- remove_player(info) {
+ disable_player(info) {
+ const idx = this.state.other_players.findIndex(o => o.id === info.id);
+ if (idx < 0)
+ return;
+
+ const other_players_copy = [...this.state.other_players];
+ other_players_copy[idx].active = false;
+
this.setState({
- other_players: this.state.other_players.filter(o => o.id !== info.id)
+ other_players: other_players_copy
});
}
@@ -944,12 +1092,29 @@ class Game extends React.PureComponent {
}
set_player_answering(player) {
+ /* Set the player as actively answering now. */
this.setState({
players_answering: {
...this.state.players_answering,
[player]: {active: true}
}
});
+ /* And arrange to have them marked idle very shortly.
+ *
+ * Note: This timeout is intentionally very, very short. We only
+ * need it long enough that the browser has latched onto the state
+ * change to "active" above. We actually use a CSS transition
+ * delay to control the user-perceptible length of time after
+ * which an active player appears inactive.
+ */
+ setTimeout(() => {
+ this.setState({
+ players_answering: {
+ ...this.state.players_answering,
+ [player]: {active: false}
+ }
+ });
+ }, 100);
}
set_answering_idle(value) {
@@ -1009,12 +1174,30 @@ class Game extends React.PureComponent {
}
set_player_judging(player) {
+ /* Set the player as actively judging now. */
this.setState({
players_judging: {
...this.state.players_judging,
[player]: {active: true}
}
});
+ /* And arrange to have them marked idle very shortly.
+ *
+ * Note: This timeout is intentionally very, very short. We only
+ * need it long enough that the browser has latched onto the state
+ * change to "active" above. We actually use a CSS transition
+ * delay to control the user-perceptible length of time after
+ * which an active player appears inactive.
+ */
+ setTimeout(() => {
+ this.setState({
+ players_judging: {
+ ...this.state.players_judging,
+ [player]: {active: false}
+ }
+ });
+ }, 100);
+
}
set_judging_idle(value) {
@@ -1073,18 +1256,43 @@ class Game extends React.PureComponent {
render() {
const state = this.state;
- const players_total = 1 + state.other_players.length;
if (state.scores) {
+
+ const players_total = state.players_answered.size;
+
+ let perfect_score = 0;
+ for (let i = 0;
+ i < state.active_prompt.items &&
+ i < state.scores.words.length;
+ i++)
+ {
+ perfect_score += state.scores.words[i].players.length;
+ }
+
return (
{state.active_prompt.prompt}
Scores
{state.scores.scores.map(score => {
+ let perfect = null;
+ if (score.score === perfect_score) {
+ perfect = Perfect!;
+ }
+ let quirkster = null;
+ if (score.score === state.active_prompt.items) {
+ quirkster = Quirkster!;
+ }
+ let kudos_slam = null;
+ if (score.kudos > 0 && score.kudos >= players_total - 1) {
+ kudos_slam = Kudos Slam!;
+ }
return (
- -
+
-
{score.players.join("/")}: {score.score}
+ {score.kudos ? `, ${'â
'.repeat(score.kudos)}` : ""}
+ {' '}{perfect} {quirkster} {kudos_slam}
);
})}
@@ -1092,9 +1300,20 @@ class Game extends React.PureComponent {
Words submitted
{state.scores.words.map(word => {
+ let great_minds = null;
+ if (word.kudos.length && word.players.length > 1) {
+ great_minds = Great Minds!;
+ }
+ let kudos_slam = null;
+ if (word.kudos.length > 0 && word.kudos.length >= players_total - 1) {
+ kudos_slam = Kudos Slam!;
+ }
return (
-
- {word.word} ({word.players.length}): {word.players.join(', ')}
+ {word.word} ({word.players.length}
+ {word.kudos.length ? `, ${'â
'.repeat(word.kudos.length)}` : ""}
+ ): {word.players.join(', ')}
+ {' '}{great_minds}{kudos_slam}
);
})}
@@ -1163,14 +1382,15 @@ class Game extends React.PureComponent {
,
- ,
p.active).length}
prompts={state.prompts}
+ />,
+
];
}