Skip to content

Commit 5149639

Browse files
authored
Add info token character token (#411)
1 parent 7094bf6 commit 5149639

7 files changed

Lines changed: 190 additions & 14 deletions

File tree

src/app/botc/actions-modal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ const BotcActionsModal = ({
201201
setPlayers(newPlayers);
202202
setOpen(false);
203203
}}
204+
defaultShowAll
204205
/>
205206
)}
206207
{selectMode === 'player' && 'test'}

src/app/botc/blood-on-the-clocktower-game.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ export class BotcGame {
2121
edition: Edition;
2222
lobby?: { name: string; corpsId?: string }[];
2323
players?: BotcPlayer[];
24+
demonBluffs?: CharacterId[];
2425
}) {
2526
this.edition = initial.edition;
2627
this.lobby = initial.lobby ?? [];
2728
this.players = initial.players ?? [];
28-
this.demonBluffs = [];
29+
this.demonBluffs = initial.demonBluffs ?? [];
2930
}
3031

3132
static fromJSON(json: string) {

src/app/botc/blood-on-the-clocktower.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ const BloodOnTheClocktowerElement = () => {
8686
const startGame = () => {
8787
gameState.assignCharacters(selectedCharacters);
8888
if (gameState.players.length > 0) {
89+
const bluffs = gameState.generateDemonBluffs();
90+
gameState.demonBluffs = bluffs;
8991
setGameState(gameState);
9092
setTab('grimoire');
9193
}
@@ -276,6 +278,11 @@ const BloodOnTheClocktowerElement = () => {
276278
<InfoTokenList
277279
chosenCharacters={gameState.charactersInPlay()}
278280
allCharacters={gameState.characters()}
281+
demonBluffs={gameState.demonBluffs}
282+
setDemonBluffs={(demonBluffs) => {
283+
gameState.demonBluffs = demonBluffs;
284+
setGameState(gameState);
285+
}}
279286
/>
280287
)}
281288
</div>

src/app/botc/character-token-selector.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ interface CharacterTokenSelectorProps {
99
characters: CharacterId[];
1010
allCharacters: CharacterId[];
1111
onChange?: (arg0: CharacterId) => void;
12+
defaultShowAll?: boolean;
1213
}
1314

1415
const CharacterTokenSelector = ({
1516
characters,
1617
allCharacters,
1718
onChange,
19+
defaultShowAll = false,
1820
}: CharacterTokenSelectorProps) => {
19-
const [showAllCharacters, setShowAllCharacters] = useState(true);
21+
const [showAllCharacters, setShowAllCharacters] = useState(defaultShowAll);
2022

2123
const charactersSet = new Set(characters);
2224
const activeCharacters = showAllCharacters

src/app/botc/info-token-list.tsx

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,35 @@ import InfoToken from './info-token';
99
interface InfoTokenListProps {
1010
chosenCharacters: CharacterId[];
1111
allCharacters: CharacterId[];
12+
demonBluffs: CharacterId[];
13+
setDemonBluffs: (arg0: CharacterId[]) => void;
1214
}
1315

1416
const INFO_TOKENS = [
1517
{
1618
text: 'This is the Demon',
17-
className: 'bg-red-600',
19+
className: 'bg-red-700',
1820
},
1921
{
2022
text: 'These are your Minions',
21-
className: 'bg-red-600',
23+
className: 'bg-red-700',
2224
},
2325
{
24-
text: 'These characters are not in play',
26+
text: 'These are your Demon bluffs',
2527
className: 'bg-blue-500',
2628
},
2729
{
2830
text: 'This character selected you',
2931
className: 'bg-blue-500',
3032
},
33+
{
34+
text: 'These characters are NOT in play',
35+
className: 'bg-blue-500',
36+
},
37+
{
38+
text: 'These characters are in play',
39+
className: 'bg-blue-500',
40+
},
3141
{
3242
text: 'You are',
3343
className: 'bg-green-500',
@@ -41,25 +51,44 @@ const INFO_TOKENS = [
4151
const InfoTokenList = ({
4252
chosenCharacters,
4353
allCharacters,
54+
demonBluffs,
55+
setDemonBluffs,
4456
}: InfoTokenListProps) => {
4557
const [activeTokenIndex, setActiveTokenIndex] = useState<
4658
number | undefined
4759
>();
4860
const [modalOpen, setModalOpen] = useState(false);
49-
const token =
50-
activeTokenIndex !== undefined ? INFO_TOKENS[activeTokenIndex] : undefined;
51-
console.log({ chosenCharacters, allCharacters });
5261
return (
5362
<>
5463
<Modal
64+
title='Info token'
5565
open={modalOpen}
5666
onBlur={() => {
5767
setModalOpen(false);
68+
setActiveTokenIndex(undefined);
5869
}}
5970
withCloseButton
6071
hideBackground
6172
>
62-
{token && <InfoToken text={token.text} />}
73+
{INFO_TOKENS.map((token, i) => (
74+
<div
75+
key={'inModal:' + token.text}
76+
className={i === activeTokenIndex ? '' : 'hidden'}
77+
>
78+
<InfoToken
79+
text={token.text}
80+
className={token.className}
81+
characters={chosenCharacters}
82+
allCharacters={allCharacters}
83+
demonBluffs={
84+
token.text.includes('bluffs') ? demonBluffs : undefined
85+
}
86+
setDemonBluffs={
87+
token.text.includes('bluffs') ? setDemonBluffs : undefined
88+
}
89+
/>
90+
</div>
91+
))}
6392
</Modal>
6493
<div className='grid grid-cols-2 gap-2 text-xs'>
6594
{INFO_TOKENS.map((token, i) => (

src/app/botc/info-token.tsx

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,123 @@
11
'use client';
22

3+
import Button from 'components/input/button';
4+
import { useState } from 'react';
5+
import {
6+
CharacterId,
7+
CHARACTERS,
8+
getDefaultAlignment,
9+
getType,
10+
} from './characters';
11+
import CharacterTokenSelector from './character-token-selector';
12+
import { cn } from 'utils/class-names';
13+
import CharacterToken from './character-token';
14+
315
interface InfoTokenProps {
416
text: string;
17+
className?: string;
18+
characters: CharacterId[];
19+
allCharacters: CharacterId[];
20+
demonBluffs?: CharacterId[];
21+
setDemonBluffs?: (arg0: CharacterId[]) => void;
522
}
623

7-
const InfoToken = ({ text }: InfoTokenProps) => {
24+
const InfoToken = ({
25+
text,
26+
className = '',
27+
characters,
28+
allCharacters,
29+
demonBluffs,
30+
setDemonBluffs,
31+
}: InfoTokenProps) => {
32+
const [isSelectingCharacterToken, setIsSelectingCharacterToken] =
33+
useState(false);
34+
const [characterTokens, _setCharacterTokens] = useState<CharacterId[]>(
35+
demonBluffs ?? [],
36+
);
37+
38+
const setCharacterTokens = (v: CharacterId[]) => {
39+
_setCharacterTokens(v);
40+
if (demonBluffs !== undefined && setDemonBluffs !== undefined) {
41+
setDemonBluffs(v);
42+
}
43+
};
44+
45+
const charactersSet = new Set(
46+
demonBluffs ? characterTokens.concat(characters) : characterTokens,
47+
);
48+
const filterFunc = (id: CharacterId) =>
49+
!charactersSet.has(id) &&
50+
(demonBluffs === undefined ||
51+
(getDefaultAlignment(id) === 'good' && getType(id) !== 'travellers'));
52+
53+
const firstCharacterToken = characterTokens[0];
854
return (
9-
<div className='rounded border p-12 shadow-md'>
10-
<h3 className='text-wrap text-center'>{text}</h3>
55+
<div
56+
className={cn(
57+
'flex flex-col items-center rounded border p-12 text-white shadow-md',
58+
className,
59+
)}
60+
>
61+
{!isSelectingCharacterToken && (
62+
<>
63+
<h3 className='text-wrap text-center'>{text}</h3>
64+
<div className='h-4' />
65+
<div className='flex w-1/2 flex-wrap justify-center gap-4'>
66+
{characterTokens.length > 0 &&
67+
characterTokens.map((id, i) => (
68+
<div key={text + id} className='w-1/3'>
69+
<CharacterToken
70+
characterId={id}
71+
onClick={() => {
72+
setCharacterTokens(characterTokens.toSpliced(i, 1));
73+
}}
74+
/>
75+
</div>
76+
))}
77+
{characterTokens.length === 1 &&
78+
firstCharacterToken &&
79+
CHARACTERS[firstCharacterToken].description}
80+
</div>
81+
<div className='h-4' />
82+
<div className='flex gap-2'>
83+
<Button
84+
compact
85+
onClick={() => {
86+
setIsSelectingCharacterToken(true);
87+
}}
88+
>
89+
Add character token
90+
</Button>
91+
</div>
92+
</>
93+
)}
94+
{isSelectingCharacterToken && (
95+
<>
96+
<h3>
97+
Add character token
98+
{demonBluffs && ' (Showing good characters not in play)'}
99+
</h3>
100+
<div className='h-2' />
101+
<CharacterTokenSelector
102+
characters={characters.filter(filterFunc)}
103+
allCharacters={allCharacters.filter(filterFunc)}
104+
onChange={(id) => {
105+
setCharacterTokens([...characterTokens, id]);
106+
setIsSelectingCharacterToken(false);
107+
}}
108+
defaultShowAll={!!demonBluffs}
109+
/>
110+
<div className='h-2' />
111+
<Button
112+
compact
113+
onClick={() => {
114+
setIsSelectingCharacterToken(false);
115+
}}
116+
>
117+
Cancel
118+
</Button>
119+
</>
120+
)}
11121
</div>
12122
);
13123
};

src/app/links/page.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Metadata } from 'next';
2+
import Link from 'next/link';
23
import { lang } from 'utils/language';
34

45
export const metadata: Metadata = {
@@ -9,7 +10,7 @@ const Links = () => {
910
return (
1011
<div>
1112
<h1>{lang('Länkar', 'Links')}</h1>
12-
<div className='text-lg'>
13+
<span className='text-lg'>
1314
<ul className='list-disc pl-4'>
1415
<li>
1516
<a
@@ -112,7 +113,32 @@ const Links = () => {
112113
</a>
113114
</li>
114115
</ul>
115-
</div>
116+
<div className='h-8' />
117+
<h3>Cool Corps Games</h3>
118+
<ul className='list-disc pl-4'>
119+
<li>
120+
<Link className='cursor-pointer text-red-600 underline' href='/set'>
121+
Set
122+
</Link>
123+
</li>
124+
<li>
125+
<Link
126+
className='cursor-pointer text-red-600 underline'
127+
href='/botc'
128+
>
129+
Bleck on the Corpstower
130+
</Link>
131+
</li>
132+
<li>
133+
<Link
134+
className='cursor-pointer text-red-600 underline'
135+
href='/coolmathgames/mummymaze'
136+
>
137+
Mummy Maze (WIP)
138+
</Link>
139+
</li>
140+
</ul>
141+
</span>
116142
</div>
117143
);
118144
};

0 commit comments

Comments
 (0)