// myth_defs.h
#ifndef __myth_defs_h__
#define __myth_defs_h__

// put all global myth defs in here.
#define KILO 1024
#define MEG (KILO*KILO)
#define GIG (KILO*MEG)

typedef long fixed;
typedef unsigned short fixed_fraction;

typedef short short_fixed;
typedef unsigned char short_fixed_fraction;

enum
{
//	UNSIGNED_LONG_MAX= 4294967295,
//	LONG_MAX= 2147483647L,
//	LONG_MIN= (-2147483648L),
	LONG_BITS= 32

//	UNSIGNED_SHORT_MAX= 65535,
//	SHORT_MAX= 32767,
//	SHORT_MIN= (-32768),
//	SHORT_BITS= 16,

//	UNSIGNED_CHAR_MAX= 255,
//	CHAR_MAX= 127,
//	CHAR_MIN= (-128),
//	CHAR_BITS= 8
};

enum
{
	// Timing Enums
	MILLISECONDS_PER_SECOND= 1000,
	SECONDS_PER_MINUTE= 60,
	MINUTES_PER_HOUR= 60,
	HOURS_PER_DAY= 24,
	TICKS_PER_SECOND= 30,
	TICKS_PER_MINUTE= TICKS_PER_SECOND*SECONDS_PER_MINUTE,
	TICKS_PER_HOUR= TICKS_PER_MINUTE*MINUTES_PER_HOUR,
	TICKS_PER_DAY= TICKS_PER_HOUR*HOURS_PER_DAY,

	// 16.16 fixed
	FIXED_FRACTIONAL_BITS= 16,
	FIXED_ONE= 1<<FIXED_FRACTIONAL_BITS,
	FIXED_ONE_HALF= FIXED_ONE/2,
	FIXED_ONE_QUARTER= FIXED_ONE/4,

	// 8.8 short_fixed
	SHORT_FIXED_FRACTIONAL_BITS= 8,
	SHORT_FIXED_ONE= 1<<SHORT_FIXED_FRACTIONAL_BITS,
	SHORT_FIXED_ONE_HALF= SHORT_FIXED_ONE/2,
	SHORT_FIXED_ONE_QUARTER= SHORT_FIXED_ONE/4,
	
	TRIG_SHIFT= 14,
	TRIG_BITS= TRIG_SHIFT,
	TRIG_MAGNITUDE= 1<<TRIG_SHIFT,

	ANGULAR_BITS= 16,
	NUMBER_OF_ANGLES= 1<<ANGULAR_BITS,
	FULL_CIRCLE= NUMBER_OF_ANGLES,
	QUARTER_CIRCLE= NUMBER_OF_ANGLES/4,
	HALF_CIRCLE= NUMBER_OF_ANGLES/2,
	THREE_QUARTER_CIRCLE= (3*NUMBER_OF_ANGLES)/4,
	EIGHTH_CIRCLE= NUMBER_OF_ANGLES/8,
	SIXTEENTH_CIRCLE= NUMBER_OF_ANGLES/16,

	SIGNIFICANT_ANGULAR_BITS= 10,
	NUMBER_OF_SIGNIFICANT_ANGLES= 1<<SIGNIFICANT_ANGULAR_BITS,
	ANGLE_ONE= 1<<(ANGULAR_BITS-SIGNIFICANT_ANGULAR_BITS),

	WORLD_FRACTIONAL_BITS= 9,
	WORLD_ONE= 1<<WORLD_FRACTIONAL_BITS,
	WORLD_ONE_HALF= WORLD_ONE/2,
	WORLD_ONE_FOURTH= WORLD_ONE/4,
	WORLD_THREE_FOURTHS= (3*WORLD_ONE)/4

};

#define FIXED_TO_SHORT_FIXED(f) ((f)>>(FIXED_FRACTIONAL_BITS-SHORT_FIXED_FRACTIONAL_BITS))
#define SHORT_FIXED_TO_FIXED(f) ((f)<<(FIXED_FRACTIONAL_BITS-SHORT_FIXED_FRACTIONAL_BITS))

