ref: ca4af600fdad77b3c4603a62c81eee51187fafcf
parent: 25e1b9489b9090b5d3372dd0dac09c1e7b3f10b3
author: rodri <rgl@antares-labs.eu>
date: Fri Aug 25 17:53:17 EDT 2023
implemented most of the layout code. added a new util.c to host the cell/coordinate conversions. made the showproc a painter thread instead, to avoid problems with menuhit(2).
--- a/bts.c
+++ b/bts.c
@@ -3,6 +3,7 @@
#include <thread.h>
#include <draw.h>
#include <mouse.h>
+#include <cursor.h>
#include <keyboard.h>
#include <geometry.h>
#include "dat.h"
@@ -20,6 +21,7 @@
Board alienboard;
Board localboard;
Ship armada[NSHIPS];
+Ship *curship;
struct {
int state;
@@ -197,7 +199,7 @@
freeimage(brush);
break;
case Tship:
- brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x333333FF);
+ brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF);
draw(tiletab[i], tiletab[i]->r, brush, nil, ZP);
freeimage(brush);
brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlack);
@@ -257,7 +259,7 @@
case Scruiser: /* fallthrough */
case Ssubmarine: s->ncells = 3; break;
case Sdestroyer: s->ncells = 2; break;
- default: sysfatal("initships: unknown ship: %d", i);
+ default: sysfatal("initarmada: unknown ship: %d", i);
}
s->orient = OH;
s->hit = emalloc(s->ncells*sizeof(int));
@@ -266,38 +268,41 @@
}
}
-void
-placeship(Mousectl *mc, Ship *s)
+int
+confirmdone(Mousectl *mc)
{
- Rectangle newbbox;
-
- for(;;){
- if(readmouse(mc) < 0)
- break;
-
- mc->xy = subpt(mc->xy, screen->r.min);
- newbbox = mkshipbbox(toboard(&localboard, mc->xy), s->orient, s->ncells);
-
- if(rectinrect(newbbox, localboard.bbox)){
- s->p = toboard(&localboard, mc->xy);
- s->bbox = newbbox;
+ Cursor yousure = {
+ {0, 0},
+ { 0xf7, 0xfe, 0x15, 0x54, 0x1d, 0x54, 0x09, 0x54,
+ 0x09, 0xdc, 0x00, 0x00, 0x75, 0x77, 0x45, 0x54,
+ 0x75, 0x66, 0x15, 0x54, 0x77, 0x57, 0x00, 0x00,
+ 0x00, 0x02, 0x2a, 0x84, 0x11, 0x28, 0x2a, 0x90,
+ },
+ { 0xea, 0x2b, 0xea, 0xab, 0xe2, 0xab, 0xf6, 0xab,
+ 0xf6, 0x23, 0xff, 0xff, 0x8a, 0x88, 0xba, 0xab,
+ 0x8a, 0x99, 0xea, 0xab, 0x88, 0xa8, 0xff, 0xff,
+ 0xff, 0xfd, 0xd5, 0x7b, 0xee, 0xd7, 0xd5, 0x6f,
}
- if(mc->buttons == 1 && ptinrect(mc->xy, localboard.bbox))
- break;
- send(drawchan, nil);
+ };
+ setcursor(mc, &yousure);
+ while(mc->buttons == 0)
+ readmouse(mc);
+ if(mc->buttons != 4){
+ setcursor(mc, nil);
+ return 0;
}
+ while(mc->buttons){
+ if(mc->buttons != 4){
+ setcursor(mc, nil);
+ return 0;
+ }
+ readmouse(mc);
+ }
+ setcursor(mc, nil);
+ return 1;
}
void
-placeships(Mousectl *mc)
-{
- int i;
-
- for(i = 0; i < nelem(armada); i++)
- placeship(mc, &armada[i]);
-}
-
-void
lmb(Mousectl *mc)
{
Board *b;
@@ -315,10 +320,11 @@
cell = toboard(b, mc->xy);
switch(game.state){
case Outlaying:
- settile(b, cell, Tship);
+ if(curship != nil && ++curship-armada >= nelem(armada))
+ curship = nil;
break;
case Playing:
- chanprint(egress, "shoot %d-%d", (int)cell.x, (int)cell.y);
+ chanprint(egress, "shoot %s", cell2coords(cell));
break;
}
send(drawchan, nil);
@@ -325,35 +331,99 @@
}
void
+mmb(Mousectl *mc)
+{
+ enum {
+ ROTATE,
+ };
+ static char *items[] = {
+ [ROTATE] "rotate ship",
+ nil
+ };
+ static Menu menu = { .item = items };
+
+ if(game.state != Outlaying)
+ return;
+
+ mc->xy = addpt(mc->xy, screen->r.min);
+ switch(menuhit(2, mc, &menu, _screen)){
+ case ROTATE:
+ if(curship != nil)
+ curship->orient = curship->orient == OH? OV: OH;
+ break;
+ }
+ send(drawchan, nil);
+}
+
+void
rmb(Mousectl *mc)
{
enum {
PLACESHIP,
+ DONE,
};
static char *items[] = {
- [PLACESHIP] "place ship",
+ [PLACESHIP] "place ships",
+ [DONE] "done",
nil
};
static Menu menu = { .item = items };
+ char buf[5*(1+3+1)+1];
+ int i, n;
+ if(game.state != Outlaying)
+ return;
+
+ mc->xy = addpt(mc->xy, screen->r.min);
switch(menuhit(3, mc, &menu, _screen)){
case PLACESHIP:
- placeships(mc);
+ curship = &armada[0];
break;
+ case DONE:
+ if(curship != nil)
+ break;
+
+ if(!confirmdone(mc))
+ break;
+
+ buf[0] = 0;
+ n = 0;
+ for(i = 0; i < nelem(armada); i++){
+ assert(sizeof buf - n > 1+3+1);
+ if(i != 0)
+ buf[n++] = ',';
+ n += snprint(buf+n, sizeof buf - n, "%s%c",
+ cell2coords(armada[i].p), armada[i].orient == OH? 'h': 'v');
+ }
+ chanprint(egress, "layout %s", buf);
+ break;
}
+ send(drawchan, nil);
}
void
mouse(Mousectl *mc)
{
+ Rectangle newbbox;
+
mc->xy = subpt(mc->xy, screen->r.min);
+ if(game.state == Outlaying && curship != nil){
+ newbbox = mkshipbbox(toboard(&localboard, mc->xy), curship->orient, curship->ncells);
+
+ if(rectinrect(newbbox, localboard.bbox)){
+ curship->p = toboard(&localboard, mc->xy);
+ curship->bbox = newbbox;
+ }
+ send(drawchan, nil);
+ }
+
switch(mc->buttons){
case 1:
lmb(mc);
break;
case 2:
-// mmb(mc);
+ mmb(mc);
break;
case 4:
rmb(mc);
@@ -372,14 +442,11 @@
}
void
-showproc(void *)
+painter(void *)
{
- threadsetname("showproc");
-
while(recv(drawchan, nil) > 0)
redraw();
-
- sysfatal("showproc died");
+ sysfatal("painter died");
}
void
@@ -426,12 +493,21 @@
while((n = ioread(io, fd, buf, sizeof(buf)-1)) > 0){
buf[n] = 0;
+
if(debug)
fprint(2, "rcvd '%s'\n", buf);
+
+ if(strcmp(buf, "win") == 0)
+ game.state = Waiting0;
+ else if(strcmp(buf, "lose") == 0)
+ game.state = Waiting0;
+
switch(game.state){
case Waiting0:
- if(strcmp(buf, "layout") == 0)
+ if(strcmp(buf, "layout") == 0){
game.state = Outlaying;
+ curship = &armada[0];
+ }
break;
case Outlaying:
if(strcmp(buf, "wait") == 0)
@@ -540,7 +616,7 @@
drawchan = chancreate(sizeof(void*), 0);
ingress = chancreate(sizeof(char*), 16);
egress = chancreate(sizeof(char*), 16);
- proccreate(showproc, nil, mainstacksize);
+ threadcreate(painter, nil, mainstacksize);
threadcreate(inputthread, &in, mainstacksize);
threadcreate(netrecvthread, &fd, mainstacksize);
threadcreate(netsendthread, &fd, mainstacksize);
--- a/btsd.c
+++ b/btsd.c
@@ -115,7 +115,7 @@
while((i = alt(a)) >= 0){
if(a[i].err != nil){
if(debug)
- fprint(2, "alt: %s\n", a[i].err);
+ fprint(2, "[%d] alt: %s\n", getpid(), a[i].err);
write(m[i^1]->fd, "win", 3);
m[i^1]->state = Waiting0;
pushplayer(m[i^1]);
--- a/fns.h
+++ b/fns.h
@@ -6,3 +6,9 @@
void *emalloc(ulong);
void *erealloc(void*, ulong);
Image *eallocimage(Display*, Rectangle, ulong, int, ulong);
+
+/*
+ * util
+ */
+char *cell2coords(Point2);
+Point2 coords2cell(char*);
--- a/mkfile
+++ b/mkfile
@@ -8,6 +8,7 @@
OFILES=\
alloc.$O\
+ util.$O\
HFILES=\
dat.h\
--- /dev/null
+++ b/util.c
@@ -1,0 +1,42 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <geometry.h>
+#include "dat.h"
+#include "fns.h"
+
+static char rowtab[] = "abcdefghijklmnopq";
+
+
+char *
+cell2coords(Point2 cell)
+{
+ static char s[3+1];
+
+ assert(cell.x < 17 && cell.x >= 0
+ && cell.y < 17 && cell.y >= 0);
+
+ snprint(s, sizeof s, "%c%d", rowtab[(int)cell.y], (int)cell.x);
+ return s;
+}
+
+Point2
+coords2cell(char *s)
+{
+ Point2 cell;
+ char *p;
+
+ assert(s[0] >= 'a' && s[0] <= 'q');
+
+ cell = Pt2(0,0,1);
+ p = strchr(rowtab, s[0]);
+ cell.y = p-rowtab;
+ cell.x = strtol(s+1, nil, 10);
+
+ assert(cell.x < 17 && cell.x >= 0);
+
+ return cell;
+}