/* 
   This file is part of Practical Distributed Processing
   Copyright (C) 2006-2007 Phillip J. Brooke and Richard F. Paige
*/

#ifndef _NGCOMMON_HDR
#define _NGCOMMON_HDR

#include <netinet/in.h>
#include <stdlib.h>

/* See the comp.lang.c FAQ for this one.... */
#define Str(x) #x
#define Xstr(x) Str(x)

/* A protocol version and header so that we can match servers/clients
   appropriately. */
#define PROTOCOL_VERSION 1
#define PROTOCOL_HDR "DPB-NG"
#define PROTOCOL_LN PROTOCOL_HDR " " Xstr(PROTOCOL_VERSION)

/* Hard-wired port numbers (for now). */
#define ADMIN_PORT 23457

/* Buffer size for inbound messages. */
#define BUFFER_SIZE 1024
/* But sometimes we want to pretend that it's one character smaller to
   accommodate a trailing \0. */
#define SHORT_BUFFER 1023

/* Size of the game world. */
#define TILE_LENGTH 100
#define N_TILES     5
/* So there are N_TILES * N_TILES tiles, and the world size is
   TILE_LENGTH * N_TILES long each side.  We label them
   0..N_TILES-1. */

/* We arrange to read the command-line with a single function.  What
   follows are the variables we use for the command line (as global
   variables) and a function to read them. */
extern char *secret_keyword;
extern char *admin_host;
extern char *name;
extern int   bot;
void read_command_line(int argc, char *argv[]);

/* A structure describing players.  Although ngclient1, ngadmin and
   ngmap1 all use it, they don't necessarily use all fields.  For
   example, the clients shouldnt' know the network addresses of other
   players. */
typedef struct player_node {
  struct sockaddr_in       tcp;        /* Player's address. */
  struct sockaddr_in       udp;        /* Player's address. */
  char                    *name;       /* Player name. */
  /* Init/current position data. */
  int                      xt, yt;
  float                    xi, yi;
  /* Current position as a single value. */
  float                    xr, yr;
  /* Place where player is moving to. */
  int                      txt, tyt;
  float                    txi, tyi;
  /* Next in the linked list. */
  struct player_node      *next;
  /* Nanoseconds since last move. */
  long int                 last_move;
} pnode;

/* Head of the linked list of players. */
extern pnode *phead;

/* Mutex for player AND shot list, since we have multiple threads
   here.  Both use the same mutex to prevent deadlocks. */
extern pthread_mutex_t pmutex; 

/* Match players by name and delete them from the linked list. */
pnode *match_player(char *name);
void delete_player(pnode *pdel);

/* A structure listing shots. */
typedef struct shot_node {
  char                    *name;       /* Player's name. */
  /* Place where player's shot is currently. */
  int                      xt, yt;
  float                    xi, yi;
  /* Current position as a single value. */
  float                    xr, yr;
  /* Aim point of player's shot. */
  int                      txt, tyt;
  float                    txi, tyi;
  /* Next in the linked list. */
  struct shot_node      *next;
} snode;

/* Head of the linked list of shots. */
extern snode *shead;

/* Match shots by player's name and delete them from the linked list. */
snode *match_shot(char *name);
void delete_shot(snode *sdel);

/* Functions to add players and shots.  Not all fields are catered for
   here.  The new pointer is returned each time. */
pnode *add_player(char *username, 
		int xt, int yt, float xi, float yi,
		int txt, int tyt, float txi, float tyi,
		char *p_host, int p_port);
snode *add_shot(char *username, 
		int xt, int yt, float xi, float yi,
		int txt, int tyt, float txi, float tyi);

/* Conversion functions. */
float to_real(int t, float i);
int to_tile(float r);
float to_inner(float r);
float get_dir(float r0, float r1);
float distance(float x, float y);
float distance8(int axt, int ayt, float axi, float ayi,
		int bxt, int byt, float bxi, float byi);
int local_tile(int axt, int ayt, int bxt, int byt);

/* Safety limit.  Bring any bogus values back into range.  Both return
   true if okay, false if there were corrections. */
int check_tile(int *xt, int *yt);
int check_inner(float *xi, float *yi);

#endif