#define FIXED_TO_FLOAT(f) (((double)(f))/(FIXED_ONE - 1))
#define FLOAT_TO_FIXED(f) ((fixed)((f)*(FIXED_ONE - 1)))

#define INTEGER_TO_FIXED(s) (((fixed)(s))<<FIXED_FRACTIONAL_BITS)
#define FIXED_TO_INTEGER(f) ((f)>>FIXED_FRACTIONAL_BITS)
#define FIXED_TO_INTEGER_ROUND(f) FIXED_TO_INTEGER((f)+FIXED_ONE_HALF)
#define FIXED_FRACTIONAL_PART(f) ((f)&(FIXED_ONE-1))

#define SHORT_FIXED_TO_FLOAT(f) (((double)(f))/SHORT_FIXED_ONE)
#define FLOAT_TO_SHORT_FIXED(f) ((short_fixed)((f)*(SHORT_FIXED_ONE + 0.5)))

#define INTEGER_TO_SHORT_FIXED(s) (((short_fixed)(s))<<SHORT_FIXED_FRACTIONAL_BITS)
#define SHORT_FIXED_TO_INTEGER(f) ((f)>>SHORT_FIXED_FRACTIONAL_BITS)
#define SHORT_FIXED_TO_INTEGER_ROUND(f) SHORT_FIXED_TO_INTEGER((f)+SHORT_FIXED_ONE_HALF)
#define SHORT_FIXED_FRACTIONAL_PART(f) ((f)&(SHORT_FIXED_ONE-1))

#define INTEGER_TO_WORLD(s) (((world_distance)(s))<<WORLD_FRACTIONAL_BITS)
#define WORLD_FRACTIONAL_PART(d) ((d)&((world_distance)(WORLD_ONE-1)))
#define WORLD_TO_INTEGER(d) ((d)>>WORLD_FRACTIONAL_BITS)

#define WORLD_TO_FIXED(w) (((fixed)(w))<<(FIXED_FRACTIONAL_BITS-WORLD_FRACTIONAL_BITS))
#define FIXED_TO_WORLD(f) ((world_distance)((f)>>(FIXED_FRACTIONAL_BITS-WORLD_FRACTIONAL_BITS)))

#define WORLD_TO_FLOAT(f) (((float)(f))/WORLD_ONE)
#define FLOAT_TO_WORLD(f) ((world_distance)((f)*WORLD_ONE))

#define ANGLE_TO_INTEGER_ANGLE(a) ((a)>>(ANGULAR_BITS-SIGNIFICANT_ANGULAR_BITS))
#define INTEGER_ANGLE_TO_ANGLE(a) ((a)<<(ANGULAR_BITS-SIGNIFICANT_ANGULAR_BITS))
#define NORMALIZE_ANGLE(a) ((a)&(FULL_CIRCLE-1))

#define FLAG(b) (1<<(b))

#define TEST_FLAG(f, b) ((f)&(byte)FLAG(b))
#define SWAP_FLAG(f, b) ((f)^=(byte)FLAG(b))
#define SET_FLAG(f, b, v) ((v) ? ((f)|=(byte)FLAG(b)) : ((f)&=(byte)~FLAG(b)))

#define TEST_FLAG16(f, b) ((f)&(word)FLAG(b))
#define SWAP_FLAG16(f, b) ((f)^=(word)FLAG(b))
#define SET_FLAG16(f, b, v) ((v) ? ((f)|=(word)FLAG(b)) : ((f)&=(word)~FLAG(b)))

#define TEST_FLAG32(f, b) ((f)&(unsigned long)FLAG(b))
#define SWAP_FLAG32(f, b) ((f)^=(unsigned long)FLAG(b))
#define SET_FLAG32(f, b, v) ((v) ? ((f)|=(unsigned long)FLAG(b)) : ((f)&=(unsigned long)~FLAG(b)))

#define FLOOR(n,f) ((n)<(f) ? (f) : (n))
#define CEILING(n,c) ((n)>(c) ? (c) : (n))
#define PIN(n,f,c) ((n) < (f) ? (f) : CEILING( (n), (c) ))

