shithub: scoundrel

ref: 2f76aa950c0e7aba70b856f331bfc3227e47556f
dir: /game.c/

View raw version
#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;
}