juegos

Juegos de terminal de Pancho: Catan (TUI, GUI, web, servidor, PicoCalc), ajedrez, calculadora y minijuegos
git clone https://git.lu3dhn.xyz/juegos.git
Log | Files | Refs

commit 81d7034e427025f3924725bc6da2f30cab8b11d2
parent e7c053eba5afaaebc3afd07e955b3e2b48175f7f
Author: Francisco Armando Rosmino <franciscorosmino@rosmino.com.ar>
Date:   Sat,  3 Oct 2026 14:47:31 -0300

Oro para el que no tiene el turno, puntitos en Navegantes, una sola 'otra'

- ctrl: en la fase de oro actua cada asiento local con oro, aunque el turno
  sea de otro (como el descarte): la partida CPWAZB quedo 'esperando a Bot 4'
  cuando el oro era de Pancho. Test t_ctrl_gold.
- Fichas de numero: puntos de probabilidad desde R 20 con ficha de radio 10
  (en los tableros de Navegantes el hexagono queda en ~20 px y no salian).
- AGAIN: si alguien de la mesa ya pidio otra partida, al siguiente se lo manda
  a su asiento en esa en vez de crear una mas (se habian creado dos).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Mcatan/core/ctrl.c | 3++-
Mcatan/gfx/board.c | 6++++--
Mcatan/linux/selftest.c | 23+++++++++++++++++++++++
Mcomun/server/srv.c | 14++++++++++++++
4 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/catan/core/ctrl.c b/catan/core/ctrl.c @@ -46,8 +46,9 @@ static int pick_actor(const Ctrl *c) { const Game *g = c->g; if (g->phase == PH_OVER) return -1; + /* descartar (7) y elegir el oro los hace cada uno, no solo el del turno */ for (int s = 0; s < g->o.np; s++) - if (is_local(c, s) && g->phase == PH_DISCARD && g->p[s].discard) return s; + if (is_local(c, s) && ((g->phase == PH_DISCARD && g->p[s].discard) || (g->phase == PH_GOLD && g->p[s].gold))) return s; if (g->offer.active) for (int s = 0; s < g->o.np; s++) if (is_local(c, s) && s != g->cur && game_needs(g, s)) return s; diff --git a/catan/gfx/board.c b/catan/gfx/board.c @@ -208,9 +208,12 @@ static void token(Surface *s, const BoardGeom *g, int h, int num) { int cx, cy; geom_hex(g, h, &cx, &cy); + /* los puntos de probabilidad entran con una ficha de radio 10 (en los tableros grandes + * de Navegantes el hexagono queda en ~20 px); la Pico (R 24) tambien los lleva ahora */ + bool pips = g->R >= 20; int r = g->R * 32 / 100; const Font *f = g->R >= 30 ? &font_bold : &font_normal; - if (r < f->h * 3 / 4) r = f->h * 3 / 4; + if (r < (pips ? 10 : f->h * 3 / 4)) r = pips ? 10 : f->h * 3 / 4; gfx_disc(s, cx, cy, r + 1, C_OUTLINE); gfx_disc(s, cx, cy, r, C_TOKEN); char txt[3] = { 0 }; @@ -218,7 +221,6 @@ static void token(Surface *s, const BoardGeom *g, int h, int num) else txt[0] = (char)('0' + num); Color c = (num == 6 || num == 8) ? C_RED : C_OUTLINE; int tw = gfx_text_w(f, txt); - bool pips = g->R >= 26; /* los puntos de probabilidad; la Pico (R 24) no los tiene */ int ty = cy - f->h / 2 - (pips ? 2 : 0); gfx_text(s, f, cx - tw / 2, ty, txt, c); if (pips) { diff --git a/catan/linux/selftest.c b/catan/linux/selftest.c @@ -1365,6 +1365,28 @@ static void t_ctrl_robber(void) CHECK(auth_submit(&a, &m) == E_OK && g->robber == h1 && g->p[1].res[GRAIN] == 1 && g->p[0].res[GRAIN] == 1); } +/* Navegantes: el oro lo elige cada uno aunque el turno sea de otro (igual que el descarte). */ +static void t_ctrl_gold(void) +{ + static Auth a; + Opts o; + opts_default(&o, 3, false); + opts_scenario(&o, SCEN_SEA1); + auth_new(&a, &o, 5, NULL, NULL); + Game *g = &a.g; + static const char *nm[MAXP] = { "A", "B", "C", "D" }; + g->phase = PH_GOLD; g->cur = 1; g->rolled = 1; + g->p[0].gold = 1; + static Ctrl c; + ctrl_init(&c, 1, false); /* solo el asiento 0 es local */ + for (int i = 0; i < MAXP; i++) c.names[i] = nm[i]; + ctrl_sync(&c, g); + CHECK(c.actor == 0 && c.mode == CM_CARDS && c.intent == I_GOLD); + Move m; + CHECK(!ctrl_key(&c, '1', &m)); /* elige un recurso */ + CHECK(ctrl_key(&c, K_OK, &m) && m.type == M_GOLD && m.p == 0); +} + int app_selftest(void) { printf("selftest del nucleo\n"); @@ -1391,6 +1413,7 @@ int app_selftest(void) t_ctrl_nav(); t_ctrl_setup(); t_ctrl_robber(); + t_ctrl_gold(); t_serialize(); t_replay(); t_freeplay(); diff --git a/comun/server/srv.c b/comun/server/srv.c @@ -44,6 +44,7 @@ typedef struct { int nchat, capchat; FILE *chatf; bool loading; + char again[8]; /* la partida "otra como esta" ya creada (AGAIN), para no crear dos */ void *st; /* estado del juego (GameModule.state_size) */ } SGame; @@ -588,13 +589,26 @@ static void cmd_again(Server *s, Client *c) const GameModule *gm = s->gm; if (c->game < 0) { sendf(s, c, "ERR %d not in a game", gm->err_args); return; } SGame *old = s->games[c->game]; + /* si otro de la mesa ya pidio "otra", es esa: lo mando a su asiento en vez de crear una mas */ + if (old->again[0]) { + int gi = find_game(s, old->again); + if (gi >= 0 && !gm->is_over(s->games[gi]->st)) { + SGame *g = s->games[gi]; + for (int k = 0; k < g->np; k++) + if (g->kind[k] == 'P' && !strcmp(g->token[k], old->token[c->seat])) { detach(s, c); attach(s, c, gi, k); return; } + } + } char opts[SRV_LINE], seats[SRV_MAX_SEATS + 1] = ""; if (gm->again) gm->again(old->opts, opts, sizeof opts); else snprintf(opts, sizeof opts, "%s", old->opts); int np = old->np, myseat = c->seat; for (int i = 0; i < np; i++) seats[i] = old->kind[i] == 'B' ? 'B' : old->kind[i] == 'N' ? 'N' : 'H'; seats[np] = 0; + char oldcode[8]; + snprintf(oldcode, sizeof oldcode, "%s", old->code); create_game(s, c, opts, seats, np, old, myseat); + int oi = find_game(s, oldcode); /* create_game puede mover el arreglo de partidas */ + if (oi >= 0 && c->game >= 0) snprintf(s->games[oi]->again, sizeof s->games[oi]->again, "%s", s->games[c->game]->code); } static void cmd_join(Server *s, Client *c, const char *code)