feat(rosto): atividades (momentos dele) e seis gestos novos

Atividades: a tela se divide, o rosto vai para a esquerda e encolhe, e
à direita um bonequinho do Carinha (silhueta na cor dos olhos) faz algo:
ler (vira a página), cantar (microfone e notas), jogar bola
(embaixadinha), videogame (TV com joguinho), pintar (cavalete que ganha
pinceladas) e malhar (halteres e suor). Os olhos grandes acompanham:
leem as linhas, seguem a bola, olham a TV. Camada própria atrás dos
olhos, vale para todos os rostos; em pé (retrato) a cena vai para baixo.

- Comando {tipo: "atividade", valor: nome|parar}; toque na tela, dormir
  e E-Stop encerram; o celular informa a atividade na telemetria.
- Modo vida escolhe pelo humor (feliz canta e joga bola, tranquilo lê
  e pinta, entediado joga videogame), nunca de madrugada, e não
  interrompe uma atividade em andamento.
- Gestos novos: rir, comemorar, tímido, confuso, bocejar e tonto; o
  humor e o modo vida também os usam.
- Painel: favoritos vão até 20 e o bravo volta junto com os novos;
  botões de atividade no Ao vivo, no Ctrl+K e tópico no guia.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
julio
2026-10-06 21:12:14 -03:00
co-authored by Claude Opus 5.5
parent 48fd51e377
commit d7a17b5683
13 changed files with 895 additions and 36 deletions
+30 -5
View File
@@ -55,20 +55,32 @@ HUMORES = {
# Gestos de cada humor: (gesto, peso, o que vai no diário)
ATOS = {
'feliz': [('alegre', 3, 'Saltitou de alegria'), ('musica', 2, 'Cantarolou'), ('feliz', 3, 'Sorriu à toa'),
('piscadinha', 2, 'Deu uma piscadinha'), ('coracao', 1, 'Ficou apaixonado pelo dia')],
('piscadinha', 2, 'Deu uma piscadinha'), ('coracao', 1, 'Ficou apaixonado pelo dia'),
('rir', 2, 'Deu risada sozinho'), ('comemorar', 1, 'Comemorou à toa')],
'tranquilo': [('olhar_esq', 2, 'Olhou em volta'), ('olhar_dir', 2, 'Olhou em volta'), ('piscar2', 2, 'Piscou devagar'),
('feliz', 1, 'Sorriu'), ('pensar', 1, 'Ficou pensativo')],
('feliz', 1, 'Sorriu'), ('pensar', 1, 'Ficou pensativo'), ('timido', 1, 'Ficou tímido')],
'entediado': [('pensar', 3, 'Ficou pensando na vida'), ('olhar_esq', 2, 'Procurou algo para fazer'),
('olhar_dir', 2, 'Procurou algo para fazer'), ('espiar', 2, 'Espiou por trás das mãos'),
('musica', 1, 'Cantou para passar o tempo')],
('musica', 1, 'Cantou para passar o tempo'), ('bocejar', 2, 'Bocejou de tédio'),
('confuso', 1, 'Ficou confuso com alguma coisa')],
'carente': [('triste', 2, 'Sentiu falta de alguém'), ('olhar_baixo', 2, 'Ficou cabisbaixo'),
('esconder', 1, 'Escondeu o rosto')],
'carente_perto': [('acenar', 3, 'Acenou chamando atenção'), ('espiar', 2, 'Espiou quem está aí'),
('coracao', 2, 'Pediu carinho'), ('surpreso', 1, 'Fez cara de "oi!"')],
('coracao', 2, 'Pediu carinho'), ('surpreso', 1, 'Fez cara de "oi!"'), ('timido', 1, 'Ficou tímido')],
'triste': [('triste', 3, 'Ficou tristinho'), ('olhar_baixo', 2, 'Olhou para baixo'), ('pensar', 1, 'Ficou pensativo')],
'cansado': [('piscar2', 3, 'Bocejou'), ('olhar_baixo', 2, 'Cochilou de olho aberto')],
'cansado': [('bocejar', 3, 'Bocejou'), ('piscar2', 1, 'Piscou devagar'), ('olhar_baixo', 2, 'Cochilou de olho aberto'),
('tonto', 1, 'Ficou meio tonto de sono')],
}
# Atividades (momentos dele): o bonequinho faz algo na tela. Por humor: (atividade, peso, diário, efeito)
ATIVIDADES = {
'feliz': [('cantar', 3, 'Foi cantar'), ('bola', 2, 'Foi jogar bola'), ('malhar', 1, 'Foi malhar')],
'tranquilo': [('ler', 3, 'Foi ler um livro'), ('pintar', 2, 'Foi pintar um quadro'), ('cantar', 1, 'Foi cantar')],
'entediado': [('videogame', 3, 'Foi jogar videogame'), ('bola', 2, 'Foi jogar bola'),
('pintar', 1, 'Foi pintar um quadro'), ('ler', 1, 'Foi ler um livro')],
}
GASTO_ATIVIDADE = {'malhar': 8, 'bola': 5, 'cantar': 3} # energia gasta
# Assuntos das figurinhas que ele inventa sozinho, por humor e por hora do dia.
TEMAS = {
'feliz': ['um sol sorridente', 'um balão colorido', 'um arco-íris', 'um sorvete de casquinha', 'confete de festa'],
@@ -102,6 +114,7 @@ class Vida:
self.celular_dormindo = lambda: None # True/False com o celular online, None sem ele
self.celular_online = lambda: False
self.alguem_perto = lambda: False # PIR/movimento recente
self.celular_atividade = lambda: None # atividade que o celular está fazendo agora
self.bloqueado = lambda: False # E-Stop ou modo presença com ninguém em casa
self.pode_gemini = lambda: bool(os.environ.get('GEMINI_API_KEY'))
self.madrugada = self.noite_padrao # o main troca pelo horário dos ajustes
@@ -375,6 +388,18 @@ class Vida:
self.dormir(agora, 'Ficou cansado e foi tirar um cochilo')
return 'dormir'
humor = self.humor()
if self.celular_atividade():
return None # ocupado com uma atividade: deixa terminar
# momentos dele: ler, cantar, jogar bola, videogame... (de dia, com o celular online)
if humor in ATIVIDADES and self.celular_online() and not self.madrugada(agora) and self.rng.random() < 0.18:
nome, texto = self.escolher(ATIVIDADES[humor])
self.enfileirar('atividade ' + nome)
with self.lock:
n['diversao'] = _limitar(n['diversao'] + 18)
n['alegria'] = _limitar(n['alegria'] + 5)
n['energia'] = _limitar(n['energia'] - GASTO_ATIVIDADE.get(nome, 2))
self.anotar('atividade', texto, agora)
return 'atividade ' + nome
# habilidade: inventar uma figurinha nova (raro, com limite por dia e intervalo)
if not self.motivo_sem_emoji(agora) and self.celular_online() and self.rng.random() < 0.08:
if self.criar_figurinha(agora, humor):