diff --git a/COMPANERO.md b/COMPANERO.md
index a40e9ae9..6d1b7537 100644
--- a/COMPANERO.md
+++ b/COMPANERO.md
@@ -85,6 +85,7 @@ Los consumibles no suman a ese total: cuestan de 5 a 15 y son opcionales.
- **Vínculo:** +1 por cada cuidado y +3 extra al cumplir el deseo de la visita. Una misma acción gratuita suma como mucho una vez cada 30 segundos, pero se puede hacer siempre.
- **Cinco niveles**, a los 0, 10, 25, 50 y 100 puntos. El 100 es el máximo y se muestra desde el principio.
- **Un deseo por visita**, distinto del de la visita anterior: probar una comida, un baño de burbujas, algo nuevo para ponerse, jugar o caricias. Primero se elige el tipo, todos igual de probables, y después cuál comida: así las siete comidas no acaparan los deseos.
+- **Ganas (#39):** de comer, de jugar y de bañarse, de 0 a 3. Suben una cada 3, 4 y 5 partidas terminadas en toda la app (leídas de las estadísticas del núcleo, que el compañero nunca escribe). **Crecen jugando, nunca por el tiempo fuera:** un año sin jugar las deja como estaban. En 3, el globo lo dice («¡Uf, tanto mirarte jugar me abrió el apetito!») y la cara es antojada. Atenderlas las baja a 0, y si estaban en 2 o más suman +2 de vínculo. Si nadie las atiende no pasa nada.
- **Tocarlo:** responde con risa, guiño, sonrojo o un giro, nunca dos veces seguidas igual, y vuelve a mostrar su deseo. Cinco toques en 3 segundos lo marean un momento: es un gesto gracioso, no un castigo. Suma vínculo con la regla de 30 segundos y no da monedas.
- **Escenas:** comer lleva la comida a la boca, el jabón da un baño de burbujas y jugar trae una pelota que rebota. Al comer mastica («ñam») y en el baño se sonroja. Con movimiento reducido se ve la misma escena, quieta.
@@ -102,6 +103,7 @@ Todo se guarda en el teléfono, bajo `chogan.companero.`:
| Decisión | Por qué |
|---|---|
| Deseos en vez de necesidades | Las mascotas virtuales suelen enganchar con culpa; Capybara promete no hacerlo. |
+| Ganas que crecen jugando, no esperando | El compañero reacciona a lo que hacés sin castigar a quien no entra (decisión del 2026-11-03). |
| El compañero es una entrada más de `games.json` | El núcleo queda intacto y sincronizar con el original no da conflictos. |
| Lógica pura en módulos propios (`economia.js`, `cuidado.js`, `disenos.js`, `prendas.js`, `expresiones.js`) | Se prueba sin navegador, con el reloj y el azar simulados. |
| Una sola fuente para la app y el arte | `design/companero/` usa los mismos módulos, así lo aprobado es exactamente lo que se ve. |
diff --git a/tools/test-companero.js b/tools/test-companero.js
index d58375d9..807d46ae 100644
--- a/tools/test-companero.js
+++ b/tools/test-companero.js
@@ -318,9 +318,11 @@ function companero(o) {
const x = nuevo({ saldo: o.saldo === undefined ? 500 : o.saldo, datos: o.datos });
let t = o.t || 1e12;
let dado = o.dado || (() => 0);
- const crearCuidado = () => K.crear({ store: x.s, economia: x.eco, ahora: () => t, azar: () => dado() });
+ // the games finished in the whole app, as the core counts them (C.stats.get().plays)
+ let jugadas = o.partidas || 0;
+ const crearCuidado = () => K.crear({ store: x.s, economia: x.eco, ahora: () => t, azar: () => dado(), partidas: () => jugadas });
const c = crearCuidado();
- return Object.assign(x, { c, crearCuidado, pasar(ms) { t += ms; }, dado(f) { dado = f; } });
+ return Object.assign(x, { c, crearCuidado, pasar(ms) { t += ms; }, dado(f) { dado = f; }, jugar(n) { jugadas += n; } });
}
function testCuidadoLogica() {
@@ -574,7 +576,7 @@ function testDeseosSinCarencia() {
zh: ['饿', '伤心', '难过', '脏', '孤单', '寂寞', '想你'],
fa: ['گرسنه', 'غمگین', 'ناراحت', 'کثیف', 'تنها', 'دلتنگ'],
};
- const claves = (K ? K.DESEOS.map((d) => 'deseo_' + d.id) : []).concat(['deseoCumplido']);
+ const claves = (K ? K.DESEOS.map((d) => 'deseo_' + d.id) : []).concat(['deseoCumplido', 'gana_comer', 'gana_jugar', 'gana_banio']);
for (const l of Object.keys(PROHIBIDAS)) {
const textos = claves.map((k) => T[l] && T[l][k]);
ok(textos.every((x) => typeof x === 'string' && x.length > 2), l + ': cada deseo tiene su texto');
@@ -1003,6 +1005,65 @@ async function testRopaNueva() {
});
}
+/* ------------------------------------------------ wanting things, as you play (#39) */
+
+function testGanas() {
+ head('Ganas de comer, jugar y bañarse: crecen jugando, nunca por ausencia (#39)');
+ if (!K || !K.GANAS) return ok(false, 'cuidado.js exporta GANAS');
+ ok(JSON.stringify(K.GANAS) === JSON.stringify({ comer: 3, jugar: 4, banio: 5 }), 'una gana sube cada 3 partidas (comer), 4 (jugar) y 5 (bañarse)');
+ const x = companero({ saldo: 200, partidas: 40 });
+ ok(JSON.stringify(x.c.ganas()) === '{"comer":0,"jugar":0,"banio":0}', 'un perfil que ya jugaba empieza con las ganas en 0, no con las partidas de antes');
+ x.jugar(3);
+ ok(x.c.ganas().comer === 1 && x.c.ganas().jugar === 0, 'tras 3 partidas: comer 1, jugar 0');
+ x.jugar(2);
+ ok(JSON.stringify(x.c.ganas()) === '{"comer":1,"jugar":1,"banio":1}', 'tras 5: las tres en 1');
+ x.jugar(30);
+ ok(JSON.stringify(x.c.ganas()) === '{"comer":3,"jugar":3,"banio":3}', 'tras 35: las tres en 3, el tope');
+ x.pasar(365 * 864e5);
+ ok(JSON.stringify(x.crearCuidado().ganas()) === '{"comer":3,"jugar":3,"banio":3}', 'un año después siguen en 3: nunca bajan solas');
+
+ const v0 = x.c.vinculo().puntos;
+ x.eco.comprar('galleta');
+ const r = x.c.alimentar('galleta');
+ ok(x.c.ganas().comer === 0 && x.c.ganas().jugar === 3, 'cualquier comida baja «comer» a 0, y nada más');
+ ok(r.atendio === 'comer' && x.c.vinculo().puntos === v0 + 1 + 2, 'atender una gana en 2 o más suma +2 de vínculo extra (' + v0 + ' → ' + x.c.vinculo().puntos + ')');
+ x.c.hecho({ accion: 'jugar' });
+ x.eco.comprar('jabon'); x.c.alimentar('jabon');
+ ok(JSON.stringify(x.c.ganas()) === '{"comer":0,"jugar":0,"banio":0}', 'jugar baja «jugar» y el jabón, «bañarse»');
+ x.jugar(3); const v1 = x.c.vinculo().puntos;
+ x.pasar(31000); x.eco.comprar('fruta'); x.c.alimentar('fruta');
+ ok(x.c.vinculo().puntos === v1 + 1, 'una gana en 1 no da el extra');
+
+ const y = companero({ partidas: 0 });
+ y.pasar(365 * 864e5);
+ ok(JSON.stringify(y.crearCuidado().ganas()) === '{"comer":0,"jugar":0,"banio":0}', 'un año sin jugar: las ganas siguen en 0');
+ const z = companero({ partidas: 0 });
+ z.jugar(9);
+ ok(z.c.ganaFuerte() === 'comer' && z.c.expresionAlAbrir() === 'antojado', 'con una gana en 3, abre antojado y la gana fuerte es la que más creció (comer)');
+ ok(z.s.escritas.every((k) => k === 'inventario' || k === 'cuidado'), 'las ganas se guardan en «cuidado»: nunca escribe las estadísticas del núcleo');
+ // an old saved care, from before #39, keeps its bond
+ const w = nuevo({ saldo: 10, datos: { cuidado: { version: 1, puntos: 42, ultimas: {}, deseo: null, ultimoDeseo: null } } });
+ const cw = K.crear({ store: w.s, economia: w.eco, partidas: () => 80 });
+ ok(cw.vinculo().puntos === 42 && JSON.stringify(cw.ganas()) === '{"comer":0,"jugar":0,"banio":0}', 'un cuidado guardado antes de #39 conserva su vínculo y empieza con las ganas en 0');
+}
+
+async function testGanasPagina() {
+ head('Las ganas en la página (#39)');
+ await navegador(async ({ abrir, evaluar }) => {
+ await abrir('/games/companero/index.html');
+ await evaluar(preparar({ monedas: 100 }));
+ await evaluar(`localStorage.setItem('chogan.app.stats', JSON.stringify({ plays: 12, timeMs: 0, byGame: {}, streak: { count: 0 } })); localStorage.setItem('chogan.companero.cuidado', JSON.stringify({ version: 1, puntos: 5, ultimas: {}, deseo: null, ultimoDeseo: null, ganas: { comer: 0, jugar: 4, banio: 12 } })); true`);
+ await abrir('/games/companero/index.html');
+ const g = await evaluar(`[...document.querySelectorAll('.cp-gana')].map((x) => x.dataset.gana + ':' + x.dataset.nivel).join()`);
+ ok(g === 'comer:3,jugar:2,banio:0', 'tres indicadores con su nivel: comer 3, jugar 2, bañarse 0 (' + g + ')');
+ ok(await evaluar(`[...document.querySelectorAll('.cp-gana')].every((x) => x.querySelector('svg') && x.getAttribute('aria-label'))`), 'cada indicador tiene su dibujo y un nombre para el lector de pantalla');
+ ok(await evaluar(`document.querySelector('.cp-globo').dataset.gana === 'comer'`) && await evaluar(`document.querySelector('.cp-compa').dataset.expresion === 'antojado'`), 'con ganas de comer en 3, el globo lo dice y la cara es antojada');
+ await evaluar(`document.querySelector('[data-consumible="fruta"]').click(); true`); await evaluar(pausa(200)); await evaluar(aceptar); await evaluar(pausa(200));
+ ok(await evaluar(`document.querySelector('[data-gana="comer"]').dataset.nivel`) === '0', 'al darle de comer, la gana baja a 0');
+ ok(!(await evaluar(`localStorage.getItem('chogan.app.stats')`)).includes('companero'), 'las estadísticas del núcleo quedan intactas');
+ });
+}
+
/* ------------------------------------------------ run */
const GROUPS = [...fs.readFileSync(__filename, 'utf8').matchAll(/^(?:async )?function (test[A-Za-z0-9]+)\(\) \{/gm)].map((m) => m[1]);
diff --git a/www/games/companero/cuidado.js b/www/games/companero/cuidado.js
index d616ab33..e828a21f 100644
--- a/www/games/companero/cuidado.js
+++ b/www/games/companero/cuidado.js
@@ -35,6 +35,10 @@
var POR_CUIDADO = 1, POR_DESEO = 3;
// the same free action adds to the bond at most once in this long; it is never blocked
var ESPERA_MS = 30000;
+ // Wanting things (#39): one level more every this many games finished in the whole app, up to 3.
+ // Games, never time: a year away with no games leaves them as they were.
+ var GANAS = { comer: 3, jugar: 4, banio: 5 };
+ var TOPE = 3, POR_GANA = 2;
function vacio() { return { version: VERSION, puntos: 0, ultimas: {}, deseo: null, ultimoDeseo: null }; }
function sano(d) {
@@ -58,9 +62,28 @@
var store = opts.store, eco = opts.economia;
var ahora = opts.ahora || function () { return Date.now(); };
var azar = opts.azar || Math.random;
+ var partidas = function () { var n = opts.partidas ? opts.partidas() : 0; return typeof n === 'number' && n >= 0 ? Math.floor(n) : 0; };
var d = store.get('cuidado', null);
if (!sano(d)) d = vacio();
+ // each gana keeps the game count it was last tended at; a missing one starts now, so the games
+ // played before #39 never count, and a count above the core's (its stats were erased) comes down
+ if (!d.ganas || typeof d.ganas !== 'object') d.ganas = {};
+ var nuevas = false;
+ Object.keys(GANAS).forEach(function (g) {
+ var b = d.ganas[g];
+ if (typeof b !== 'number' || b < 0 || b > partidas()) { d.ganas[g] = partidas(); nuevas = true; }
+ });
function guardar() { store.set('cuidado', d); }
+ // kept at once: else the next opening would start them over from its own count
+ if (nuevas) guardar();
+ function nivel(g) { return Math.min(TOPE, Math.floor((partidas() - d.ganas[g]) / GANAS[g])); }
+ function ganas() { var r = {}; Object.keys(GANAS).forEach(function (g) { r[g] = nivel(g); }); return r; }
+ // the gana at the top, if any, in a fixed order: the bubble says it and the face shows it
+ function ganaFuerte() {
+ var gs = Object.keys(GANAS);
+ for (var i = 0; i < gs.length; i++) if (nivel(gs[i]) >= TOPE) return gs[i];
+ return null;
+ }
// A visit is each time the space opens: one wish, never the same as the last visit's
function visitar() {
@@ -86,9 +109,17 @@
} else if (ev.usar) suma += POR_CUIDADO;
var cumplio = !!(d.deseo && !d.deseo.cumplido && cumple(d.deseo, ev));
if (cumplio) { d.deseo.cumplido = true; suma += POR_DESEO; }
+ // tending a gana brings it back to 0, with a little extra when it had grown
+ var gana = ev.usar === 'jabon' ? 'banio' : ev.usar ? 'comer' : ev.accion === 'jugar' || ev.juego ? 'jugar' : null;
+ var atendio = null;
+ if (gana) {
+ if (nivel(gana) >= 2) suma += POR_GANA;
+ if (nivel(gana) > 0) atendio = gana;
+ d.ganas[gana] = partidas();
+ }
d.puntos = Math.min(MAXIMO, d.puntos + suma);
guardar();
- return { ok: true, suma: suma, cumplioDeseo: cumplio };
+ return { ok: true, suma: suma, cumplioDeseo: cumplio, atendio: atendio };
}
// Feeding or a bubble bath: uses one unit from the economy, then counts as care
@@ -105,10 +136,11 @@
}
// The face on opening depends only on the visit's wish, never on time away
- function expresionAlAbrir() { return d.deseo && !d.deseo.cumplido ? 'antojado' : 'contento'; }
+ function expresionAlAbrir() { return (d.deseo && !d.deseo.cumplido) || ganaFuerte() ? 'antojado' : 'contento'; }
- return { visitar: visitar, deseo: deseo, hecho: hecho, alimentar: alimentar, vinculo: vinculo, expresionAlAbrir: expresionAlAbrir };
+ return { visitar: visitar, deseo: deseo, hecho: hecho, alimentar: alimentar, vinculo: vinculo, expresionAlAbrir: expresionAlAbrir,
+ ganas: ganas, ganaFuerte: ganaFuerte };
}
- return { VERSION: VERSION, DESEOS: DESEOS, ACCIONES: ACCIONES, NIVELES: NIVELES, MAXIMO: MAXIMO, crear: crear };
+ return { VERSION: VERSION, DESEOS: DESEOS, ACCIONES: ACCIONES, NIVELES: NIVELES, MAXIMO: MAXIMO, GANAS: GANAS, crear: crear };
});
diff --git a/www/games/companero/index.html b/www/games/companero/index.html
index fc9286e7..6cb8c236 100644
--- a/www/games/companero/index.html
+++ b/www/games/companero/index.html
@@ -47,6 +47,12 @@
@media (prefers-reduced-motion: reduce) { .cp-globo { transition: none; } }
.cp-globo[data-cumplido="1"] { border: 2px solid var(--game); }
.cp-vinculo { margin: 0; text-align: center; font-size: .9rem; }
+ /* three small gauges of what it wants (#39): an icon and three dots */
+ .cp-ganas { display: flex; gap: var(--s-3); justify-content: center; }
+ .cp-gana { display: flex; align-items: center; gap: 3px; }
+ .cp-gana svg { width: 18px; height: 18px; }
+ .cp-punto { width: 6px; height: 6px; border-radius: 50%; background: var(--c-line); }
+ .cp-punto--on { background: var(--game); }
.cp-corazones { color: #D7263D; letter-spacing: 2px; }
.cp-accion { min-height: 56px; justify-content: center; font-weight: 600; }
@keyframes cp-salto { 0%, 100% { transform: translateY(0); } 40% { transform: translateY(-8%); } }
@@ -89,35 +95,35 @@
/* ==== TEXTOS START ==== */
var TEXTOS = {
- fa: { p_diadema: 'تل سر', p_mono: 'پاپیون بزرگ', p_perlas: 'گردنبند مروارید', p_vestido: 'پیراهن گلدار', p_gala: 'لباس مهمانی', p_falda: 'دامن', p_zapatillas: 'کفش ورزشی', p_botas: 'چکمه', p_sandalias: 'صندل', e_pies: 'پا', c_sandia: 'هندوانه', c_galleta: 'کلوچه', c_helado: 'بستنی', c_te: 'دمنوش', deseo_sandia: 'دوست دارم هندوانه امتحان کنم!', deseo_galleta: 'یک کلوچه چه خوب میشد!', deseo_helado: 'یک بستنی چه کیفی دارد!', deseo_te: 'یک دمنوش بنوشیم؟', verDeseo: 'دیدن آرزویش', acariciar: 'نوازش', cepillar: 'برس زدن', jugar: 'بازی', c_fruta: 'میوه', c_zanahoria: 'هویج', c_pastel: 'کیک', c_jabon: 'صابون حباب', cantidad: '×{n}', vinculo: 'پیوند: سطح {n} از {m}', deseoCumplido: 'ممنون! خیلی دوستش داشتم.', deseo_fruta: 'دوست دارم میوه امتحان کنم!', deseo_zanahoria: 'دوست دارم هویج امتحان کنم!', deseo_pastel: 'یک کیک چه خوب میشد!', deseo_banio: 'یک حمام کف چه کیفی دارد!', deseo_ropa: 'با یک لباس تازه قشنگ میشوم!', deseo_jugar: 'بیا کمی بازی کنیم!', deseo_caricias: 'نوازشم میکنی؟',
+ fa: { gana_comer: 'این همه بازی، اشتهایم را باز کرد!', gana_jugar: 'دیدن بازیات، من را هم هوس بازی انداخت!', gana_banio: 'یک حمام کف الان چه میچسبد!', ganaNivel_comer: 'میل به خوردن: {n} از ۳', ganaNivel_jugar: 'میل به بازی: {n} از ۳', ganaNivel_banio: 'میل به حمام: {n} از ۳', p_diadema: 'تل سر', p_mono: 'پاپیون بزرگ', p_perlas: 'گردنبند مروارید', p_vestido: 'پیراهن گلدار', p_gala: 'لباس مهمانی', p_falda: 'دامن', p_zapatillas: 'کفش ورزشی', p_botas: 'چکمه', p_sandalias: 'صندل', e_pies: 'پا', c_sandia: 'هندوانه', c_galleta: 'کلوچه', c_helado: 'بستنی', c_te: 'دمنوش', deseo_sandia: 'دوست دارم هندوانه امتحان کنم!', deseo_galleta: 'یک کلوچه چه خوب میشد!', deseo_helado: 'یک بستنی چه کیفی دارد!', deseo_te: 'یک دمنوش بنوشیم؟', verDeseo: 'دیدن آرزویش', acariciar: 'نوازش', cepillar: 'برس زدن', jugar: 'بازی', c_fruta: 'میوه', c_zanahoria: 'هویج', c_pastel: 'کیک', c_jabon: 'صابون حباب', cantidad: '×{n}', vinculo: 'پیوند: سطح {n} از {m}', deseoCumplido: 'ممنون! خیلی دوستش داشتم.', deseo_fruta: 'دوست دارم میوه امتحان کنم!', deseo_zanahoria: 'دوست دارم هویج امتحان کنم!', deseo_pastel: 'یک کیک چه خوب میشد!', deseo_banio: 'یک حمام کف چه کیفی دارد!', deseo_ropa: 'با یک لباس تازه قشنگ میشوم!', deseo_jugar: 'بیا کمی بازی کنیم!', deseo_caricias: 'نوازشم میکنی؟',
p_gorra: 'کلاه', p_corona: 'تاج', p_lentes: 'عینک', p_lazo: 'پاپیون', p_panuelo: 'دستمال گردن', p_sueter: 'پلیور', p_capa: 'شنل', e_cabeza: 'سر', e_cuello: 'گردن', e_cuerpo: 'بدن', ninguna: 'هیچکدام', ariaPrecio: '{nombre}، {precio}', ariaTuyo: '{nombre}، مال توست', ariaEnUso: '{nombre}، در حال استفاده', ariaPerfil: '{nombre}، در نمایه باز میشود',
d_natural: 'طبیعی', d_medianoche: 'نیمهشب', d_arcoiris: 'رنگینکمان', d_manchitas: 'خالخالی', d_rayas: 'راهراه', d_dorado: 'طلایی',
desbloquear: 'با {n} سکه باز شود؟', desbloquearBtn: 'باز کردن', faltan: '{n} سکه کم داری', jugarParaGanar: 'یک بازی کن تا سکه بگیری.', enPerfil: 'در نمایه باز میشود', precio: '{n} سکه', tuyo: 'مال توست',
monedas: 'سکه', animales: 'حیوانها', colores: 'رنگها', ropa: 'لباسها', cuidado: 'مراقبت',
cargando: 'همراهت را آماده میکنیم…', vacio: 'هنوز اینجا چیزی نیست.', sinMonedas: 'هنوز سکه نداری. یک بازی کن تا سکه بگیری.', equipado: 'در حال استفاده',
a_fox: 'روباه', a_owl: 'جغد', a_cat: 'گربه', a_bear: 'خرس', a_capybara: 'کاپیبارا', a_conejo: 'خرگوش', a_panda: 'پاندا', a_nutria: 'سمور آبی' },
- en: { p_diadema: 'Headband', p_mono: 'Big bow', p_perlas: 'Pearls', p_vestido: 'Flower dress', p_gala: 'Party dress', p_falda: 'Skirt', p_zapatillas: 'Sneakers', p_botas: 'Boots', p_sandalias: 'Sandals', e_pies: 'Feet', c_sandia: 'Watermelon', c_galleta: 'Cookie', c_helado: 'Ice cream', c_te: 'Herbal tea', deseo_sandia: 'I would love to try some watermelon!', deseo_galleta: 'A cookie would be lovely!', deseo_helado: 'I would love an ice cream!', deseo_te: 'Shall we have some herbal tea?', verDeseo: 'See its wish', acariciar: 'Pet', cepillar: 'Brush', jugar: 'Play', c_fruta: 'Fruit', c_zanahoria: 'Carrot', c_pastel: 'Cake', c_jabon: 'Bubble soap', cantidad: '×{n}', vinculo: 'Bond: level {n} of {m}', deseoCumplido: 'Thank you! I loved it.', deseo_fruta: 'I would love to try some fruit!', deseo_zanahoria: 'I would love to try the carrot!', deseo_pastel: 'A cake would be lovely!', deseo_banio: 'I would love a bubble bath!', deseo_ropa: 'Something new to wear would look nice on me!', deseo_jugar: 'Let us play for a bit!', deseo_caricias: 'Could I have a cuddle?',
+ en: { gana_comer: 'All that playing gave me an appetite!', gana_jugar: 'Watching you play makes me want to play too!', gana_banio: 'A bubble bath would feel so nice!', ganaNivel_comer: 'Wants to eat: {n} of 3', ganaNivel_jugar: 'Wants to play: {n} of 3', ganaNivel_banio: 'Wants a bath: {n} of 3', p_diadema: 'Headband', p_mono: 'Big bow', p_perlas: 'Pearls', p_vestido: 'Flower dress', p_gala: 'Party dress', p_falda: 'Skirt', p_zapatillas: 'Sneakers', p_botas: 'Boots', p_sandalias: 'Sandals', e_pies: 'Feet', c_sandia: 'Watermelon', c_galleta: 'Cookie', c_helado: 'Ice cream', c_te: 'Herbal tea', deseo_sandia: 'I would love to try some watermelon!', deseo_galleta: 'A cookie would be lovely!', deseo_helado: 'I would love an ice cream!', deseo_te: 'Shall we have some herbal tea?', verDeseo: 'See its wish', acariciar: 'Pet', cepillar: 'Brush', jugar: 'Play', c_fruta: 'Fruit', c_zanahoria: 'Carrot', c_pastel: 'Cake', c_jabon: 'Bubble soap', cantidad: '×{n}', vinculo: 'Bond: level {n} of {m}', deseoCumplido: 'Thank you! I loved it.', deseo_fruta: 'I would love to try some fruit!', deseo_zanahoria: 'I would love to try the carrot!', deseo_pastel: 'A cake would be lovely!', deseo_banio: 'I would love a bubble bath!', deseo_ropa: 'Something new to wear would look nice on me!', deseo_jugar: 'Let us play for a bit!', deseo_caricias: 'Could I have a cuddle?',
p_gorra: 'Cap', p_corona: 'Crown', p_lentes: 'Glasses', p_lazo: 'Bow', p_panuelo: 'Bandana', p_sueter: 'Sweater', p_capa: 'Cape', e_cabeza: 'Head', e_cuello: 'Neck', e_cuerpo: 'Body', ninguna: 'None', ariaPrecio: '{nombre}, {precio}', ariaTuyo: '{nombre}, yours', ariaEnUso: '{nombre}, in use', ariaPerfil: '{nombre}, unlocked in your profile',
d_natural: 'Natural', d_medianoche: 'Midnight', d_arcoiris: 'Soft rainbow', d_manchitas: 'Spots', d_rayas: 'Stripes', d_dorado: 'Golden',
desbloquear: 'Unlock for {n} coins?', desbloquearBtn: 'Unlock', faltan: 'You need {n} more coins', jugarParaGanar: 'Play a game to earn some.', enPerfil: 'Unlocked in your profile', precio: '{n} coins', tuyo: 'Yours',
monedas: 'Coins', animales: 'Animals', colores: 'Colours', ropa: 'Clothes', cuidado: 'Care',
cargando: 'Getting your companion ready…', vacio: 'Nothing here yet.', sinMonedas: 'You have no coins yet. Play a game to earn some.', equipado: 'In use',
a_fox: 'Fox', a_owl: 'Owl', a_cat: 'Cat', a_bear: 'Bear', a_capybara: 'Capybara', a_conejo: 'Rabbit', a_panda: 'Panda', a_nutria: 'Otter' },
- zh: { p_diadema: '发箍', p_mono: '大蝴蝶结', p_perlas: '珍珠项链', p_vestido: '碎花裙', p_gala: '礼服裙', p_falda: '短裙', p_zapatillas: '运动鞋', p_botas: '靴子', p_sandalias: '凉鞋', e_pies: '脚', c_sandia: '西瓜', c_galleta: '饼干', c_helado: '冰淇淋', c_te: '花草茶', deseo_sandia: '我想尝尝西瓜!', deseo_galleta: '来块饼干就太好了!', deseo_helado: '我好想吃冰淇淋!', deseo_te: '我们来喝杯花草茶吧?', verDeseo: '看看它的心愿', acariciar: '抚摸', cepillar: '梳毛', jugar: '玩耍', c_fruta: '水果', c_zanahoria: '胡萝卜', c_pastel: '蛋糕', c_jabon: '泡泡皂', cantidad: '×{n}', vinculo: '亲密度:第 {n} 级,共 {m} 级', deseoCumplido: '谢谢!我好喜欢。', deseo_fruta: '我想尝尝水果!', deseo_zanahoria: '我想尝尝胡萝卜!', deseo_pastel: '来块蛋糕就太好了!', deseo_banio: '我想泡个泡泡浴!', deseo_ropa: '穿点新衣服一定很好看!', deseo_jugar: '我们来玩一会儿吧!', deseo_caricias: '可以摸摸我吗?',
+ zh: { gana_comer: '看你玩得这么开心,我也想吃点东西啦!', gana_jugar: '看你玩,我也想玩啦!', gana_banio: '好想泡个泡泡浴呀!', ganaNivel_comer: '想吃东西:{n}/3', ganaNivel_jugar: '想玩耍:{n}/3', ganaNivel_banio: '想洗澡:{n}/3', p_diadema: '发箍', p_mono: '大蝴蝶结', p_perlas: '珍珠项链', p_vestido: '碎花裙', p_gala: '礼服裙', p_falda: '短裙', p_zapatillas: '运动鞋', p_botas: '靴子', p_sandalias: '凉鞋', e_pies: '脚', c_sandia: '西瓜', c_galleta: '饼干', c_helado: '冰淇淋', c_te: '花草茶', deseo_sandia: '我想尝尝西瓜!', deseo_galleta: '来块饼干就太好了!', deseo_helado: '我好想吃冰淇淋!', deseo_te: '我们来喝杯花草茶吧?', verDeseo: '看看它的心愿', acariciar: '抚摸', cepillar: '梳毛', jugar: '玩耍', c_fruta: '水果', c_zanahoria: '胡萝卜', c_pastel: '蛋糕', c_jabon: '泡泡皂', cantidad: '×{n}', vinculo: '亲密度:第 {n} 级,共 {m} 级', deseoCumplido: '谢谢!我好喜欢。', deseo_fruta: '我想尝尝水果!', deseo_zanahoria: '我想尝尝胡萝卜!', deseo_pastel: '来块蛋糕就太好了!', deseo_banio: '我想泡个泡泡浴!', deseo_ropa: '穿点新衣服一定很好看!', deseo_jugar: '我们来玩一会儿吧!', deseo_caricias: '可以摸摸我吗?',
p_gorra: '鸭舌帽', p_corona: '王冠', p_lentes: '眼镜', p_lazo: '蝴蝶结', p_panuelo: '领巾', p_sueter: '毛衣', p_capa: '斗篷', e_cabeza: '头部', e_cuello: '颈部', e_cuerpo: '身体', ninguna: '不穿', ariaPrecio: '{nombre},{precio}', ariaTuyo: '{nombre},已拥有', ariaEnUso: '{nombre},使用中', ariaPerfil: '{nombre},在个人资料中解锁',
d_natural: '自然', d_medianoche: '午夜', d_arcoiris: '柔和彩虹', d_manchitas: '斑点', d_rayas: '条纹', d_dorado: '金色',
desbloquear: '花 {n} 金币解锁?', desbloquearBtn: '解锁', faltan: '还差 {n} 金币', jugarParaGanar: '玩一局就能赚到。', enPerfil: '在个人资料中解锁', precio: '{n} 金币', tuyo: '已拥有',
monedas: '金币', animales: '动物', colores: '颜色', ropa: '服装', cuidado: '照顾',
cargando: '正在准备你的伙伴……', vacio: '这里还没有东西。', sinMonedas: '你还没有金币。玩一局就能赚到。', equipado: '使用中',
a_fox: '狐狸', a_owl: '猫头鹰', a_cat: '猫', a_bear: '熊', a_capybara: '水豚', a_conejo: '兔子', a_panda: '熊猫', a_nutria: '水獭' },
- de: { p_diadema: 'Haarreif', p_mono: 'Große Schleife', p_perlas: 'Perlen', p_vestido: 'Blumen\u00ADkleid', p_gala: 'Fest\u00ADkleid', p_falda: 'Rock', p_zapatillas: 'Turn\u00ADschuhe', p_botas: 'Stiefel', p_sandalias: 'Sandalen', e_pies: 'Füße', c_sandia: 'Wasser\u00ADmelone', c_galleta: 'Keks', c_helado: 'Eis', c_te: 'Kräuter\u00ADtee', deseo_sandia: 'Ich würde gern Wassermelone probieren!', deseo_galleta: 'Ein Keks wäre toll!', deseo_helado: 'Ein Eis wäre herrlich!', deseo_te: 'Trinken wir einen Kräutertee?', verDeseo: 'Seinen Wunsch zeigen', acariciar: 'Streicheln', cepillar: 'Bürsten', jugar: 'Spielen', c_fruta: 'Obst', c_zanahoria: 'Karotte', c_pastel: 'Kuchen', c_jabon: 'Schaumseife', cantidad: '×{n}', vinculo: 'Bindung: Stufe {n} von {m}', deseoCumplido: 'Danke! Das hat mir gefallen.', deseo_fruta: 'Ich würde gern ein Stück Obst probieren!', deseo_zanahoria: 'Ich würde gern die Karotte probieren!', deseo_pastel: 'Ein Kuchen wäre toll!', deseo_banio: 'Ein Schaumbad wäre herrlich!', deseo_ropa: 'Etwas Neues zum Anziehen stünde mir gut!', deseo_jugar: 'Lass uns ein bisschen spielen!', deseo_caricias: 'Streichelst du mich ein wenig?',
+ de: { gana_comer: 'Vom Zuschauen hab ich Appetit bekommen!', gana_jugar: 'Beim Zuschauen will ich auch spielen!', gana_banio: 'Ein Schaumbad wäre jetzt schön!', ganaNivel_comer: 'Lust auf Essen: {n} von 3', ganaNivel_jugar: 'Lust zu spielen: {n} von 3', ganaNivel_banio: 'Lust auf ein Bad: {n} von 3', p_diadema: 'Haarreif', p_mono: 'Große Schleife', p_perlas: 'Perlen', p_vestido: 'Blumen\u00ADkleid', p_gala: 'Fest\u00ADkleid', p_falda: 'Rock', p_zapatillas: 'Turn\u00ADschuhe', p_botas: 'Stiefel', p_sandalias: 'Sandalen', e_pies: 'Füße', c_sandia: 'Wasser\u00ADmelone', c_galleta: 'Keks', c_helado: 'Eis', c_te: 'Kräuter\u00ADtee', deseo_sandia: 'Ich würde gern Wassermelone probieren!', deseo_galleta: 'Ein Keks wäre toll!', deseo_helado: 'Ein Eis wäre herrlich!', deseo_te: 'Trinken wir einen Kräutertee?', verDeseo: 'Seinen Wunsch zeigen', acariciar: 'Streicheln', cepillar: 'Bürsten', jugar: 'Spielen', c_fruta: 'Obst', c_zanahoria: 'Karotte', c_pastel: 'Kuchen', c_jabon: 'Schaumseife', cantidad: '×{n}', vinculo: 'Bindung: Stufe {n} von {m}', deseoCumplido: 'Danke! Das hat mir gefallen.', deseo_fruta: 'Ich würde gern ein Stück Obst probieren!', deseo_zanahoria: 'Ich würde gern die Karotte probieren!', deseo_pastel: 'Ein Kuchen wäre toll!', deseo_banio: 'Ein Schaumbad wäre herrlich!', deseo_ropa: 'Etwas Neues zum Anziehen stünde mir gut!', deseo_jugar: 'Lass uns ein bisschen spielen!', deseo_caricias: 'Streichelst du mich ein wenig?',
p_gorra: 'Kappe', p_corona: 'Krone', p_lentes: 'Brille', p_lazo: 'Schleife', p_panuelo: 'Halstuch', p_sueter: 'Pullover', p_capa: 'Umhang', e_cabeza: 'Kopf', e_cuello: 'Hals', e_cuerpo: 'Körper', ninguna: 'Nichts', ariaPrecio: '{nombre}, {precio}', ariaTuyo: '{nombre}, gehört dir', ariaEnUso: '{nombre}, in Gebrauch', ariaPerfil: '{nombre}, im Profil freischaltbar',
d_natural: 'Natur', d_medianoche: 'Mitternacht', d_arcoiris: 'Sanfter Regenbogen', d_manchitas: 'Tupfen', d_rayas: 'Streifen', d_dorado: 'Golden',
desbloquear: 'Für {n} Münzen freischalten?', desbloquearBtn: 'Freischalten', faltan: 'Dir fehlen {n} Münzen', jugarParaGanar: 'Spiel eine Runde, um welche zu verdienen.', enPerfil: 'Im Profil freischaltbar', precio: '{n} Münzen', tuyo: 'Deins',
monedas: 'Münzen', animales: 'Tiere', colores: 'Farben', ropa: 'Kleidung', cuidado: 'Pflege',
cargando: 'Dein Begleiter wird vorbereitet …', vacio: 'Hier ist noch nichts.', sinMonedas: 'Du hast noch keine Münzen. Spiel eine Runde, um welche zu verdienen.', equipado: 'In Gebrauch',
a_fox: 'Fuchs', a_owl: 'Eule', a_cat: 'Katze', a_bear: 'Bär', a_capybara: 'Wasser\u00ADschwein', a_conejo: 'Hase', a_panda: 'Panda', a_nutria: 'Otter' },
- es: { p_diadema: 'Diadema', p_mono: 'Moño', p_perlas: 'Perlas', p_vestido: 'Vestido de flores', p_gala: 'Vestido de fiesta', p_falda: 'Falda', p_zapatillas: 'Zapatillas', p_botas: 'Botas', p_sandalias: 'Sandalias', e_pies: 'Pies', c_sandia: 'Sandía', c_galleta: 'Galleta', c_helado: 'Helado', c_te: 'Té de hierbas', deseo_sandia: '¡Me gustaría probar la sandía!', deseo_galleta: '¡Qué rica sería una galleta!', deseo_helado: '¡Me encantaría un helado!', deseo_te: '¿Tomamos un té de hierbas?', verDeseo: 'Ver su deseo', acariciar: 'Acariciar', cepillar: 'Cepillar', jugar: 'Jugar', c_fruta: 'Fruta', c_zanahoria: 'Zanahoria', c_pastel: 'Pastel', c_jabon: 'Jabón de burbujas', cantidad: '×{n}', vinculo: 'Vínculo: nivel {n} de {m}', deseoCumplido: '¡Gracias! Me encantó.', deseo_fruta: '¡Me gustaría probar una fruta!', deseo_zanahoria: '¡Me gustaría probar la zanahoria!', deseo_pastel: '¡Qué rico sería un pastel!', deseo_banio: '¡Me encantaría un baño de burbujas!', deseo_ropa: '¡Me vería bien con algo nuevo!', deseo_jugar: '¡Juguemos un rato!', deseo_caricias: '¿Me das unas caricias?',
+ es: { gana_comer: '¡Uf, tanto mirarte jugar me abrió el apetito!', gana_jugar: '¡Mirarte jugar me dio ganas de jugar a mí!', gana_banio: '¡Qué bien me vendría un baño de burbujas!', ganaNivel_comer: 'Ganas de comer: {n} de 3', ganaNivel_jugar: 'Ganas de jugar: {n} de 3', ganaNivel_banio: 'Ganas de un baño: {n} de 3', p_diadema: 'Diadema', p_mono: 'Moño', p_perlas: 'Perlas', p_vestido: 'Vestido de flores', p_gala: 'Vestido de fiesta', p_falda: 'Falda', p_zapatillas: 'Zapatillas', p_botas: 'Botas', p_sandalias: 'Sandalias', e_pies: 'Pies', c_sandia: 'Sandía', c_galleta: 'Galleta', c_helado: 'Helado', c_te: 'Té de hierbas', deseo_sandia: '¡Me gustaría probar la sandía!', deseo_galleta: '¡Qué rica sería una galleta!', deseo_helado: '¡Me encantaría un helado!', deseo_te: '¿Tomamos un té de hierbas?', verDeseo: 'Ver su deseo', acariciar: 'Acariciar', cepillar: 'Cepillar', jugar: 'Jugar', c_fruta: 'Fruta', c_zanahoria: 'Zanahoria', c_pastel: 'Pastel', c_jabon: 'Jabón de burbujas', cantidad: '×{n}', vinculo: 'Vínculo: nivel {n} de {m}', deseoCumplido: '¡Gracias! Me encantó.', deseo_fruta: '¡Me gustaría probar una fruta!', deseo_zanahoria: '¡Me gustaría probar la zanahoria!', deseo_pastel: '¡Qué rico sería un pastel!', deseo_banio: '¡Me encantaría un baño de burbujas!', deseo_ropa: '¡Me vería bien con algo nuevo!', deseo_jugar: '¡Juguemos un rato!', deseo_caricias: '¿Me das unas caricias?',
p_gorra: 'Gorra', p_corona: 'Corona', p_lentes: 'Lentes', p_lazo: 'Lazo', p_panuelo: 'Pañuelo', p_sueter: 'Suéter', p_capa: 'Capa', e_cabeza: 'Cabeza', e_cuello: 'Cuello', e_cuerpo: 'Cuerpo', ninguna: 'Ninguna', ariaPrecio: '{nombre}, {precio}', ariaTuyo: '{nombre}, tuyo', ariaEnUso: '{nombre}, en uso', ariaPerfil: '{nombre}, se desbloquea en tu perfil',
d_natural: 'Natural', d_medianoche: 'Medianoche', d_arcoiris: 'Arcoíris suave', d_manchitas: 'Manchitas', d_rayas: 'Rayas', d_dorado: 'Dorado',
desbloquear: '¿Desbloquear por {n} monedas?', desbloquearBtn: 'Desbloquear', faltan: 'Te faltan {n} monedas', jugarParaGanar: 'Juega una partida para ganarlas.', enPerfil: 'Se desbloquea en tu perfil', precio: '{n} monedas', tuyo: 'Tuyo',
@@ -147,7 +153,9 @@
nucleo: function () { return { unlocks: C.state.unlocks, mascot: C.state.settings.mascot }; }
});
var ARTE = window.CompaneroArte;
- var K = window.CompaneroCuidado.crear({ store: ctx.store, economia: E });
+ // the games finished in the whole app, read from the core and never written (#39)
+ var K = window.CompaneroCuidado.crear({ store: ctx.store, economia: E,
+ partidas: function () { var st = C.stats && C.stats.get ? C.stats.get() : null; return st && st.plays; } });
K.visitar(); // each opening is a visit: one kind wish, never the last visit's
var CONSUMIBLES = window.CompaneroEconomia.CATALOGO.filter(function (a) { return a.tipo === 'consumible'; }).map(function (a) { return a.id; });
// the face of the moment: the opening one, or a short-lived one after something happens
@@ -204,6 +212,13 @@
compa.appendChild(globo);
compa.appendChild(lienzo);
compa.appendChild(vinculo);
+ var ganasEl = el('div', { class: 'cp-ganas' });
+ compa.appendChild(ganasEl);
+ var ICONO_GANA = {
+ comer: '',
+ jugar: '',
+ banio: ''
+ };
var raiz = el('div', { class: 'cp' }, [
el('div', { class: 'cp-escenario' }, [estado, compa]),
sinMonedas,
@@ -224,12 +239,22 @@
lienzo.innerHTML = dibujo;
compa.dataset.expresion = cara;
- var deseo = K.deseo();
+ var deseo = K.deseo(), fuerte = K.ganaFuerte();
if (deseo) {
globo.dataset.deseo = deseo.id;
globo.dataset.cumplido = deseo.cumplido ? '1' : '0';
globo.textContent = deseo.cumplido ? C.t('deseoCumplido') : C.t('deseo_' + deseo.id);
}
+ // a gana at its top speaks instead of the visit's wish, which stays as it is
+ globo.dataset.gana = fuerte || '';
+ if (fuerte && !(deseo && deseo.cumplido)) globo.textContent = C.t('gana_' + fuerte);
+ var gs = K.ganas();
+ ganasEl.textContent = '';
+ Object.keys(gs).forEach(function (g) {
+ var x = el('span', { class: 'cp-gana', 'data-gana': g, 'data-nivel': String(gs[g]), role: 'img', 'aria-label': C.t('ganaNivel_' + g, { n: C.num(gs[g]) }), html: ICONO_GANA[g] });
+ for (var i = 0; i < 3; i++) x.appendChild(el('span', { class: 'cp-punto' + (i < gs[g] ? ' cp-punto--on' : '') }));
+ ganasEl.appendChild(x);
+ });
var v = K.vinculo();
vinculo.dataset.vinculo = String(v.puntos);
vinculo.textContent = '';