/* spite.h
 *
 * Type definitions and function prototypes.
 *
 * Copyright (C) 2002 Andy Goth <unununium@openverse.com>
 *                    Matt Harang <matt@ioioio.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 * USA. */

#ifndef SEEN_SPITE_H
#define SEEN_SPITE_H

#include <stdlib.h>

/* --- TYPE DEFINITIONS ----------------------------------------------------- */

/* A hint for when things are supposed to be true/false. */
typedef unsigned bool;

/* Possible suits for a card.  Note that these values, the first four anyway,
 * are used for card_t.suit. */
typedef enum suit_t {
	S_HEART, S_DIAMOND, S_CLUB, S_SPADE,
	S_JOKER,		/* Jokers have no suit */
	S_NO_CARD,		/* No hay tarjeta */
	S_UNKNOWN		/* Card is hidden */
} suit_t;

/* Possible values for a card.  Among other things, this is used for
 * card_t.real_value and card_t.eff_value. */
typedef enum value_t {
	V_NO_CARD,		/* There is no spoon, err, card */
	V_ACE, V_TWO, V_THREE, V_FOUR, V_FIVE, V_SIX, V_SEVEN, V_EIGHT, V_NINE,
	V_TEN, V_JACK, V_QUEEN, V_KING, V_JOKER,
	V_UNKNOWN		/* Card is hidden */
} value_t;

/* Identifier for a card.  Note that there are multiple copies of a particular
 * card in a Spite & Malice deck, so this value is nonunique.  Also note that
 * in different contexts and at different times, the same card will have
 * different identifiers as it goes from being hidden to being visible, changes
 * piles, changes effective values, is being looked at by different
 * players, and so on. */
typedef struct card_t {
	bool exists: 1;		/* True if card is present */
	bool visible: 1;	/* True if card can be seen in this context */
	value_t real_value: 4;	/* 1 - 14, 1: A, 11: J, 12: Q, 13: K, 14: Jo */
	suit_t suit: 3;		/* 0: Heart, 1: Diamond, 2: Club, 3: Spade */
	bool in_play: 1;	/* True if card is in a shared discard pile */
	value_t eff_value: 4;	/* 1 - 14, 1: A, 11: J, 12: Q, 13: K, 14: Jo */
} card_t;

/* Unique identifier for a player.  A value of 0 means no player. */
typedef int player_id_t;

/* Additional state information for a player; doubles as a secret unique
 * identifier for passing to system functions. */
typedef void player_state_t;

/* Names of the various piles in play.  These values, along with a player's
 * unique id, can be used to obtain access to pile data. */
typedef enum pile_name_t {
	P_NONE,			/* Not applicable */

	/* Shared piles */
	P_SHARED_JUNK,		/* Junk pile to be shuffled into draw pile */
	P_SHARED_DRAW,		/* Pile all players draw from */
	P_SHARED_DISCARD_1,	/* First shared discard pile */
	P_SHARED_DISCARD_2,	/* Second shared discard pile */
	P_SHARED_DISCARD_3,	/* Third shared discard pile */
	P_SHARED_DISCARD_4,	/* Fourth shared discard pile */

	/* Personal piles */
	P_PLAYER_DRAW,		/* Player's personal draw pile */
	P_PLAYER_HAND,		/* Player's hand */
	P_PLAYER_DISCARD_1,	/* Player's first discard pile */
	P_PLAYER_DISCARD_2,	/* Player's second discard pile */
	P_PLAYER_DISCARD_3,	/* Player's third discard pile */
	P_PLAYER_DISCARD_4	/* Player's fourth discard pile */
} pile_name_t;

/* A stack or a hand of cards. */
typedef struct pile_t {
	card_t* cards;		/* Actual card data */
	int capacity; 		/* The maximum number of cards in the pile */
	player_id_t owner;	/* Owner (0: shared amongst players) */
	pile_name_t name;	/* Name of pile */
	bool is_stack;		/* True if this file is a stack */
	int top;		/* For a stack, index of top card (-1: empty) */
} pile_t;

