ref: bcf588dfdf8ce73721ceba766c219c3e0bace666
dir: /game.c/
#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;
Card *next;
};
State state;
Card possible[4*9 + 2*4];
Card *deck = nil;
Card *last = nil;
int ncards = 0;
static void
addcard(int c, Color col)
{
Card *card;
card = mallocz(sizeof(Card), 1);
if (!card)
sysfatal("mallocz: %r");
card->col = col;
card->value = c;
if (!deck) {
deck = last = card;
state.deckcards++;
return;
}
last->next = card;
last = card;
state.deckcards++;
}
static Card
drawcard(void)
{
Card *c, card;
if (!deck)
return (Card){-1, -1, nil};
c = deck;
deck = deck->next;
card = *c;
free(c);
state.deckcards--;
return card;
}
static int
cardexists(int c, Color col)
{
Card *cd;
for (cd = deck; cd; cd = cd->next) {
if (cd->col == col && cd->value == c)
return 1;
}
return 0;
}
static void
cleardeck(void)
{
Card *c, *d;
for (c = deck; c; c = d) {
d = c->next;
free(c);
}
deck = last = nil;
state.deckcards = 0;
}
static int
validcard(int c, Color col)
{
int range;
if (c < 2)
return 0;
switch (col) {
case Diamonds:
case Hearts:
range = 10;
break;
case Clubs:
case Spades:
range = 14;
break;
default:
return 0;
}
return c <= range;
}
static void
gendeck(void)
{
int c, col;
int expected = 4*9 + 2*4;
cleardeck();
while (state.deckcards < expected) {
c = nrand(13) + 2;
col = nrand(4);
if (!validcard(c, col))
continue;
if (cardexists(c, col))
continue;
addcard(c, col);
}
}
static void
fillroom(void)
{
int i;
Card c;
for (i = 0; i < 4; i++) {
if (state.room[i] > 0)
continue;
c = drawcard();
if (c.value < 0) {
state.status = Won;
continue;
}
state.room[i] = c2n(c.value, c.col);
}
state.hadpotion = 0;
}
int
c2n(int c, Color col)
{
return c + col*15;
}
static Card
n2c(int n)
{
Card c;
c.col = n/15;
c.value = n%15;
return c;
}
State*
getstate()
{
return &state;
}
int
roomaction(int c, int useweapon)
{
int cd, i, n;
Card card, weapon;
if (state.status != Running)
return 0;
cd = state.room[c];
if (cd < 0)
return 0;
card = n2c(cd);
weapon = n2c(state.weapon);
switch (card.col) {
case Diamonds:
state.lastweaponkill = -1;
state.weapon = cd;
state.room[c] = -1;
break;
case Hearts:
state.room[c] = -1;
if (state.hadpotion)
break;
state.hp += card.value;
if (state.hp > 20) state.hp = 20;
state.hadpotion = 1;
break;
case Spades:
case Clubs:
state.room[c] = -1;
state.hp -= useweapon && weapon.value > 0 ? card.value - weapon.value : card.value;
if (useweapon)
state.lastweaponkill = cd;
break;
}
if (state.hp <= 0) {
state.status = Lost;
return 1;
}
state.canskip = 0;
n = 0;
for (i = 0; i < 4; i++) {
if (state.room[i] < 0)
n++;
}
if (n >= 3) {
state.canskip = 1;
fillroom();
}
return 1;
}
int
startgame(void)
{
int i;
if (state.status == Running)
return 0;
state.status = Running;
state.canskip = 1;
state.hp = 20;
state.weapon = -1;
state.lastweaponkill = -1;
gendeck();
for (i = 0; i < 4; i++)
state.room[i] = -1;
fillroom();
return 1;
}
void
initgame(void)
{
state.status = Notstarted;
}
int
nextround(void)
{
int i;
Card c;
if (state.status != Running)
return 0;
if (!state.canskip)
return 0;
/* skipped this round, another skip is invalid! */
state.canskip = 0;
for (i = 0; i < 4; i++) {
if (state.room[i] < 0) {
fprint(2, "skip room with empty slot. Invalid!\n");
continue;
}
c = n2c(state.room[i]);
addcard(c.value, c.col);
state.room[i] = -1;
}
fillroom();
return 1;
}