/* ---------- types */

typedef unsigned short word;
typedef unsigned char byte;
//typedef int boolean;
typedef byte short_boolean;
typedef unsigned long tag;
typedef unsigned long file_tag;
typedef file_tag tag;

typedef word angle;

typedef short short_world_distance;
typedef long world_distance;

typedef float real;

#define MIN( a, b ) ( (a) > (b) ? (b) : (a) )
#define MAX( a, b ) ( (a) < (b) ? (b) : (a) )

enum
{
	_game_scoring_attrition= 0, // most kill-points wins (game will end after a certain period of inactivity or if further play would not change the rankings)
	_game_scoring_steal_the_bacon, // [must have time limit] last guy to own the token wins (a neutral or contested ball does not end the game)
	_game_scoring_last_man_on_the_hill, // [must have time limit] last guy to own the flag wins (a neutral or contested flag does not end the game)
	_game_scoring_scavenger_hunt, // first team to touch all the balls wins
	_game_scoring_flag_rally, // first team to touch all the flags wins
	_game_scoring_capture_the_flag, // each team must own or be contesting at least one flag to remain alive (scored by kill-points)
	_game_scoring_balls_on_parade, // each team must own or be contesting at least one ball to remain alive (scored by kill-points)
	_game_scoring_territories, // [must have time limit] team with the most flags at endgame wins (ties due to contested or neutral flags do not end the game)
	_game_scoring_captures, // [must have time limit] team with the most balls at endgame wins (ties due to contested or neutral balls do not end the game)
	_game_scoring_king_of_the_hill, // [must have time limit]most time on hill wins (was royalty)
	_game_scoring_cattle_drive, // score by taking your marked units into the opponents end zone
	_game_scoring_assassination,
	_game_scoring_hunting,
	_game_scoring_custom, // map actions determine endgame
	NUMBER_OF_GAME_SCORING_TYPES,
	MAXIMUM_NUMBER_OF_GAME_SCORING_TYPES= 16
};

struct rgb_color
{
	word red, green, blue;
	
	word flags;
};

struct rectangle2d
{
	short top, left, bottom, right;
};

struct world_point3d
{
	world_distance x, y, z;
};
typedef struct world_point3d world_point3d;

struct world_vector3d
{
	short_world_distance i, j, k;
};
typedef struct world_vector3d world_vector3d;

struct fixed_vector3d
{
	fixed i, j, k;
};
typedef struct fixed_vector3d fixed_vector3d;

struct world_location3d
{
	world_point3d position;
	world_vector3d velocity;
	short_world_distance height; // height above ground (or under media?)
	
	angle yaw, pitch, roll;
};
typedef struct world_location3d world_location3d;

struct world_point2d
{
	world_distance x, y;
};
typedef struct world_point2d world_point2d;

struct short_world_point2d
{
	short_world_distance x, y;
};
typedef struct short_world_point2d short_world_point2d;

struct short_world_point3d
{
	short_world_distance x, y, z;
};
typedef struct short_world_point3d short_world_point3d;

struct world_plane3d
{
	// points are in front of the plane if a * x + b * y + c * z >= d
	short a, b, c;	// of TRIG_MAGNITUDE
	long d; // of magnitude TRIG_MAGNITUDE * WORLD_ONE
};
typedef struct world_plane3d world_plane3d;

struct short_world_rectangle2d
{
	short_world_point2d minimum_corner, maximum_corner;
};
typedef struct short_world_rectangle2d short_world_rectangle2d;

struct short_world_rectangle3d
{
	short_world_point3d minimum_corner, maximum_corner;
};
typedef struct short_world_rectangle3d short_world_rectangle3d;

struct world_rectangle2d
{
	world_point2d minimum_corner, maximum_corner;
};
typedef struct world_rectangle2d world_rectangle2d;

struct world_rectangle3d
{
	world_point3d minimum_corner, maximum_corner;
};

#endif
