ref: 7b76e7467822316b699847cbd61a0ecb985882d3
author: rodri <rgl@antares-labs.eu>
date: Tue Aug 8 04:35:17 EDT 2023
initial commit.
--- /dev/null
+++ b/alloc.c
@@ -1,0 +1,44 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+void*
+emalloc(ulong n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil)
+ sysfatal("malloc: %r");
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
+
+void*
+erealloc(void *p, ulong n)
+{
+ void *np;
+
+ np = realloc(p, n);
+ if(np == nil){
+ if(n == 0)
+ return nil;
+ sysfatal("realloc: %r");
+ }
+ if(p == nil)
+ setmalloctag(np, getcallerpc(&p));
+ else
+ setrealloctag(np, getcallerpc(&p));
+ return np;
+}
+
+Image*
+eallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong col)
+{
+ Image *i;
+
+ i = allocimage(d, r, chan, repl, col);
+ if(i == nil)
+ sysfatal("allocimage: %r");
+ return i;
+}
--- /dev/null
+++ b/bts.c
@@ -1,0 +1,315 @@
+#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"
+
+int debug;
+
+char deffont[] = "/lib/font/bit/pelm/unicode.9.font";
+char winspec[32];
+Channel *drawchan;
+RFrame worldrf;
+Image *screenb;
+Image *tiletab[NTILES];
+Board alienboard;
+Board localboard;
+
+
+Point
+fromworld(Point2 p)
+{
+ p = invrframexform(p, worldrf);
+ return Pt(p.x,p.y);
+}
+
+Point2
+toworld(Point p)
+{
+ return rframexform(Pt2(p.x,p.y,1), worldrf);
+}
+
+Point
+fromboard(Board *b, Point2 p)
+{
+ p = invrframexform(invrframexform(p, *b), worldrf);
+ return Pt(p.x,p.y);
+}
+
+Point2
+toboard(Board *b, Point p)
+{
+ return rframexform(rframexform(Pt2(p.x,p.y,1), worldrf), *b);
+}
+
+Image *
+gettileimage(int type)
+{
+ if(type < 0 || type > nelem(tiletab))
+ return nil;
+ return tiletab[type];
+}
+
+void
+settile(Board *b, Point2 cell, int type)
+{
+ Point p;
+
+ p.x = cell.x;
+ p.y = cell.y;
+ b->map[p.x][p.y] = type;
+}
+
+void
+drawtile(Image *dst, Board *b, Point2 cell, int type)
+{
+ Point p;
+ Image *ti;
+
+ p = fromboard(b, cell);
+ ti = gettileimage(type);
+ if(ti == nil)
+ return;
+
+ draw(dst, Rpt(p, addpt(p, Pt(TW,TH))), ti, nil, ZP);
+}
+
+void
+drawboard(Image *dst, Board *b)
+{
+ int i, j;
+
+ for(i = 0; i < MAPW; i++)
+ for(j = 0; j < MAPH; j++)
+ drawtile(dst, b, Pt2(i,j,1), b->map[i][j]);
+}
+
+void
+redraw(void)
+{
+ lockdisplay(display);
+
+ draw(screenb, screenb->r, display->black, nil, ZP);
+ drawboard(screenb, &alienboard);
+ drawboard(screenb, &localboard);
+
+ draw(screen, screen->r, screenb, nil, ZP);
+
+ flushimage(display, 1);
+ unlockdisplay(display);
+}
+
+void
+resize(void)
+{
+ lockdisplay(display);
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("resize failed");
+ unlockdisplay(display);
+
+ freeimage(screenb);
+ screenb = eallocimage(display, rectsubpt(screen->r, screen->r.min), screen->chan, 0, DNofill);
+ send(drawchan, nil);
+}
+
+void
+inittiles(void)
+{
+ Image *brush;
+ int i, x, y;
+ Point pts[2];
+
+ for(i = 0; i < nelem(tiletab); i++){
+ tiletab[i] = eallocimage(display, Rect(0,0,TW,TH), screen->chan, 0, DNofill);
+ switch(i){
+ case Twater:
+ brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreyblue);
+ draw(tiletab[i], tiletab[i]->r, brush, nil, ZP);
+ freeimage(brush);
+ brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalebluegreen);
+ for(pts[0] = ZP, x = 0; x < TW; x++){
+ y = sin(x)*TH/2;
+ pts[1] = Pt(x,y+TH/2);
+ line(tiletab[i], pts[0], pts[1], Endsquare, Endsquare, 0, brush, ZP);
+ pts[0] = pts[1];
+ }
+ freeimage(brush);
+ break;
+ case Tship:
+ brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x333333FF);
+ draw(tiletab[i], tiletab[i]->r, brush, nil, ZP);
+ freeimage(brush);
+ brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlack);
+ fillellipse(tiletab[i], Pt(TW/2,TH/2), 2, 2, brush, ZP);
+ freeimage(brush);
+ break;
+ case Thit:
+ brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
+ draw(tiletab[i], tiletab[i]->r, brush, nil, ZP);
+ freeimage(brush);
+ brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlack);
+ pts[0] = Pt(TW/2-TW/4,TH/2-TH/4);
+ pts[1] = Pt(TW/2+TW/4,TH/2+TH/4);
+ line(tiletab[i], pts[0], pts[1], Endsquare, Endsquare, 1, brush, ZP);
+ pts[0].y += TH/2;
+ pts[1].y -= TH/2;
+ line(tiletab[i], pts[0], pts[1], Endsquare, Endsquare, 1, brush, ZP);
+ freeimage(brush);
+ break;
+ case Tmiss:
+ draw(tiletab[i], tiletab[i]->r, tiletab[Twater], nil, ZP);
+ brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DWhite);
+ ellipse(tiletab[i], Pt(TW/2,TH/2), 6, 6, 1, brush, ZP);
+ freeimage(brush);
+ break;
+ }
+ }
+}
+
+void
+initboards(void)
+{
+ memset(alienboard.map, Twater, MAPW*MAPH);
+ alienboard.p = Pt2(Boardmargin,Boardmargin,1);
+ memset(localboard.map, Twater, MAPW*MAPH);
+ localboard.p = addpt2(alienboard.p, Vec2(0,MAPH*TH+TH));
+ alienboard.bx = localboard.bx = Vec2(TW,0);
+ alienboard.by = localboard.by = Vec2(0,TH);
+ alienboard.bbox = Rpt(fromworld(alienboard.p), fromworld(addpt2(alienboard.p, Pt2(TW*MAPW,TH*MAPH,1))));
+ localboard.bbox = Rpt(fromworld(localboard.p), fromworld(addpt2(localboard.p, Pt2(TW*MAPW,TH*MAPH,1))));
+}
+
+void
+mouse(Mousectl *mc)
+{
+ mc->xy = subpt(mc->xy, screen->r.min);
+
+ switch(mc->buttons){
+ case 1:
+ if(ptinrect(mc->xy, alienboard.bbox))
+ settile(&alienboard, toboard(&alienboard, mc->xy), Tmiss);
+ if(ptinrect(mc->xy, localboard.bbox))
+ settile(&localboard, toboard(&localboard, mc->xy), Tmiss);
+ send(drawchan, nil);
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ }
+}
+
+void
+key(Rune r)
+{
+ switch(r){
+ case Kdel:
+ case 'q':
+ threadexitsall(nil);
+ }
+}
+
+void
+showproc(void *)
+{
+ threadsetname("showproc");
+
+ while(recv(drawchan, nil) > 0)
+ redraw();
+
+ sysfatal("showproc died");
+}
+
+void
+inputthread(void *arg)
+{
+ Input *in;
+ Rune r;
+ Alt a[4];
+
+ in = arg;
+
+ a[0].op = CHANRCV; a[0].c = in->mc->c; a[0].v = &in->mc->Mouse;
+ a[1].op = CHANRCV; a[1].c = in->mc->resizec; a[1].v = nil;
+ a[2].op = CHANRCV; a[2].c = in->kc->c; a[2].v = &r;
+ a[3].op = CHANEND;
+
+ for(;;)
+ switch(alt(a)){
+ case 0:
+ mouse(in->mc);
+ break;
+ case 1:
+ resize();
+ break;
+ case 2:
+ key(r);
+ break;
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-d] addr\n", argv0);
+ threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ char *addr;
+ int fd;
+ Input in;
+
+ GEOMfmtinstall();
+ ARGBEGIN{
+ case 'd':
+ debug++;
+ break;
+ default: usage();
+ }ARGEND
+ if(argc != 1)
+ usage();
+
+ addr = netmkaddr(argv[0], "tcp", "3047");
+ if(debug)
+ fprint(2, "connecting to %s\n", addr);
+
+ fd = dial(addr, nil, nil, nil);
+ if(fd < 0)
+ sysfatal("dial: %r");
+ else if(debug)
+ fprint(2, "line established\n");
+
+ snprint(winspec, sizeof winspec, "-dx %d -dy %d", SCRW, SCRH);
+ if(newwindow(winspec) < 0)
+ sysfatal("newwindow: %r");
+ if(initdraw(nil, deffont, "bts") < 0)
+ sysfatal("initdraw: %r");
+ if((in.mc = initmouse(nil, screen)) == nil)
+ sysfatal("initmouse: %r");
+ if((in.kc = initkeyboard(nil)) == nil)
+ sysfatal("initkeyboard: %r");
+
+ display->locking = 1;
+ unlockdisplay(display);
+
+ screenb = eallocimage(display, rectsubpt(screen->r, screen->r.min), screen->chan, 0, DNofill);
+ worldrf.p = Pt2(0,0,1);
+ worldrf.bx = Vec2(1,0);
+ worldrf.by = Vec2(0,1);
+
+ inittiles();
+ initboards();
+
+ drawchan = chancreate(sizeof(void*), 0);
+ proccreate(showproc, nil, mainstacksize);
+ threadcreate(inputthread, &in, mainstacksize);
+ send(drawchan, nil);
+ yield();
+}
--- /dev/null
+++ b/btsd.c
@@ -1,0 +1,98 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <geometry.h>
+#include "dat.h"
+#include "fns.h"
+
+int debug;
+
+
+void
+serveproc(void *arg)
+{
+ Biobuf *bin, *bout;
+ NetConnInfo *nci;
+ char *line;
+ int fd, linelen;
+
+ fd = *(int*)arg;
+ nci = getnetconninfo(nil, fd);
+ if(nci == nil)
+ sysfatal("getnetconninfo: %r");
+ threadsetname("serveproc %s", nci->raddr);
+ freenetconninfo(nci);
+
+ bin = Bfdopen(fd, OREAD);
+ bout = Bfdopen(fd, OWRITE);
+ if(bin == nil || bout == nil)
+ sysfatal("Bfdopen: %r");
+
+ while((line = Brdline(bin, '\n')) != nil){
+ linelen = Blinelen(bin);
+ Bwrite(bout, line, linelen);
+ Bflush(bout);
+ print("%.*s", linelen, line);
+ }
+
+ Bterm(bin);
+ Bterm(bout);
+}
+
+void
+listenthread(void *arg)
+{
+ char *addr, adir[40], ldir[40];
+ int acfd, lcfd, dfd;
+
+ addr = arg;
+
+ acfd = announce(addr, adir);
+ if(acfd < 0)
+ sysfatal("announce: %r");
+
+ if(debug)
+ fprint(2, "listening on %s\n", addr);
+
+ while((lcfd = listen(adir, ldir)) >= 0){
+ if((dfd = accept(lcfd, ldir)) >= 0){
+ proccreate(serveproc, &dfd, mainstacksize);
+ close(dfd);
+ }
+ close(lcfd);
+ }
+
+ threadexitsall("listen: %r");
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-d] [-a addr]\n", argv0);
+ threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ char *addr;
+
+ addr = "tcp!*!3047";
+ ARGBEGIN{
+ case 'd':
+ debug++;
+ break;
+ case 'a':
+ addr = EARGF(usage());
+ break;
+ }ARGEND
+ if(argc != 0)
+ usage();
+
+ threadcreate(listenthread, addr, mainstacksize);
+ yield();
+}
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,31 @@
+enum {
+ Twater,
+ Tship,
+ Thit,
+ Tmiss,
+ NTILES,
+
+ Boardmargin = 50,
+ TW = 16,
+ TH = TW,
+ MAPW = 17,
+ MAPH = MAPW,
+ SCRW = Boardmargin+MAPW*TW+Boardmargin,
+ SCRH = Boardmargin+MAPH*TH+TH+MAPH*TH+Boardmargin,
+};
+
+typedef struct Input Input;
+typedef struct Board Board;
+
+struct Input
+{
+ Mousectl *mc;
+ Keyboardctl *kc;
+};
+
+struct Board
+{
+ RFrame;
+ char map[17][17];
+ Rectangle bbox;
+};
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,8 @@
+#define HZ2MS(hz) (1000/(hz))
+
+/*
+ * alloc
+ */
+void *emalloc(ulong);
+void *erealloc(void*, ulong);
+Image *eallocimage(Display*, Rectangle, ulong, int, ulong);
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,24 @@
+</$objtype/mkfile
+
+MAN=/sys/man/1
+BIN=/$objtype/bin/games
+TARG=\
+ bts\
+ btsd\
+
+OFILES=\
+ alloc.$O\
+
+HFILES=\
+ dat.h\
+ fns.h\
+
+</sys/src/cmd/mkmany
+
+install:V: man
+
+uninstall:V:
+ for(i in $TARG){
+ rm -f $BIN/$i
+ rm -f $MAN/$i
+ }