ref: 05825e751d69cde554c21ddfd00e646049425e31
parent: 2293ed78636e5f66b5e2884bebd193803cb6939f
author: rodri <rgl@antares-labs.eu>
date: Tue Sep 26 14:39:02 EDT 2023
initial work towards spectator mode.
--- a/bts.c
+++ b/bts.c
@@ -23,6 +23,7 @@
CMmatchesb, /* list header */
CMmatch, /* list entry */
CMmatchese, /* list tail */
+ CMwatching,
CMwin,
CMlose,
};
@@ -40,6 +41,7 @@
CMmatchesb, "matches", 1,
CMmatch, "m", 4,
CMmatchese, "end", 1,
+ CMwatching, "watching", 6,
CMwin, "win", 1,
CMlose, "lose", 1,
};
@@ -116,6 +118,7 @@
int layoutdone;
Point2 lastshot;
Menulist *matches;
+MatchInfo match; /* of which we are an spectator */
struct {
int state;
@@ -310,6 +313,10 @@
s = "";
switch(game.state){
+ case Watching:
+ snprint(aux, sizeof aux, "watching %s vs. %s", match.pl[0], match.pl[1]);
+ s = aux;
+ break;
case Ready: s = "looking for players"; break;
case Outlaying: s = "place the fleet"; break;
case Waiting: s = "wait for your turn"; break;
@@ -326,9 +333,9 @@
vstring(dst, p, display->white, ZP, font, s);
p = Pt(alienboard.bbox.max.x+2, alienboard.bbox.min.y);
- vstring(dst, p, display->white, ZP, font, oid);
+ vstring(dst, p, display->white, ZP, font, game.state == Watching? match.pl[1]: oid);
p = subpt(localboard.bbox.min, Pt(font->width+2,0));
- vstring(dst, p, display->white, ZP, font, uid);
+ vstring(dst, p, display->white, ZP, font, game.state == Watching? match.pl[0]: uid);
if(game.state == Outlaying){
if(c == nil)
@@ -656,8 +663,10 @@
mc->xy = subpt(mc->xy, screen->r.min);
if(game.state == Waiting0)
- if((selmatch = matches->update(matches, mc, drawchan)) >= 0)
- if(debug) fprint(2, "selected match id %d title %s\n", selmatch, matches->entries[selmatch].title);
+ if((selmatch = matches->update(matches, mc, drawchan)) >= 0){
+ if(debug) fprint(2, "selected match id %d title %s\n", matches->entries[selmatch].id, matches->entries[selmatch].title);
+ chanprint(egress, "watch %d\n", matches->entries[selmatch].id);
+ }
if(game.state == Outlaying && curship != nil){
newbbox = mkshipbbox(toboard(&localboard, mc->xy), curship->orient, curship->ncells);
@@ -752,6 +761,7 @@
Cmdbuf *cb;
Cmdtab *ct;
Point2 cell;
+ uchar buf[BY2MAP];
int i;
if(debug)
@@ -783,6 +793,18 @@
matches->add(matches, strtoul(cb->f[1], nil, 10), smprint("%s vs %s", cb->f[2], cb->f[3]));
else if(matches->filling && ct->index == CMmatchese)
matches->filling = 0;
+ else if(ct->index == CMwatching){
+ match.id = strtoul(cb->f[1], nil, 10);
+ match.pl[0] = estrdup(cb->f[2]);
+ match.pl[1] = estrdup(cb->f[3]);
+ match.bl[0] = &localboard;
+ match.bl[1] = &alienboard;
+ dec64(buf, sizeof buf, cb->f[4], strlen(cb->f[4]));
+ bitunpackmap(match.bl[0], buf, sizeof buf);
+ dec64(buf, sizeof buf, cb->f[5], strlen(cb->f[5]));
+ bitunpackmap(match.bl[1], buf, sizeof buf);
+ game.state = Watching;
+ }
break;
case Ready:
if(ct->index == CMlayout){
--- a/btsd.c
+++ b/btsd.c
@@ -317,6 +317,7 @@
Cmdtab *ct;
Player *p, *op;
Stands stands;
+ uchar buf1[BY2MAP], buf2[BY2MAP];
uint n0;
Point2 cell;
@@ -432,8 +433,8 @@
}else{
op = p == m->pl[0]? m->pl[1]: m->pl[0];
chanprint(op->io.out, "win\n");
- op->state = Waiting0;
op->battle = nil;
+ op->state = Waiting0;
freeplayer(p);
freemsg(msg);
goto Finish;
@@ -442,6 +443,11 @@
takeseat(&stands, p);
p->battle = m;
p->state = Watching;
+ bitpackmap(buf1, sizeof buf1, m->pl[0]);
+ bitpackmap(buf2, sizeof buf2, m->pl[1]);
+ chanprint(p->io.out, "watching %d %s %s %.*[ %.*[\n",
+ m->id, m->pl[0]->name, m->pl[1]->name,
+ sizeof buf1, buf1, sizeof buf2, buf2);
}else if(strcmp(msg->body, "leave seat") == 0){
leaveseat(&stands, p);
p->battle = nil;
@@ -642,6 +648,7 @@
char *addr;
GEOMfmtinstall();
+ fmtinstall('[', encodefmt);
addr = "tcp!*!3047";
ARGBEGIN{
case 'd':
--- a/dat.h
+++ b/dat.h
@@ -5,6 +5,9 @@
Tmiss,
NTILES,
+ TBITS = 2, /* ceil(log(NTILES)/log(2)) */
+ TMASK = (1<<TBITS) - 1,
+
Scarrier = 0,
Sbattleship,
Scruiser,
@@ -31,6 +34,7 @@
SCRH = Boardmargin+MAPH*TH+TH+MAPH*TH+Boardmargin,
KB = 1024,
+ BY2MAP = TBITS*MAPW*MAPH/8+1,
};
typedef struct Ship Ship;
@@ -41,6 +45,7 @@
typedef struct Match Match;
typedef struct Msg Msg;
typedef struct Stands Stands;
+typedef struct MatchInfo MatchInfo;
struct Ship
{
@@ -104,6 +109,13 @@
Player **seats;
ulong nused;
ulong cap;
+};
+
+struct MatchInfo
+{
+ int id;
+ char *pl[2];
+ Board *bl[2];
};
typedef struct Mentry Mentry;
--- a/fns.h
+++ b/fns.h
@@ -23,6 +23,8 @@
char *statename(int);
int max(int, int);
int min(int, int);
+int bitpackmap(uchar*, ulong, Map*);
+int bitunpackmap(Map*, uchar*, ulong);
/*
* menulist
--- a/util.c
+++ b/util.c
@@ -100,6 +100,9 @@
switch(m->map[j][i]){
case Twater: fprint(fd, "W"); break;
case Tship: fprint(fd, "S"); break;
+ case Thit: fprint(fd, "X"); break;
+ case Tmiss: fprint(fd, "O"); break;
+ default: fprint(fd, "?"); break;
}
fprint(fd, "\n");
}
@@ -152,4 +155,45 @@
min(int a, int b)
{
return a < b? a: b;
+}
+
+int
+bitpackmap(uchar *buf, ulong len, Map *m)
+{
+ int i, j, off, n;
+
+ assert(len >= BY2MAP);
+
+ off = n = 0;
+ *buf = 0;
+ for(i = 0; i < MAPW; i++)
+ for(j = 0; j < MAPH; j++){
+ if(off >= 8){
+ buf[++n] = 0;
+ off = 0;
+ }
+ buf[n] |= (m->map[i][j] & TMASK) << off;
+ off += TBITS;
+ }
+ return n+1;
+}
+
+int
+bitunpackmap(Map *m, uchar *buf, ulong len)
+{
+ int i, j, off, n;
+
+ assert(len >= BY2MAP);
+
+ off = n = 0;
+ for(i = 0; i < MAPW; i++)
+ for(j = 0; j < MAPH; j++){
+ if(off >= 8){
+ n++;
+ off = 0;
+ }
+ m->map[i][j] = buf[n] >> off & TMASK;
+ off += TBITS;
+ }
+ return n+1;
}