import { Character } from './Character.tsx'; import { orientationDegrees } from '../../convex/util/geometry.ts'; import { characters } from '../../data/characters.ts'; import { toast } from 'react-toastify'; import { Player as ServerPlayer } from '../../convex/aiTown/player.ts'; import { GameId } from '../../convex/aiTown/ids.ts'; import { Id } from '../../convex/_generated/dataModel'; import { Location, locationFields, playerLocation } from '../../convex/aiTown/location.ts'; import { useHistoricalValue } from '../hooks/useHistoricalValue.ts'; import { PlayerDescription } from '../../convex/aiTown/playerDescription.ts'; import { WorldMap } from '../../convex/aiTown/worldMap.ts'; import { ServerGame } from '../hooks/serverGame.ts'; export type SelectElement = (element?: { kind: 'player'; id: GameId<'players'> }) => void; const logged = new Set(); export const Player = ({ game, isViewer, player, onClick, historicalTime, }: { game: ServerGame; isViewer: boolean; player: ServerPlayer; onClick: SelectElement; historicalTime?: number; }) => { const playerCharacter = game.playerDescriptions.get(player.id)?.character; if (!playerCharacter) { throw new Error(`Player ${player.id} has no character`); } let character = characters.find((c) => c.name === playerCharacter); // If it's night, use the night version of the character if (game.world.gameCycle.cycleState === 'Night' && game.playerDescriptions.get(player.id)?.type === 'werewolf') { character = characters.find((c) => c.name === 'c1'); } const locationBuffer = game.world.historicalLocations?.get(player.id); const historicalLocation = useHistoricalValue( locationFields, historicalTime, playerLocation(player), locationBuffer, ); if (!character) { if (!logged.has(playerCharacter)) { logged.add(playerCharacter); toast.error(`Unknown character ${playerCharacter}`); } return null; } if (!historicalLocation) { return null; } const isSpeaking = !![...game.world.conversations.values()].find( (c) => c.isTyping?.playerId === player.id, ); const isThinking = !isSpeaking && !![...game.world.agents.values()].find( (a) => a.playerId === player.id && !!a.inProgressOperation, ); const tileDim = game.worldMap.tileDim; const historicalFacing = { dx: historicalLocation.dx, dy: historicalLocation.dy }; return ( <> 0} isThinking={isThinking} isSpeaking={isSpeaking} emoji={ player.activity && player.activity.until > (historicalTime ?? Date.now()) ? player.activity?.emoji : undefined } isViewer={isViewer} textureUrl={character.textureUrl} spritesheetData={character.spritesheetData} speed={character.speed} onClick={() => { onClick({ kind: 'player', id: player.id }); }} /> ); };