shithub: scoundrel

Download patch

ref: f5aa8e66aaa6184506d08b27ccd4f2b9b0726f12
author: sirjofri <sirjofri@sirjofri.de>
date: Fri Feb 13 14:38:37 EST 2026

adds working UI

--- /dev/null
+++ b/dat.h
@@ -1,0 +1,18 @@
+typedef enum {
+	Diamonds = 0,
+	Hearts,
+	Clubs,
+	Spades,
+} Color;
+
+
+typedef struct State State;
+struct State {
+	int room[4];
+	int deckcards;
+	int weapon;
+	int lastweaponkill;
+	
+	int running;
+	int canskip;
+};
\ No newline at end of file
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,8 @@
+void loadimages(char *path);
+Image *getimage(int num);
+
+int c2n(int c, Color col);
+State *getstate(void);
+int roomaction(int c, int useweapon);
+int startgame(void);
+int nextround(void);
\ No newline at end of file
--- /dev/null
+++ b/game.c
@@ -1,0 +1,77 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct Card Card;
+struct Card {
+	Color col;
+	int value;
+};
+
+State state;
+
+int
+c2n(int c, Color col)
+{
+	return c + col*15;
+}
+
+State*
+getstate()
+{
+	return &state;
+}
+
+int
+roomaction(int c, int useweapon)
+{
+	int card;
+	
+	if (!state.running)
+		return 0;
+	
+	card = state.room[c];
+	if (card < 0)
+		return 0;
+	// TODO: manage card: fight if enemy, heal if potion, change weapon if weapon card
+	fprint(2, "card pressed: %d\n", c);
+	return 1;
+}
+
+int
+startgame(void)
+{
+	if (state.running)
+		return 0;
+	
+	state.running++;
+	
+	state.canskip = 1;
+	// TODO: mix cards, update state
+	
+	// fake display
+	
+	state.room[0] = c2n(2, Spades);
+	state.room[1] = c2n(11, Diamonds);
+	state.room[2] = c2n(14, Clubs);
+	state.room[3] = c2n(4, Hearts);
+	state.deckcards = 5;
+	state.weapon = c2n(6, Diamonds);
+	state.lastweaponkill = c2n(4, Spades);
+	return 1;
+}
+
+int
+nextround(void)
+{
+	if (!state.running)
+		return 0;
+	if (!state.canskip)
+		return 0;
+	
+	state.canskip = 0;
+	// TODO: skip round: move cards to end of deck
+	return 1;
+}
\ No newline at end of file
--- /dev/null
+++ b/images.c
@@ -1,0 +1,80 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+static int
+isnumeric(char *name)
+{
+	while (*name && isdigit(*name))
+		name++;
+	return *name == 0;
+}
+
+Image *images[4*15];
+
+static Image*
+loadfromfile(char *path, int num)
+{
+	char *file;
+	int fd;
+	Image *img;
+	
+	file = smprint("%s/%d", path, num);
+	if (!file)
+		sysfatal("smprint: %r");
+	
+	fd = open(file, OREAD);
+	if (fd < 0)
+		sysfatal("open file %s: %r", file);
+	free(file);
+	
+	img = readimage(display, fd, 0);
+	close(fd);
+	if (!img)
+		sysfatal("readimage: %r");
+	return img;
+}
+
+void
+loadimages(char *path)
+{
+	int i, n, a;
+	Dir *d;
+	
+	a = open(path, OREAD);
+	if (a < 0)
+		sysfatal("open: %r");
+	
+	n = dirreadall(a, &d);
+	close(a);
+	
+	memset(images, 0, sizeof images);
+	
+	for (i = 0; i < n; i++) {
+		if (!isnumeric(d[i].name))
+			continue;
+		a = atoi(d[i].name);
+		if (a >= nelem(images))
+			continue;
+		images[a] = loadfromfile(path, a);
+	}
+	free(d);
+}
+
+Image*
+getimage(int num)
+{
+	Image *img;
+	if (num >= nelem(images)) {
+		werrstr("missing image: %d\n", num);
+		return nil;
+	}
+	img = images[num];
+	if (img)
+		return img;
+	werrstr("missing image: %d\n", num);
+	return nil;
+}
\ No newline at end of file
--- /dev/null
+++ b/main.c
@@ -1,0 +1,213 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <keyboard.h>
+#include <event.h>
+#include "dat.h"
+#include "fns.h"
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s\n", argv0);
+	exits("usage");
+}
+
+Point carddim;
+
+static void
+drawroom(int *cards)
+{
+	int i;
+	Point p;
+	Image *img;
+	
+	for (i = 0; i < 4; i++) {
+		if (cards[i] < 0)
+			continue;
+		img = getimage(cards[i]);
+		if (!img)
+			sysfatal("%r");
+		p.x = i * Dx(img->r);
+		p.y = 0;
+		p = addpt(p, screen->r.min);
+		draw(screen, rectaddpt(img->r, p), img, nil, ZP);
+	}
+}
+
+int useweapon = 0;
+
+static void
+drawweapon(int weapon, int killed)
+{
+	Point p;
+	Image *img;
+	
+	if (weapon < 0)
+		return;
+	
+	img = getimage(weapon);
+	if (!img)
+		sysfatal("%r");
+	
+	p.x = 0;
+	p.y = Dy(img->r);
+	p = addpt(p, screen->r.min);
+	draw(screen, rectaddpt(img->r, p), img, nil, ZP);
+	
+	if (useweapon) {
+		p.x = Dx(img->r)+10;
+		p.y = Dy(img->r) + 10;
+		p = addpt(p, screen->r.min);
+		line(screen, p, Pt(p.x, p.y + Dy(img->r) - 10),
+			Enddisc, Enddisc, 4, display->black, ZP);
+	}
+	
+	if (killed < 0)
+		return;
+	
+	img = getimage(killed);
+	if (!img)
+		sysfatal("%r");
+	
+	p.x = 0;
+	p.y = Dy(img->r) + 30;
+	p = addpt(p, screen->r.min);
+	draw(screen, rectaddpt(img->r, p), img, nil, ZP);
+}
+
+static void
+drawstats(State *state)
+{
+	Point p;
+	char s[64];
+	
+	p.x = carddim.x + 100;
+	p.y = carddim.y + 40;
+	p = addpt(p, screen->r.min);
+	
+	snprint(s, sizeof s, "Deck: %d", state->deckcards);
+	string(screen, p, display->black, ZP, font, s);
+}
+
+static void
+redraw(void)
+{
+	State *state;
+	draw(screen, screen->r, display->white, nil, ZP);
+	
+	state = getstate();
+	
+	if (!state->running)
+		return;
+	
+	drawroom(state->room);
+	drawweapon(state->weapon, state->lastweaponkill);
+	drawstats(state);
+}
+
+void
+eresized(int new)
+{
+	if (new && getwindow(display, Refnone) < 0)
+		sysfatal("resized: %r");
+	
+	redraw();
+}
+
+static void
+handlekbd(int key)
+{
+	int i;
+	switch (key) {
+	case 'w':
+		useweapon = !useweapon;
+		redraw();
+		break;
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+		i = key - '0';
+		i = roomaction(i-1, useweapon);
+		useweapon = 0;
+		if (i) goto Redraw;
+		break;
+	case 's':
+		if (startgame()) goto Redraw;
+		break;
+	case 'n':
+		if (nextround()) goto Redraw;
+		break;
+	}
+Redraw:
+	redraw();
+}
+
+static void
+handlemouse(Mouse m)
+{
+	int i;
+	
+	if (m.buttons != 1)
+		return;
+	
+	m.xy.x -= screen->r.min.x;
+	m.xy.y -= screen->r.min.y;
+	
+	if (m.xy.y < carddim.y) {
+		/* first row: room cards */
+		i = m.xy.x / carddim.x;
+		if (roomaction(i, useweapon)) redraw();
+		return;
+	}
+	if (m.xy.y < carddim.y*2) {
+		if (m.xy.x < carddim.x) {
+			/* weapon card pressed */
+			useweapon = !useweapon;
+			redraw();
+			return;
+		}
+	}
+}
+
+void
+main(int argc, char **argv)
+{
+	int e;
+	Event ev;
+	Image *img;
+	
+	ARGBEGIN{
+	case 'h':
+		usage();
+		break;
+	}ARGEND;
+	
+	if (initdraw(nil, nil, "scoundrel") < 0)
+		sysfatal("initdraw: %r");
+	
+	einit(Emouse|Ekeyboard);
+	
+	loadimages("img");
+	
+	/* 2 must be valid */
+	img = getimage(2);
+	carddim.x = Dx(img->r);
+	carddim.y = Dy(img->r);
+	
+	redraw();
+	
+	for (;;) {
+		e = event(&ev);
+		switch (e) {
+		case Emouse:
+			handlemouse(ev.mouse);
+			break;
+		case Ekeyboard:
+			if (ev.kbdc == Kesc || ev.kbdc == 'q')
+				exits(nil);
+			handlekbd(ev.kbdc);
+		}
+	}
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,11 @@
+</$objtype/mkfile
+
+TARG=scoundrel
+OFILES=\
+	main.$O\
+	images.$O\
+	game.$O\
+
+HFILES=fns.h dat.h
+
+</sys/src/cmd/mkone
--