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
--
⑨