/* Types of game events. */
typedef enum event_type_t {
	E_INITIALIZE,		/* Initialize state structures */
	E_SHUTDOWN,		/* Deallocate state structures */
	E_GAME_BEGIN,		/* Do last-minute preparations */
	E_GAME_END,		/* Notification of game ending */
	E_TURN_BEGIN,		/* Draw, play cards, and discard */
	E_TURN_END,		/* Notification of turn ending */
	E_DRAW_REQUEST,		/* Request for game to end in a draw */
	E_CARD_MOVE,		/* Card movement from one pile to another */
	E_DISCARD_JUNK,		/* Movement of discard piles into junk pile */
	E_SHUFFLE,		/* Junk pile shuffling into draw pile */
	E_SPLIT,		/* A player lost his link */
	E_JOIN,			/* A player regained his link */
	E_CHAT			/* Someone thinks he has something to say */
} event_type_t;

/* Description of a single game event. */
typedef struct event_t {
	event_type_t type;	/* Type of event */
	player_id_t player;	/* Player involved (can be 0) */
	card_t card_pre;	/* Card value before movement */
	card_t card_post;	/* Card value after movement */
	pile_name_t source;	/* Card's source pile */
	pile_name_t dest;	/* Card's destination pile */
	char* text;		/* Text relating to the event */
	void* data;		/* Extra event data */
} event_t;

/* An event queue. */
typedef struct event_queue_t {
	event_t** events;	/* Actual event slots */
	int num_events;		/* Current number of events */
	int head;		/* Index of next event to insert */
	int tail;		/* Index of next event to remove */
	int capacity;		/* Current maximum number of events */
} event_queue_t;

/* Generic state information for a player. */
typedef struct player_t {
	player_id_t id;		/* Unique id */
	player_state_t* state;	/* personal state information */
	pile_t* hand;		/* Hand */
	pile_t* draw;		/* Draw pile */
	pile_t* discard[4];	/* Discard piles */
	void (*event)(player_state_t*, event_t*);
} player_t;

/* Player type information needed for registration and initialization. */
typedef struct player_type_t {
	char* name;		/* Name of player type */
	char* description;	/* Description */
	char* options;		/* Information about options */
	int sizeof_state;	/* Size, in bytes, of player's state */
	void (*event)(player_state_t*, event_t*); /* Event handler */
} player_type_t;

/* Game state. */
typedef struct game_state_t {
	/* List of all supported player types */
	player_type_t* player_types;
	int num_player_types;

	/* List of all players in the game */
	player_t* players;
	int num_players;

	/* Event queue */
	event_queue_t* event_queue;

	/* The deck */
	int num_cards;

	/* Shared piles */
	pile_t* draw;		/* Pile both players draw from */
	pile_t* discard[4];	/* Piles both players play to */
	pile_t* junk;		/* Cards from queened discard piles */
} game_state_t;

/* --- FUNCTION PROTOTYPES -------------------------------------------------- */

/* main.c */
extern int main(int argc, char** argv);

/* util.c */
extern void* xmalloc(size_t size);
extern void* xrealloc(void* p, size_t size);

/* pile.c */
extern pile_t* pile_new(int capacity, player_id_t owner, pile_name_t name,
bool is_stack);
extern void pile_del(pile_t* p);
extern bool pile_is_stack(const pile_t* p);
extern bool pile_is_empty(const pile_t* p);
extern bool pile_is_full(const pile_t* p);
extern int pile_num_cards(const pile_t* p);
extern void pile_push(pile_t* p, card_t c);
extern card_t pile_pop(pile_t* p);
extern card_t pile_peek(const pile_t* p);
extern card_t pile_peek_i(const pile_t* p, int i);
extern void pile_move_card(pile_t* src, pile_t* dst, int i);

/* card.c */
extern const card_t card_empty;
extern suit_t card_suit(card_t c);
extern value_t card_real_value(card_t c);
extern value_t card_eff_value(card_t c);
extern bool card_is_wild(card_t c);
extern bool card_in_play(card_t c);
extern bool card_is_playable(card_t top, card_t bottom);

/* event.c */
extern event_t* event_new(event_type_t type, player_id_t player,
card_t card_pre, card_t card_post, pile_name_t source, pile_name_t dest,
char* text, void* data);
extern void event_del(event_t* e);
extern void event_queue_push(event_queue_t* q, event_t* e);
extern event_t* event_queue_pop(event_queue_t* q);
extern int event_queue_num_events(const event_queue_t* q);
extern event_queue_t* event_queue_new(void);
extern void event_queue_del(event_queue_t* q);

/* player.c */

/* game.c */

#endif

/* EOF */

