shithub: city

Download patch

ref: 0428625c683eb42701271bafabb318a3728a503f
parent: acb956ad79b4e9458af3f1a1a8d029ba33a9dc40
author: qwx <qwx@sciops.net>
date: Sun Sep 12 04:56:56 EDT 2021

graphics improvements, mouse selection

- building one-letter name (temporary until pixelart)
- only print once char per tile (temporary until pixelart)
- colors (temporary until pixelart)
- usual background colors
- center drawing canvas
- draw "hud": selected tile name
- limit drawing to visible tiles (for large maps)

--- a/city.c
+++ b/city.c
@@ -23,6 +23,18 @@
 	return p;
 }
 
+int
+max(int a, int b)
+{
+	return a > b ? a : b;
+}
+
+int
+min(int a, int b)
+{
+	return a < b ? a : b;
+}
+
 static void
 timeproc(void *)
 {
@@ -77,6 +89,8 @@
 		case Amouse:
 			if(eqpt(mo.xy, ZP))
 				mo = mc->Mouse;
+			if(mc->buttons & 1<<0)
+				mouseselect(mc->xy);
 			break;
 		case Akbd:
 			switch(r){
--- a/dat.h
+++ b/dat.h
@@ -58,6 +58,7 @@
 };
 struct Building{
 	char *name;
+	char *abbr;
 	int buildtime;
 	int buildcost[Gtot];
 	int prodtime;
@@ -80,6 +81,7 @@
 };
 struct Terrain{
 	char *name;
+	char *abbr;
 	int good;
 	int initialstock;
 	double yield;
--- a/defs.c
+++ b/defs.c
@@ -100,6 +100,7 @@
 Building buildings[] = {
 	[Btownhall]{
 		.name "townhall",
+		.abbr "H",
 		.buildtime 1000,
 		.buildcost {0},
 		.terrain Tplain,
@@ -111,6 +112,7 @@
 		},
 	},[Bfishyard]{
 		.name "fishyard",
+		.abbr "F",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 5,
@@ -127,6 +129,7 @@
 		},
 	},[Bcarpentry]{
 		.name "carpentry",
+		.abbr "C",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 3,
@@ -143,6 +146,7 @@
 		},
 	},[Bsawmill]{
 		.name "sawmill",
+		.abbr "L",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 10,
@@ -161,6 +165,7 @@
 		},
 	},[Bmill]{
 		.name "mill",
+		.abbr "M",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 8,
@@ -177,6 +182,7 @@
 		},
 	},[Bfarm]{
 		.name "farm",
+		.abbr "B",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 8,
@@ -197,6 +203,7 @@
 		},
 	},[Bquarry]{
 		.name "quarry",
+		.abbr "Q",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 5,
@@ -214,6 +221,7 @@
 		},
 	},[Bsmeltery]{
 		.name "smeltery",
+		.abbr "S",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 12,
@@ -234,6 +242,7 @@
 		},
 	},[Bforge]{
 		.name "forge",
+		.abbr "F",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 10,
@@ -255,6 +264,7 @@
 		},
 	},[Blapidary]{
 		.name "lapidary",
+		.abbr "L",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 26,
@@ -277,6 +287,7 @@
 		},
 	},[Bmarket]{
 		.name "market",
+		.abbr "G",
 		.buildtime 50,
 		.buildcost {
 			[Ggold] 10,
@@ -295,36 +306,43 @@
 Terrain terrains[] = {
 	[Tplain]{
 		.name "plain",
+		.abbr "p",
 		.good -1,
 		.initialstock 0,
 		.yield 0,
 	},[Twoods]{
 		.name "woods",
+		.abbr "w",
 		.good Gwood,
 		.initialstock 9001,
 		.yield 1,
 	},[Tpond]{
 		.name "pond",
+		.abbr "p",
 		.good Gfish,
 		.initialstock 9001,
 		.yield 1,
 	},[Tcrop]{
 		.name "crop",
+		.abbr "c",
 		.good Gwheat,
 		.initialstock 800,
 		.yield 0.8,
 	},[Tmountain]{
 		.name "mountain",
+		.abbr "m",
 		.good Gstone,
 		.initialstock 9001,
 		.yield 0.8,
 	},[Tironvein]{
 		.name "ironvein",
+		.abbr "i",
 		.good Giron,
 		.initialstock 9001,
 		.yield 0.5,
 	},[Tgoldvein]{
 		.name "goldvein",
+		.abbr "g",
 		.good Ggold,
 		.initialstock 9001,
 		.yield 0.3,
--- a/drw.c
+++ b/drw.c
@@ -8,8 +8,21 @@
 
 static char *fontname = "/lib/font/bit/fixed/unicode.6x10.font";
 
-static Rectangle fbr;
+static Tile *selected;
+
+enum{
+	Cbg,
+	Cterrain,
+	Cbuild,
+	Ctext,
+	Cend,
+};
+static Image *cols[Cend];
+
+static Rectangle fbr, drwwin, hudr;
 static Image *fb;
+static Point tlsize, tlofs, tlwindow;
+static int doupdate;
 
 static Image *
 eallocimage(Rectangle r, ulong chan, int repl, ulong col)
@@ -21,47 +34,98 @@
 	return i;
 }
 
-void
+static Point
+scr2tilexy(Point p)
+{
+	p = subpt(p, drwwin.min);
+	p = Pt(p.x / (tlsize.x + 4), p.y / (tlsize.y + 4));
+	assert(p.x < tlwindow.x && p.x >= 0 && p.y < tlwindow.y && p.y >= 0);
+	return p;
+}
+
+static Tile *
+scr2tile(Point p)
+{
+	p = scr2tilexy(p);
+	return map + p.y * mapwidth + p.x;
+}
+
+static void
+drawhud(void)
+{
+	char *name;
+
+	if(selected == nil)
+		return;
+	name = selected->b != nil ? selected->b->name : selected->t->name;
+	draw(screen, hudr, cols[Cbg], nil, ZP);
+	string(screen, hudr.min, cols[Ctext], ZP, font, name);
+}
+
+static void
 drawtile(Tile *m)
 {
+	int hasbuild;
 	char *s;
 	Point p;
 
-	p.x = (m - map) % mapwidth * 16 * font->width;
-	p.y = (m - map) / mapwidth * 2 * font->height;
-	s = m->b != nil ? m->b->name : m->t->name;
-	string(fb, p, display->white, ZP, font, s);
+	p.x = ((m - map) % mapwidth) * (tlsize.x + 4);
+	p.y = ((m - map) / mapwidth) * (tlsize.y + 4);
+	hasbuild = m->b != nil;
+	s = hasbuild ? m->b->abbr : m->t->abbr;
+	string(fb, p, hasbuild ? cols[Cbuild] : cols[Cterrain], ZP, font, s);
 }
 
 void
 updatedraw(void)
 {
-	int bail;
+	int x, y;
 	Tile *m;
 
-	bail = 1;
 	qlock(&drwlock);
-	for(m=map; m<map+mapwidth*mapheight; m++)
-		if(m->stale){
-			bail = 0;
-			drawtile(m);
-			m->stale = 0;
-		}
+	for(y=0, m=map; y<tlwindow.y; y++){
+		for(x=0; x<tlwindow.x; x++, m++)
+			if(m->stale){
+				drawtile(m);
+				m->stale = 0;
+				doupdate = 1;
+			}
+		m += mapwidth - tlwindow.x;
+	}
 	qunlock(&drwlock);
-	if(bail)
+	if(!doupdate)
 		return;
-	draw(screen, screen->r, fb, nil, ZP);
+	draw(screen, screen->r, fb, nil, tlofs);
+	drawhud();
 	flushimage(display, 1);
+	doupdate = 0;
 }
 
 void
+mouseselect(Point p)
+{
+	doupdate = 1;
+	if(!ptinrect(p, drwwin)){
+		selected = nil;
+		return;
+	}
+	selected = scr2tile(p);
+	doupdate = 1;
+	updatedraw();
+}
+
+static void
 redraw(void)
 {
+	int x, y;
 	Tile *m;
 
 	draw(fb, fb->r, display->black, nil, ZP);
-	for(m=map; m<map+mapwidth*mapheight; m++)
-		m->stale = 1;
+	for(y=0, m=map; y<tlwindow.y; y++){
+		for(x=0; x<tlwindow.x; x++, m++)
+			m->stale = 1;
+		m += mapwidth - tlwindow.x;
+	}
 	updatedraw();
 }
 
@@ -68,9 +132,27 @@
 void
 resetdraw(void)
 {
+	int w, h;
+
+	w = Dx(screen->r);
+	h = Dy(screen->r);
+	fbr.min = ZP;
+	/* for fuck's sake */
+	fbr.max.x = min(w, tlsize.x * mapwidth + (mapwidth - 1) * 4);
+	fbr.max.y = min(h, tlsize.y * mapheight + (mapheight - 1) * 4 + abs(font->height - font->width));
+	tlofs.x = w > fbr.max.x ? (fbr.max.x - w) / 2 : 0;
+	tlofs.y = h > fbr.max.y ? (fbr.max.y - h) / 2 : 0;
+	tlwindow.x = w > fbr.max.x ? mapwidth : min(mapwidth, fbr.max.x / (tlsize.x + 4) + 1);
+	tlwindow.y = h > fbr.max.y ? mapheight : min(mapheight, fbr.max.y / (tlsize.y + 4) + 1);
+	drwwin.min = subpt(screen->r.min, tlofs);
+	drwwin.max = addpt(drwwin.min, fbr.max);
+	hudr.min = addpt(drwwin.max, Pt(-fbr.max.x - 16, 16));
+	hudr.max = Pt(screen->r.max.x - 16, hudr.min.y + font->height);
 	freeimage(fb);
-	fbr = rectsubpt(screen->r, screen->r.min);
 	fb = eallocimage(fbr, screen->chan, 0, DNofill);
+	if(!eqpt(tlofs, ZP))
+		draw(screen, screen->r, cols[Cbg], nil, ZP);
+	doupdate = 1;
 	redraw();
 }
 
@@ -79,5 +161,16 @@
 {
 	if(initdraw(nil, fontname, "city") < 0)
 		sysfatal("initdraw: %r");
+	cols[Cbg] = eallocimage(Rect(0,0,1,1), screen->chan, 1, 0x777777FF);
+	cols[Cterrain] = eallocimage(Rect(0,0,1,1), screen->chan, 1, 0x999999FF);
+	cols[Cbuild] = eallocimage(Rect(0,0,1,1), screen->chan, 1, 0x9B6917FF);
+	cols[Ctext] = display->black;
+	tlsize = stringsize(font, "0");
+	if(tlsize.x < tlsize.y)
+		tlsize.y = tlsize.x;
+	else
+		tlsize.x = tlsize.y;
+	fmtinstall('P', Pfmt);
+	fmtinstall('R', Rfmt);
 	resetdraw();
 }
--- a/fns.h
+++ b/fns.h
@@ -5,5 +5,7 @@
 void	startsim(void);
 void	initdrw(void);
 void	resetdraw(void);
-void	redraw(void);
 void	updatedraw(void);
+void	mouseselect(Point);
+int	min(int, int);
+int	max(int, int);
--- a/sim.c
+++ b/sim.c
@@ -19,18 +19,6 @@
 };
 static int stock[Gtot], rstock[Rtot];
 
-int
-max(int a, int b)
-{
-	return a > b ? a : b;
-}
-
-int
-min(int a, int b)
-{
-	return a < b ? a : b;
-}
-
 static void
 spawn(Tile *m, int n)
 {