feat(vida): jeito de gente e console com o porquê de cada decisão
Console (console.py + tela Console no painel):
- cada parte registra o que fez e o motivo: modo vida (com necessidades
e humor), sentidos, celular (ordens e o que o rosto fez), IA local,
aprendizado e ideias do dia; últimas 400 linhas, ao vivo pelo SSE;
- tela com o "agora" (humor, necessidades, o que está fazendo, próxima
decisão, última decisão, jeito), filtros, detalhes, pausa e busca.
Jeito de gente:
- saudade: a festa cresce com o tempo fora (aceno, "Oi! Você voltou!",
"Senti sua falta!"); bom dia lembrando de ontem;
- pedidos com motivo ("Brinca comigo?", "Me faz um carinho?", mostrar a
figurinha nova), no máximo 1 a cada 20 min;
- larga atividade no meio quando fica chato; personalidade (curiosidade,
brincadeira, timidez) que pesa nos gestos e amadurece com o convívio;
- no rosto: acordar grogue, sonhar com algo do dia (balão no motor),
hesitar antes de gestos, errar na atividade e ficar sem graça, olhar
nos olhos e desviar, sorrir de volta (FaceLandmarker no rastreador do
painel) e reagir à luz (sensor de luz no app 0.10.0);
- ordem "dizer" com legenda e voz de robô.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,8 @@ ESTIMULOS = {
|
||||
'brincar': (dict(diversao=25, alegria=8, energia=-5), 'alegre'),
|
||||
'alimentar': (dict(energia=30, alegria=4), 'feliz'),
|
||||
}
|
||||
NOME_ESTIMULO = {'pir': 'O sensor de presença viu alguém', 'movimento': 'A câmera viu movimento',
|
||||
'som': 'Ouviu um barulho', 'conversa': 'Alguém conversou com ele'}
|
||||
CUIDADOS = {'carinho': 'Recebeu carinho', 'cutucar': 'Levou uma cutucada', 'brincar': 'Brincou',
|
||||
'alimentar': 'Ganhou energia', 'ninar': 'Foi posto para dormir', 'acordar': 'Foi acordado'}
|
||||
|
||||
@@ -112,6 +114,16 @@ PERIODOS = [(5, 12, 'de manhã', ['um sol nascendo', 'um pãozinho', 'uma xícar
|
||||
(0, 5, 'de madrugada', ['uma lua', 'uma vela', 'uma coruja'])]
|
||||
|
||||
MAX_DIARIO = 60
|
||||
|
||||
# Personalidade: traços de 0 a 1 que mudam o jeito de tudo (0,5 = neutro) e amadurecem com o convívio.
|
||||
TRACOS = ('curiosidade', 'brincadeira', 'timidez')
|
||||
GESTOS_TRACO = {'brincadeira': {'rir', 'comemorar', 'alegre', 'musica', 'piscadinha'},
|
||||
'curiosidade': {'olhar_esq', 'olhar_dir', 'pensar', 'espiar', 'confuso'},
|
||||
'timidez': {'timido', 'esconder', 'espiar'}}
|
||||
# Reencontro: quanto mais tempo a pessoa ficou fora, maior a festa.
|
||||
AUSENCIA_ACENO, AUSENCIA_OI, AUSENCIA_SAUDADE = 10 * 60, 60 * 60, 4 * 3600
|
||||
INTERVALO_PEDIDO = 20 * 60 # no mínimo 20 min entre um pedido ("brinca comigo?") e outro
|
||||
DESISTE = 0.12 # chance de largar uma atividade no meio porque ficou chato
|
||||
GESTOS_VIDA = {g for atos in ATOS.values() for g, _, _ in atos}
|
||||
|
||||
|
||||
@@ -149,6 +161,17 @@ class Vida:
|
||||
self.aprendi_pendente = lambda: None # curiosidade de hoje que ainda dá para contar
|
||||
self.contar_aprendi = lambda ident, agora=None: None
|
||||
self.aprendizado = None # o que ele aprende com o dia a dia (aprendizado.py)
|
||||
self.console = lambda origem, texto, motivo='', nivel='info', agora=None: None # console do painel
|
||||
self.dia_anterior = lambda: None # resumo de ontem (aprendizado): para lembrar no bom dia
|
||||
# sorteios dos comportamentos "humanos" ficam à parte: não mexem na sequência do rng principal
|
||||
self.acaso = random.Random() if rng is None else random.Random(7)
|
||||
self.porque = '' # motivo da última decisão (vai para o console)
|
||||
self.ultima = None # {horario, texto, porque}: a última decisão de fato
|
||||
self.perto_antes = False
|
||||
self.ultimo_perto = time.time()
|
||||
self.pediu_em = 0.0
|
||||
self.desistencia = None # (quando, o que) se largou a atividade no meio
|
||||
self.figurinha_mostrada = 0.0
|
||||
|
||||
agora = time.time()
|
||||
self.config = dict(PADRAO)
|
||||
@@ -157,6 +180,10 @@ class Vida:
|
||||
self.diario = []
|
||||
self.emojis = dict(dia='', total=0, ultimo=0.0)
|
||||
self.dormindo_proprio = False
|
||||
# cada Carinha nasce com um jeito um pouco diferente (nos testes, neutro)
|
||||
self.personalidade = ({k: 0.5 for k in TRACOS} if rng is not None else
|
||||
{k: round(self.acaso.uniform(0.35, 0.65), 2) for k in TRACOS})
|
||||
self.saudou_dia = ''
|
||||
try:
|
||||
salvo = json.loads(self.caminho.read_text(encoding='utf-8'))
|
||||
self.config.update(self.validar(salvo.get('config', {})))
|
||||
@@ -165,6 +192,11 @@ class Vida:
|
||||
self.necessidades[k] = _limitar(float(salvo['necessidades'][k]))
|
||||
self.nascimento = float(salvo.get('nascimento', agora))
|
||||
self.diario = [d for d in salvo.get('diario', []) if isinstance(d, dict)][:MAX_DIARIO]
|
||||
if isinstance(salvo.get('personalidade'), dict):
|
||||
for k in TRACOS:
|
||||
if isinstance(salvo['personalidade'].get(k), (int, float)):
|
||||
self.personalidade[k] = max(0.0, min(1.0, float(salvo['personalidade'][k])))
|
||||
self.saudou_dia = str(salvo.get('saudou_dia', ''))
|
||||
if isinstance(salvo.get('emojis'), dict):
|
||||
self.emojis.update({k: salvo['emojis'][k] for k in ('dia', 'total', 'ultimo') if k in salvo['emojis']})
|
||||
except (OSError, ValueError, TypeError, AttributeError):
|
||||
@@ -222,7 +254,8 @@ class Vida:
|
||||
def salvar(self):
|
||||
with self.lock:
|
||||
dados = dict(config=self.config, necessidades=self.necessidades, nascimento=self.nascimento,
|
||||
diario=self.diario, emojis=self.emojis)
|
||||
diario=self.diario, emojis=self.emojis, personalidade=self.personalidade,
|
||||
saudou_dia=self.saudou_dia)
|
||||
self.salvo_em = time.time()
|
||||
try:
|
||||
gravar_atomico(self.caminho, dados)
|
||||
@@ -274,7 +307,9 @@ class Vida:
|
||||
nascimento=self.nascimento, idade_dias=int((agora - self.nascimento) // 86400),
|
||||
emojis_hoje=self.emojis_hoje(agora), ultimo_emoji=self.emojis.get('ultimo') or None,
|
||||
zanga=self.zanga(), sono_profundo=self.sono_profundo,
|
||||
pode_criar=self.motivo_sem_emoji(agora) or '', diario=self.diario[:30])
|
||||
pode_criar=self.motivo_sem_emoji(agora) or '', diario=self.diario[:30],
|
||||
personalidade=dict(self.personalidade), porque=self.porque, ultima=self.ultima,
|
||||
proximo_ato_em=max(0, round(self.proximo_ato - agora)))
|
||||
|
||||
def avisar(self):
|
||||
self.publicado_em = time.time()
|
||||
@@ -323,6 +358,10 @@ class Vida:
|
||||
self.interagiu_em = agora # alguém quis ele acordado (sensor não conta)
|
||||
if self.aprendizado:
|
||||
self.aprendizado.resposta(tipo, agora)
|
||||
self.amadurecer(tipo)
|
||||
self.console('sentidos', CUIDADOS.get(tipo) or NOME_ESTIMULO.get(tipo, tipo),
|
||||
', '.join('%s %+d' % (k, v) for k, v in efeito.items()),
|
||||
'detalhe' if tipo in ('som', 'movimento') else 'info', agora)
|
||||
if gesto and not self.bloqueado():
|
||||
if self.dormindo():
|
||||
self.acordar(agora, None)
|
||||
@@ -390,12 +429,108 @@ class Vida:
|
||||
self.anotar('atividade', 'Foi fazer %s %s%s' % (item['emoji'], item['nome'], motivo), agora)
|
||||
return 'atividade ' + nome
|
||||
nome = self.rng.choice(CALMAS) # apagaram a criação no meio do caminho
|
||||
if nome != 'dormir' and segundos > 60 and self.acaso.random() < DESISTE * (1.3 - self.personalidade['curiosidade']):
|
||||
segundos = segundos * self.acaso.uniform(0.3, 0.5) # vai largar no meio: ficou chato
|
||||
self.desistencia = (agora + segundos, NOME_ATIVIDADE.get(nome, 'a atividade'))
|
||||
self.enfileirar('atividade %s %d' % (nome, segundos))
|
||||
self.atividade_em = agora
|
||||
self.ultima_atividade = nome
|
||||
self.anotar('atividade', NOME_ATIVIDADE.get(nome, 'Foi fazer algo'), agora)
|
||||
return 'atividade ' + nome
|
||||
|
||||
def dizer(self, texto, gesto=None):
|
||||
"""Uma fala curta: o gesto e a frase em legenda, com a voz de robô."""
|
||||
if gesto:
|
||||
self.enfileirar(gesto)
|
||||
self.enfileirar('dizer ' + texto)
|
||||
|
||||
def resumo(self):
|
||||
n = self.necessidades
|
||||
return 'energia %d · alegria %d · social %d · diversão %d · %s' % (
|
||||
n['energia'], n['alegria'], n['social'], n['diversao'], HUMORES[self.humor()][1].lower())
|
||||
|
||||
@staticmethod
|
||||
def tempo(seg):
|
||||
return '%d min' % round(seg / 60) if seg < 3600 else '%dh%02d' % (seg // 3600, seg % 3600 // 60)
|
||||
|
||||
def saudacao(self, agora):
|
||||
"""Bom dia com uma lembrança de ontem (do que ele viveu, sem IA)."""
|
||||
hora = time.localtime(agora).tm_hour
|
||||
prefixo = 'Bom dia' if 5 <= hora < 12 else 'Boa tarde' if hora < 18 else 'Boa noite'
|
||||
fatos = []
|
||||
ontem = None
|
||||
try:
|
||||
ontem = self.dia_anterior()
|
||||
except Exception:
|
||||
pass
|
||||
if isinstance(ontem, dict):
|
||||
pres = ontem.get('presenca') or []
|
||||
tarde = [hh for hh in range(0, 5) if hh < len(pres) and pres[hh] is not None and pres[hh] >= 0.3]
|
||||
if tarde:
|
||||
fatos.append('Ontem a gente ficou acordado até as %dh, hein!' % (max(tarde) + 1))
|
||||
elif len(pres) == 24 and pres[23] is not None and pres[23] >= 0.3:
|
||||
fatos.append('Ontem a gente ficou até tarde, hein!')
|
||||
if (ontem.get('respostas') or 0) >= 5:
|
||||
fatos.append('Ontem foi um dia cheio de carinho. Obrigado!')
|
||||
elif (ontem.get('atos') or 0) >= 5 and not ontem.get('respostas'):
|
||||
fatos.append('Ontem ninguém brincou comigo... hoje vai ser diferente?')
|
||||
if not fatos:
|
||||
fatos.append('Acordei cheio de energia!' if self.necessidades['energia'] >= 80 else 'Que bom te ver!')
|
||||
return '%s! %s' % (prefixo, self.acaso.choice(fatos))
|
||||
|
||||
def reencontro(self, agora, ausencia):
|
||||
"""Alguém apareceu: a reação depende de quanto tempo ficou fora (e de quem ele é)."""
|
||||
if self.dormindo() or self.madrugada(agora) or self.bloqueado():
|
||||
return None
|
||||
n, tim = self.necessidades, self.personalidade['timidez']
|
||||
dia = time.strftime('%Y-%m-%d', time.localtime(agora))
|
||||
motivo = 'ninguém por perto havia ' + self.tempo(ausencia)
|
||||
if self.saudou_dia != dia and time.localtime(agora).tm_hour >= 5 and ausencia >= AUSENCIA_ACENO:
|
||||
self.saudou_dia = dia
|
||||
frase = self.saudacao(agora)
|
||||
self.dizer(frase, 'timido' if tim > 0.65 else 'acenar')
|
||||
ganho, texto, motivo = 10, 'Deu bom dia: "%s"' % frase, 'primeiro encontro do dia; ' + motivo
|
||||
elif ausencia >= AUSENCIA_SAUDADE:
|
||||
self.dizer('Senti sua falta!', 'comemorar')
|
||||
self.enfileirar('coracao')
|
||||
ganho, texto = 20, 'Fez festa: estava com saudade'
|
||||
n['alegria'] = _limitar(n['alegria'] + 10)
|
||||
elif ausencia >= AUSENCIA_OI:
|
||||
self.dizer('Oi! Você voltou!', 'timido' if tim > 0.65 else 'comemorar')
|
||||
ganho, texto = 10, 'Comemorou que alguém voltou'
|
||||
elif ausencia >= AUSENCIA_ACENO:
|
||||
self.enfileirar('acenar')
|
||||
ganho, texto = 4, 'Acenou para quem voltou'
|
||||
else:
|
||||
return None
|
||||
with self.lock:
|
||||
n['social'] = _limitar(n['social'] + ganho)
|
||||
self.anotar('social', texto, agora)
|
||||
self.console('vida', texto, motivo, agora=agora)
|
||||
self.avisar()
|
||||
return texto
|
||||
|
||||
def pedir_algo(self, agora):
|
||||
"""Iniciativa com motivo: pede o que está faltando (ou mostra o que fez)."""
|
||||
n = self.necessidades
|
||||
if n['social'] < 35:
|
||||
frase, gesto, porque = 'Tô carente... me faz um carinho?', 'coracao', 'social %d' % n['social']
|
||||
elif n['diversao'] < 40:
|
||||
frase, gesto, porque = 'Brinca comigo?', 'acenar', 'diversão %d' % n['diversao']
|
||||
elif (float(self.emojis.get('ultimo') or 0) > self.figurinha_mostrada and agora - float(self.emojis['ultimo']) < 3 * 3600
|
||||
and self.tocar_reacao(agora, anotar=False)):
|
||||
self.figurinha_mostrada = float(self.emojis['ultimo'])
|
||||
frase, gesto, porque = 'Olha o que eu desenhei!', None, 'criou uma figurinha e ainda não tinha mostrado'
|
||||
elif n['energia'] < 35:
|
||||
frase, gesto, porque = 'Tô com soninho...', 'bocejar', 'energia %d' % n['energia']
|
||||
else:
|
||||
return None
|
||||
self.pediu_em = agora
|
||||
self.dizer(frase, gesto)
|
||||
self.anotar('pedido', 'Pediu: "%s"' % frase, agora)
|
||||
self.porque = 'alguém por perto e ' + porque
|
||||
return 'pedido'
|
||||
|
||||
def pir_acorda(self, agora=None):
|
||||
"""Disparo do PIR com o rosto dormindo: acorda? No ritmo calmo precisa de vários em 2 min."""
|
||||
agora = agora or time.time()
|
||||
@@ -423,8 +558,27 @@ class Vida:
|
||||
"""Quanto o aprendizado multiplica a chance de um ato (1 = sem opinião)."""
|
||||
return self.aprendizado.peso(nome) if self.aprendizado else 1.0
|
||||
|
||||
def jeito(self, gesto):
|
||||
"""Quanto a personalidade puxa um gesto (1 = neutro): brincalhão ri mais, tímido se esconde mais."""
|
||||
f = 1.0
|
||||
for traco, gestos in GESTOS_TRACO.items():
|
||||
if gesto in gestos:
|
||||
f *= 1 + (self.personalidade[traco] - 0.5) * 1.2
|
||||
return f
|
||||
|
||||
def amadurecer(self, tipo):
|
||||
"""O convívio muda o jeito devagar: carinho deixa menos tímido, brincar deixa mais brincalhão."""
|
||||
p = self.personalidade
|
||||
with self.lock:
|
||||
if tipo in ('carinho', 'conversa', 'brincar'):
|
||||
p['timidez'] = round(max(0.1, p['timidez'] - 0.003), 3)
|
||||
if tipo == 'brincar':
|
||||
p['brincadeira'] = round(min(0.95, p['brincadeira'] + 0.002), 3)
|
||||
if tipo == 'conversa':
|
||||
p['curiosidade'] = round(min(0.95, p['curiosidade'] + 0.001), 3)
|
||||
|
||||
def escolher(self, opcoes):
|
||||
opcoes = [(g, p * self.gosto(g), t) for g, p, t in opcoes]
|
||||
opcoes = [(g, p * self.gosto(g) * self.jeito(g), t) for g, p, t in opcoes]
|
||||
total = sum(p for _, p, _ in opcoes)
|
||||
x = self.rng.uniform(0, total)
|
||||
for gesto, peso, texto in opcoes:
|
||||
@@ -467,42 +621,48 @@ class Vida:
|
||||
self.anotar('emoji', 'Teve uma ideia e desenhou ' + tema, agora)
|
||||
return True
|
||||
|
||||
def tocar_reacao(self, agora):
|
||||
def tocar_reacao(self, agora, anotar=True):
|
||||
try:
|
||||
reacoes = [r for r in self.treinamento.status()['reacoes'] if r.get('ativa', True) and r['feedback'] >= 0]
|
||||
except Exception:
|
||||
return False
|
||||
if not reacoes:
|
||||
return False
|
||||
r = self.rng.choice(reacoes[:40])
|
||||
r = self.rng.choice(reacoes[:40]) if anotar else reacoes[0] # para mostrar: a mais nova
|
||||
try:
|
||||
self.treinamento.testar(r['id'])
|
||||
except ValueError:
|
||||
return False
|
||||
self.anotar('acao', 'Lembrou da reação "' + r['receita'].get('nome', '?') + '"', agora)
|
||||
if anotar:
|
||||
self.anotar('acao', 'Lembrou da reação "' + r['receita'].get('nome', '?') + '"', agora)
|
||||
return True
|
||||
|
||||
def agir(self, agora):
|
||||
"""Um ato: o que um bichinho com essas necessidades faria agora."""
|
||||
n = self.necessidades
|
||||
perto = self.alguem_perto()
|
||||
self.porque = ''
|
||||
if self.dormindo():
|
||||
# de madrugada nunca acorda sozinho (nem com gente se mexendo na cama); de dia, só descansado
|
||||
if n['energia'] >= DESCANSADO and not self.madrugada(agora):
|
||||
self.acordar(agora, 'Acordou descansado')
|
||||
self.porque = 'energia %d: descansou' % n['energia']
|
||||
return 'acordar'
|
||||
# aprendeu a rotina: acorda do cochilo um pouco antes da hora em que costuma ter gente
|
||||
if (self.aprendizado and not self.sono_profundo and not self.madrugada(agora) and n['energia'] >= 50
|
||||
and self.aprendizado.chega_logo(agora)):
|
||||
self.acordar(agora, 'Acordou: daqui a pouco costuma chegar alguém')
|
||||
self.aprendizado.decidir('acordar', 'Acordou do cochilo antes da hora', self.aprendizado.porque_chegada(agora), agora)
|
||||
self.porque = self.aprendizado.porque_chegada(agora)
|
||||
self.aprendizado.decidir('acordar', 'Acordou do cochilo antes da hora', self.porque, agora)
|
||||
return 'acordar'
|
||||
return None
|
||||
if self.config['noite'] and self.madrugada(agora) and agora - self.interagiu_em > PEDIU_ATENCAO:
|
||||
self.dormir(agora, 'Ficou tarde, foi dormir')
|
||||
self.porque = 'madrugada e ninguém interagiu nos últimos 10 min'
|
||||
return 'dormir'
|
||||
if n['energia'] < SONO:
|
||||
self.dormir(agora, 'Ficou exausto e foi dormir', profundo=True)
|
||||
self.porque = 'energia %d: abaixo de %d, sono pesado até descansar' % (n['energia'], SONO)
|
||||
return 'dormir'
|
||||
humor = self.humor()
|
||||
if self.celular_atividade():
|
||||
@@ -511,9 +671,11 @@ class Vida:
|
||||
folga = agora - self.atividade_em > 90 # um respiro entre uma atividade e outra
|
||||
# cansado: um cochilo na caminha de vez em quando (recupera energia sem o sono pesado)
|
||||
if dia and folga and n['energia'] < COCHILO and self.rng.random() < 0.35:
|
||||
self.porque = 'energia %d: abaixo de %d, um cochilo' % (n['energia'], COCHILO)
|
||||
return self.comecar_atividade(agora, 'dormir', self.rng.uniform(120, 240))
|
||||
# entediado: vai fazer alguma coisa por alguns minutos (pode ser interrompido)
|
||||
if dia and folga and n['diversao'] < TEDIO and self.rng.random() < 0.75:
|
||||
self.porque = 'diversão %d: entediado (abaixo de %d)' % (n['diversao'], TEDIO)
|
||||
return self.comecar_atividade(agora, self.escolher_atividade(), self.rng.uniform(120, 300))
|
||||
# ninguém olhando há um tempo: vai cuidar da vida dele (ler, pintar, música...)
|
||||
if perto:
|
||||
@@ -523,8 +685,9 @@ class Vida:
|
||||
if (dia and folga and sozinho and self.aprendizado and n['energia'] < 85
|
||||
and self.aprendizado.casa_vazia(agora) and self.rng.random() < 0.3):
|
||||
segundos = self.rng.uniform(600, 1200)
|
||||
self.porque = self.aprendizado.porque_vazia(agora)
|
||||
self.aprendizado.decidir('cochilo', 'Tirou um cochilo de %d min para guardar energia' % round(segundos / 60),
|
||||
self.aprendizado.porque_vazia(agora), agora)
|
||||
self.porque, agora)
|
||||
return self.comecar_atividade(agora, 'dormir', segundos)
|
||||
# alguém por perto e ele aprendeu algo hoje: "Olha o que eu aprendi hoje!"
|
||||
if dia and perto and humor != 'bravo':
|
||||
@@ -533,26 +696,41 @@ class Vida:
|
||||
self.contar_aprendi(item['id'], agora)
|
||||
with self.lock:
|
||||
n['social'] = _limitar(n['social'] + 5)
|
||||
self.porque = 'alguém por perto e aprendeu "%s" hoje' % item.get('nome', '?')
|
||||
return 'aprendi'
|
||||
# iniciativa: com gente por perto, pede o que está faltando (tímido pede menos)
|
||||
if (dia and perto and not sozinho and agora - self.pediu_em > INTERVALO_PEDIDO
|
||||
and self.acaso.random() < 0.25 * (1.3 - self.personalidade['timidez'])):
|
||||
pedido = self.pedir_algo(agora)
|
||||
if pedido:
|
||||
return pedido
|
||||
if dia and folga and sozinho and self.rng.random() < 0.4:
|
||||
self.porque = 'ninguém por perto há %s: vai cuidar da vida dele' % self.tempo(agora - self.visto_em)
|
||||
return self.comecar_atividade(agora, self.escolher_atividade(), self.rng.uniform(60, 180))
|
||||
# bem: de vez em quando, uma atividade curtinha por vontade própria
|
||||
if dia and folga and humor in ('feliz', 'tranquilo') and self.rng.random() < 0.1:
|
||||
self.porque = 'de bem (%s): vontade própria' % humor
|
||||
return self.comecar_atividade(agora, self.escolher_atividade(), self.rng.uniform(40, 90))
|
||||
# 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):
|
||||
self.porque = 'teve uma ideia (até %d figurinhas por dia)' % self.config['max_emojis_dia']
|
||||
return 'figurinha'
|
||||
# às vezes lembra de uma reação da biblioteca
|
||||
if self.treinamento is not None and humor in ('feliz', 'tranquilo', 'entediado') and self.rng.random() < 0.15:
|
||||
if self.tocar_reacao(agora):
|
||||
with self.lock:
|
||||
n['diversao'] = _limitar(n['diversao'] + 8)
|
||||
self.porque = 'humor %s: lembrou de uma reação da biblioteca' % humor
|
||||
return 'reacao'
|
||||
lista = ATOS['carente_perto'] if humor == 'carente' and perto else ATOS.get(humor, ATOS['tranquilo'])
|
||||
if sozinho: # sem plateia: nada de acenar ou ficar tímido
|
||||
lista = [a for a in lista if a[0] not in PARA_ALGUEM] or ATOS['tranquilo'][:3]
|
||||
gesto, texto = self.escolher(lista)
|
||||
self.porque = 'humor %s%s%s' % (
|
||||
humor, ' com gente por perto' if perto else ', sozinho' if sozinho else '',
|
||||
'; gosto %.1f×, jeito %.1f×' % (self.gosto(gesto), self.jeito(gesto))
|
||||
if (self.gosto(gesto), round(self.jeito(gesto), 1)) != (1.0, 1.0) else '')
|
||||
if self.aprendizado and perto:
|
||||
self.aprendizado.escolheu(gesto, agora)
|
||||
self.enfileirar(gesto)
|
||||
@@ -588,6 +766,21 @@ class Vida:
|
||||
self.sono_profundo = False
|
||||
self.enfileirar('sono leve')
|
||||
self.anotar('sono', 'Acordou antes de descansar', agora)
|
||||
perto = self.alguem_perto()
|
||||
if perto:
|
||||
if not self.perto_antes:
|
||||
self.reencontro(agora, agora - self.ultimo_perto)
|
||||
self.ultimo_perto = agora
|
||||
self.perto_antes = perto
|
||||
if self.desistencia and agora >= self.desistencia[0]:
|
||||
_, oque = self.desistencia
|
||||
self.desistencia = None
|
||||
if not self.dormindo():
|
||||
self.enfileirar('bocejar')
|
||||
acao = oque[4:] if oque.startswith('Foi ') else 'a atividade'
|
||||
texto = 'Largou no meio: cansou de ' + acao
|
||||
self.anotar('acao', texto, agora)
|
||||
self.console('vida', texto, 'perdeu a graça (curiosidade %.2f)' % self.personalidade['curiosidade'], agora=agora)
|
||||
if not self.bloqueado():
|
||||
# o celular escolhe os gestos soltos pelo humor; reenvia de tempos em tempos (pode ter reiniciado)
|
||||
zanga = self.zanga()
|
||||
@@ -600,8 +793,14 @@ class Vida:
|
||||
self.humor_enviado = (humor, agora)
|
||||
self.zanga_enviada = zanga
|
||||
if agora >= self.proximo_ato:
|
||||
antes = self.diario[0]['horario'] if self.diario else None
|
||||
ato = self.agir(agora)
|
||||
self.aprender_ato(ato, agora)
|
||||
if ato:
|
||||
novo = self.diario[0] if self.diario and self.diario[0]['horario'] != antes else None
|
||||
self.ultima = dict(horario=agora, texto=novo['texto'] if novo else ato, porque=self.porque)
|
||||
self.console('vida', novo['texto'] if novo else ato,
|
||||
(self.porque + ' · ' if self.porque else '') + self.resumo(), agora=agora)
|
||||
lo, hi = RITMOS[self.config['ritmo']]
|
||||
self.proximo_ato = agora + self.rng.uniform(lo, hi)
|
||||
if ato or agora - self.publicado_em > 30 or humor != self.humor():
|
||||
|
||||
Reference in New Issue
Block a user