ref: 2293ed78636e5f66b5e2884bebd193803cb6939f
parent: 497acdd8860d629ba24ed9976fd47eeb743b74ab
author: rodri <[email protected]>
date: Fri Sep 22 11:32:36 EDT 2023
add parsecmd to the client. finish the menulist of matches. the menulist now supports scrolling. also changed some cursors and got to tidy up /^lmb\(.
--- a/bts.c
+++ b/bts.c
@@ -9,6 +9,41 @@
#include "dat.h"
#include "fns.h"
+enum {
+ CMid,
+ CMqueued,
+ CMlayout,
+ CMoid,
+ CMwait,
+ CMplay,
+ CMwehit,
+ CMwemiss,
+ CMtheyhit,
+ CMtheymiss,
+ CMmatchesb, /* list header */
+ CMmatch, /* list entry */
+ CMmatchese, /* list tail */
+ CMwin,
+ CMlose,
+};
+Cmdtab svcmd[] = {
+ CMid, "id", 1,
+ CMqueued, "queued", 1,
+ CMlayout, "layout", 1,
+ CMoid, "oid", 2,
+ CMwait, "wait", 1,
+ CMplay, "play", 1,
+ CMwehit, "hit", 1,
+ CMwemiss, "miss", 1,
+ CMtheyhit, "hit", 2,
+ CMtheymiss, "miss", 2,
+ CMmatchesb, "matches", 1,
+ CMmatch, "m", 4,
+ CMmatchese, "end", 1,
+ CMwin, "win", 1,
+ CMlose, "lose", 1,
+};
+
int debug;
Cursor patrolcursor = {
@@ -174,7 +209,7 @@
oid[0] = 0;
game.state = Waiting0;
conclusion.s = nil;
- csetcursor(mctl, &patrolcursor);
+ csetcursor(mctl, nil);
}
Point
@@ -498,36 +533,33 @@
void
lmb(Mousectl *mc)
{
- Board *b;
Point2 cell;
- b = nil;
- if(ptinrect(mc->xy, alienboard.bbox))
- b = &alienboard;
- else if(ptinrect(mc->xy, localboard.bbox))
- b = &localboard;
-
- if(b == nil || conclusion.s != nil)
+ if(conclusion.s != nil)
return;
- cell = toboard(b, mc->xy);
switch(game.state){
case Outlaying:
- if(b == &localboard)
- if(curship != nil && rectinrect(curship->bbox, localboard.bbox))
- if(++curship-armada >= nelem(armada))
- curship = nil;
- else if(curship != &armada[0])
- curship->orient = (curship-1)->orient;
+ if(!ptinrect(mc->xy, localboard.bbox))
+ break;
+
+ if(curship != nil && rectinrect(curship->bbox, localboard.bbox)){
+ if(++curship-armada >= nelem(armada))
+ curship = nil;
+ else if(curship != &armada[0])
+ curship->orient = (curship-1)->orient;
+ nbsend(drawchan, nil);
+ }
break;
case Playing:
- if(b == &alienboard){
- chanprint(egress, "shoot %s\n", cell2coords(cell));
- lastshot = cell;
- }
+ if(!ptinrect(mc->xy, alienboard.bbox))
+ break;
+
+ cell = toboard(&alienboard, mc->xy);
+ chanprint(egress, "shoot %s\n", cell2coords(cell));
+ lastshot = cell;
break;
}
- nbsend(drawchan, nil);
}
void
@@ -619,9 +651,14 @@
{
Rectangle newbbox;
static Mouse oldm;
+ int selmatch;
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(game.state == Outlaying && curship != nil){
newbbox = mkshipbbox(toboard(&localboard, mc->xy), curship->orient, curship->ncells);
@@ -712,42 +749,47 @@
void
processcmd(char *cmd)
{
+ Cmdbuf *cb;
+ Cmdtab *ct;
Point2 cell;
- char *f[3];
- int i, nf;
+ int i;
if(debug)
fprint(2, "rcvd '%s'\n", cmd);
- nf = tokenize(cmd, f, nelem(f));
- if(nf < 1)
+ cb = parsecmd(cmd, strlen(cmd));
+ ct = lookupcmd(cb, svcmd, nelem(svcmd));
+ if(ct == nil){
+ free(cb);
return;
+ }
- if(nf == 1 && strcmp(f[0], "win") == 0)
+ if(ct->index == CMwin)
celebrate();
- else if(nf == 1 && strcmp(f[0], "lose") == 0)
+ else if(ct->index == CMlose)
keelhaul();
switch(game.state){
case Waiting0:
- if(nf == 1 && strcmp(f[0], "id") == 0)
+ if(ct->index == CMid)
chanprint(egress, "id %s\n", uid);
- else if(nf == 1 && strcmp(f[0], "queued") == 0)
+ else if(ct->index == CMqueued){
game.state = Ready;
- else if(!matches->filling && nf == 1 && strcmp(f[0], "matches") == 0){
+ csetcursor(mctl, &patrolcursor);
+ }else if(!matches->filling && ct->index == CMmatchesb){
matches->clear(matches);
matches->filling = 1;
- }else if(matches->filling && nf == 3)
- matches->add(matches, strtoul(f[0], nil, 10), smprint("%s vs %s", f[1], f[2]));
- else if(matches->filling && nf == 1 && strcmp(f[0], "end") == 0)
+ }else if(matches->filling && ct->index == CMmatch)
+ 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;
break;
case Ready:
- if(nf == 1 && strcmp(f[0], "layout") == 0){
+ if(ct->index == CMlayout){
game.state = Outlaying;
curship = &armada[0];
- }else if(nf == 2 && strcmp(f[0], "oid") == 0)
- snprint(oid, sizeof oid, "%s", f[1]);
+ }else if(ct->index == CMoid)
+ snprint(oid, sizeof oid, "%s", cb->f[1]);
break;
case Watching:
/* <idx?> <uid> (hit|missed) <coord> */
@@ -756,27 +798,27 @@
*/
break;
case Outlaying:
- if(nf == 1 && strcmp(f[0], "wait") == 0){
+ if(ct->index == CMwait){
game.state = Waiting;
csetcursor(mctl, &waitcursor);
- }else if(nf == 1 && strcmp(f[0], "play") == 0)
+ }else if(ct->index == CMplay)
game.state = Playing;
break;
case Playing:
- if(nf == 1 && strcmp(f[0], "wait") == 0){
+ if(ct->index == CMwait){
game.state = Waiting;
csetcursor(mctl, &waitcursor);
- }else if(nf == 1 && strcmp(f[0], "hit") == 0)
+ }else if(ct->index == CMwehit)
settile(&alienboard, lastshot, Thit);
- else if(nf == 1 && strcmp(f[0], "miss") == 0)
+ else if(ct->index == CMwemiss)
settile(&alienboard, lastshot, Tmiss);
break;
case Waiting:
- if(nf == 1 && strcmp(f[0], "play") == 0){
+ if(ct->index == CMplay){
game.state = Playing;
csetcursor(mctl, nil);
- }else if(nf == 2 && strcmp(f[0], "hit") == 0){
- cell = coords2cell(f[1]);
+ }else if(ct->index == CMtheyhit){
+ cell = coords2cell(cb->f[1]);
for(i = 0; i < nelem(armada); i++)
if(ptinrect(fromboard(&localboard, cell), armada[i].bbox)){
cell = subpt2(cell, armada[i].p);
@@ -783,12 +825,13 @@
armada[i].hit[(int)vec2len(cell)] = 1;
break;
}
- }else if(nf == 2 && strcmp(f[0], "miss") == 0){
- cell = coords2cell(f[1]);
+ }else if(ct->index == CMtheymiss){
+ cell = coords2cell(cb->f[1]);
settile(&localboard, cell, Tmiss);
}
break;
}
+ free(cb);
nbsend(drawchan, nil);
}
@@ -906,7 +949,6 @@
initarmada();
matches = newmenulist(14*font->height, "ongoing matches");
game.state = Waiting0;
- csetcursor(mctl, &patrolcursor);
drawchan = chancreate(sizeof(void*), 1);
ingress = chancreate(sizeof(char*), 1);
--- a/menulist.c
+++ b/menulist.c
@@ -13,7 +13,7 @@
Menuborder = 2,
Vspace = 2,
Scrollwidth = 10,
- Maxvisitems = 5,
+ Maxvisitems = 8,
};
static char none[] = "none";
@@ -31,7 +31,11 @@
ml->r.min.x = SCRW/2 - ew/2;
ml->r.max.x = ml->r.min.x + ew;
}
- if(ml->nentries > 1)
+
+ if(ml->nentries > Maxvisitems){
+ ml->sr.min = subpt(ml->r.min, Pt(Scrollwidth+2*Menuborder,0));
+ ml->sr.max = Pt(ml->r.min.x-2*Menuborder, ml->r.max.y);
+ }else if(ml->nentries > 1)
ml->r.max.y += font->height+Vspace;
}
@@ -55,16 +59,45 @@
ml->r.max = addpt(ml->r.min, Pt(w, font->height+Vspace));
ml->sr = ZR;
ml->high = -1;
+ ml->off = 0;
}
-static void
-menulist_update(Menulist *ml, Mousectl *mc)
+static int
+menulist_update(Menulist *ml, Mousectl *mc, Channel *drawchan)
{
- if(ptinrect(mc->xy, ml->r)){
- /* item highlighting and selection */
- }else if(ptinrect(mc->xy, ml->sr)){
- /* scrolling */
+ /* redundant from bts.c:/^mouse\(, but it's necessary to avoid overdrawing */
+ static Mouse oldm;
+ static ulong lastlmbms;
+ int selected;
+
+ selected = -1;
+ if(ptinrect(mc->xy, Rpt(ml->sr.min, ml->r.max))){
+ if(ptinrect(mc->xy, ml->r)){
+ /* item highlighting and selection */
+ ml->high = ml->off + (mc->xy.y - ml->r.min.y)/(font->height+Vspace);
+ if(oldm.buttons != mc->buttons && mc->buttons == 1){
+ if(mc->msec-lastlmbms < 500)
+ selected = ml->high;
+ else
+ lastlmbms = mc->msec;
+ }
+ }
+ if(mc->buttons != oldm.buttons && ml->nentries > Maxvisitems)
+ /* scrolling */
+ switch(mc->buttons){
+ case 1: if(!ptinrect(mc->xy, ml->sr)) break;
+ case 8:
+ ml->off = max(0, ml->off - (mc->xy.y - ml->sr.min.y)/(font->height+Vspace));
+ break;
+ case 4: if(!ptinrect(mc->xy, ml->sr)) break;
+ case 16:
+ ml->off = min(ml->off + (mc->xy.y - ml->sr.min.y)/(font->height+Vspace), ml->nentries-Maxvisitems);
+ break;
+ }
}
+ nbsendp(drawchan, nil);
+ oldm = mc->Mouse;
+ return selected;
}
static void
@@ -72,7 +105,7 @@
{
static Image *bc;
Rectangle tr, er; /* title and per-entry */
- int i;
+ int i, width;
if(ml->filling)
return;
@@ -81,18 +114,20 @@
bc = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
/* draw title */
+ width = stringwidth(font, ml->title);
tr.min = subpt(ml->r.min, Pt(0,Menuborder + font->height+Vspace));
tr.max = Pt(ml->r.max.x, ml->r.min.y - Menuborder);
draw(dst, tr, display->black, nil, ZP);
- string(dst, tr.min, display->white, ZP, font, ml->title);
+ string(dst, addpt(tr.min, Pt(Dx(tr)/2 - width/2,0)), display->white, ZP, font, ml->title);
/* draw content */
border(dst, ml->r, -Menuborder, bc, ZP);
er.min = ml->r.min;
er.max = Pt(ml->r.max.x, er.min.y + font->height+Vspace);
- for(i = 0; i < ml->nentries; i++){
- draw(dst, er, display->white, nil, ZP);
- string(dst, er.min, display->black, ZP, font, ml->entries[i].title);
+ for(i = ml->off; i < ml->nentries && er.min.y < ml->r.max.y; i++){
+ width = stringwidth(font, ml->entries[i].title);
+ draw(dst, er, i == ml->high? display->black: display->white, nil, ZP);
+ string(dst, addpt(er.min, Pt(Dx(er)/2 - width/2,0)), i == ml->high? display->white: display->black, ZP, font, ml->entries[i].title);
er.min.y += font->height+Vspace;
er.max.y = er.min.y + font->height+Vspace;
}
@@ -99,6 +134,13 @@
if(i == 0){
draw(dst, er, display->white, nil, ZP);
string(dst, er.min, display->black, ZP, font, none);
+ }
+
+ /* draw scroll */
+ if(ml->nentries > Maxvisitems){
+ border(dst, ml->sr, -Menuborder, bc, ZP);
+ draw(dst, ml->sr, display->black, nil, ZP);
+ draw(dst, Rpt(addpt(ml->sr.min, Pt(0,ml->off*Dy(ml->sr)/ml->nentries)), Pt(ml->sr.max.x,ml->sr.min.y + (ml->off+Maxvisitems)*Dy(ml->sr)/ml->nentries)), display->white, nil, ZP);
}
}