#include <stdio.h>
#include <time.h>
#include "sgp.h"
#include "WCheck.h"
#include "Event Pump.h"
#include "Timer.h"
#include "Sound Control.h"
#include "Overhead.h"
#include "Weapons.h"
#include "Animation Control.h"
#include "opplist.h"
#include "Tactical Save.h"
#include <vector>
#include <queue>

#ifdef NETWORKED
#include "Networking.h"
#include "NetworkEvent.h"
#endif
#include "MemMan.h"
#include "Timer Control.h"
#include "DEBUG.H"

UINT8 gubEncryptionArray4[ BASE_NUMBER_OF_ROTATION_ARRAYS * 3 ][ NEW_ROTATION_ARRAY_SIZE ] =
{
	{
	177,131,58,218,175,130,210,
	59,25,190,170,189,227,245,
	104,118,7,168,136,178,184,
	4,27,64,199,101,160,24,
	83,177,178,232,185,40,122,
	109,38,253,160,14,133,106,
	190,206,58,102,244,229,124
	},

	{
	201,183,24,153,17,111,47,
	19,116,248,160,215,143,180,
	195,122,74,29,158,193,73,
	159,193,93,140,172,31,38,
	129,181,96,183,56,29,172,
	191,252,183,91,214,254,247,
	135,66,76,87,1,112,214
	},

	{
	28,138,132,173,9,230,220,
	57,32,166,202,153,246,49,
	119,246,212,1,50,230,19,
	135,20,173,235,182,61,143,
	76,162,155,224,182,54,123,
	29,223,119,200,175,10,66,
	87,171,204,12,1,44,68
	},

	{
	142,1,145,102,227,81,84,
	108,1,120,168,9,14,135,
	165,118,141,183,47,235,212,
	109,85,167,185,255,89,18,
	12,36,41,24,181,66,107,
	96,5,160,235,87,33,173,
	140,207,20,70,135,44,102
	},

	{
	85,38,191,199,157,183,122,
	186,2,236,106,181,53,100,
	69,189,22,137,117,230,153,
	150,211,184,157,220,165,234,
	113,19,238,122,120,233,181,
	130,182,140,76,219,162,90,
	66,242,19,125,8,215,162
	},

	{
	167,227,240,92,158,80,82,
	18,222,92,51,44,252,34,
	112,74,12,237,158,156,179,
	48,154,47,61,204,24,36,
	62,228,29,23,43,176,239,
	144,117,131,97,219,129,138,
	243,31,33,108,211,255,196
	},

	{
	83,29,187,49,130,95,252,
	214,6,223,87,149,168,140,
	172,33,170,24,103,180,107,
	63,212,92,143,155,126,129,
	190,25,211,244,151,103,7,
	51,227,119,104,18,177,110,
	33,155,104,15,159,62,103
	},

	{
	9,151,31,80,46,220,174,
	147,4,3,76,83,157,9,
	39,52,79,252,16,63,25,
	215,131,90,79,128,143,128,
	117,57,224,68,198,98,158,
	191,90,222,94,135,106,238,
	212,168,164,233,138,106,14
	},

	{
	159,70,200,99,183,101,85,
	117,251,218,149,119,199,12,
	102,190,144,68,145,212,202,
	250,32,118,13,149,136,91,
	203,247,68,69,124,122,248,
	92,125,154,189,60,160,12,
	148,182,162,108,187,198,113
	},

	{
	75,226,151,153,186,223,56,
	174,53,4,212,8,241,147,
	253,166,123,148,241,166,172,
	118,103,6,219,178,187,41,
	89,250,28,220,20,27,134,
	77,125,14,40,175,125,114,
	15,2,160,240,169,186,63
	},

	{
	165,251,182,208,45,34,74,
	41,106,244,193,205,160,100,
	51,41,232,106,237,201,184,
	35,112,98,118,238,38,211,
	191,33,221,226,126,55,61,
	224,82,255,19,252,131,188,
	220,111,242,172,93,61,67
	},

	{
	246,142,205,184,114,219,1,
	246,63,229,6,41,167,187,
	173,185,75,205,96,37,252,
	142,135,8,82,240,138,254,
	107,202,42,104,198,71,98,
	173,197,100,156,37,180,190,
	88,30,229,135,12,58,198
	},

	{
	7,121,166,123,114,32,78,
	223,125,21,155,124,116,240,
	222,91,57,5,254,51,4,
	161,122,236,49,146,88,235,
	253,149,42,31,140,254,163,
	71,253,70,242,115,10,171,
	101,38,217,187,117,31,141
	},

	{
	220,220,58,61,163,182,106,
	201,38,91,53,99,7,253,
	179,12,108,175,148,246,162,
	217,7,36,146,193,22,3,
	220,68,101,117,184,62,195,
	25,94,226,155,28,43,110,
	161,132,70,110,201,58,228
	},

	{
	39,253,170,4,47,122,100,
	182,223,98,128,205,167,103,
	42,16,227,30,43,181,80,
	212,194,100,164,123,181,97,
	126,145,213,51,44,135,240,
	100,105,151,106,174,180,134,
	106,49,72,73,237,2,84
	},

	{
	1,140,181,150,80,96,57,
	214,115,209,143,122,31,162,
	201,171,155,38,225,68,12,
	219,180,253,105,97,208,19,
	20,8,84,223,139,223,146,
	150,53,161,187,167,163,61,
	45,242,115,110,195,89,15
	},

	{
	50,197,196,115,105,176,64,
	87,141,157,64,185,202,118,
	158,70,79,168,121,141,57,
	163,128,141,228,192,195,115,
	15,227,176,28,130,126,54,
	75,200,45,202,7,158,179,
	77,23,142,127,110,31,141
	},

	{
	123,175,80,224,82,146,27,
	61,247,16,236,96,150,244,
	102,13,165,47,253,185,96,
	178,149,204,82,2,235,182,
	47,249,110,211,181,241,87,
	93,208,215,155,65,168,65,
	152,71,236,50,249,80,249
	},

	{
	139,219,5,39,213,136,215,
	228,108,228,169,234,173,243,
	229,45,65,105,121,208,18,
	202,118,209,11,19,178,162,
	59,74,82,99,111,28,119,
	6,217,203,9,252,227,146,
	217,194,195,213,12,221,229
	},

	{
	49,9,169,202,201,231,152,
	102,226,150,26,173,50,161,
	241,73,224,232,42,44,182,
	48,85,6,112,192,109,58,
	164,25,233,113,68,229,93,
	83,32,42,74,152,119,240,
	95,234,245,83,222,203,49
	},

	{
	58,104,2,6,164,206,186,
	224,222,73,218,87,103,158,
	186,30,242,149,198,193,89,
	94,43,38,197,36,33,64,
	7,136,243,253,80,61,90,
	223,72,116,47,46,190,94,
	50,77,217,111,227,35,30
	},

	{
	161,5,6,26,113,239,46,
	35,195,65,36,225,119,8,
	31,27,206,249,207,129,119,
	218,138,239,90,154,78,217,
	247,85,161,87,123,185,175,
	152,74,2,181,30,66,9,
	30,147,91,147,86,146,232
	},

	{
	111,204,65,49,124,16,12,
	149,51,137,89,252,190,203,
	155,194,84,231,136,213,197,
	202,212,73,251,17,80,12,
	106,75,180,1,15,52,1,
	36,27,194,180,13,226,151,
	210,106,27,190,237,194,16
	},

	{
	63,38,43,226,100,106,44,
	100,72,214,138,170,142,137,
	51,246,203,190,250,5,139,
	146,105,90,117,73,83,168,
	127,89,106,238,176,54,135,
	79,97,13,229,87,119,110,
	253,184,151,32,70,14,191
	},

	{
	3,134,209,61,87,248,16,
	140,69,243,241,249,240,83,
	184,156,4,81,67,134,241,
	25,176,185,228,181,65,200,
	143,165,255,165,222,193,94,
	146,188,178,68,171,218,177,
	198,3,208,189,1,204,100
	},

	{
	22,66,132,87,17,19,147,
	142,42,56,105,247,102,68,
	124,234,205,209,46,130,54,
	254,10,162,22,63,87,26,
	148,32,114,179,139,23,239,
	128,191,233,238,76,251,218,
	169,126,70,24,167,70,244
	},

	{
	156,153,114,200,16,71,190,
	214,189,154,249,102,57,40,
	212,144,211,72,187,194,106,
	32,131,241,173,161,83,169,
	128,245,153,168,115,72,94,
	90,15,107,218,206,232,88,
	162,109,52,236,54,42,212
	},

	{
	242,93,89,143,226,33,252,
	126,83,174,156,75,156,21,
	131,85,147,30,130,90,228,
	40,2,178,7,79,138,196,
	44,201,134,186,63,196,113,
	28,89,156,53,96,166,205,
	213,15,57,112,70,138,190
	},

	{
	148,127,27,140,97,157,84,
	2,67,71,99,182,13,250,
	113,100,84,156,156,16,242,
	216,176,107,248,176,40,208,
	235,220,159,243,169,56,65,
	159,199,244,77,142,201,210,
	81,198,4,7,43,126,122
	},

	{
	23,101,250,171,81,20,89,
	128,51,189,208,81,88,108,
	69,78,59,131,199,38,130,
	102,215,54,7,153,251,58,
	80,98,150,172,193,144,115,
	212,46,119,19,184,10,188,
	14,237,241,16,173,125,191
	},

	{
	97,19,206,235,176,242,227,
	101,12,97,196,163,218,152,
	104,40,3,63,3,39,15,
	31,4,138,217,199,156,12,
	239,16,55,165,35,249,155,
	252,132,220,53,22,68,104,
	63,246,158,93,50,126,104
	},

	{
	136,86,29,88,238,198,176,
	148,161,188,49,187,54,131,
	114,216,90,238,169,131,120,
	150,234,162,232,205,105,255,
	161,150,158,52,226,116,23,
	23,218,114,33,50,169,53,
	18,105,210,117,86,89,125
	},

	{
	178,13,149,148,121,91,82,
	38,29,64,153,12,44,11,
	161,74,139,68,88,35,124,
	42,191,86,119,137,56,127,
	38,40,69,17,89,107,234,
	226,90,137,67,200,96,232,
	79,43,143,239,180,33,81
	},

	{
	254,112,239,101,191,19,131,
	123,153,174,191,181,101,3,
	46,221,48,253,2,188,62,
	48,225,85,249,74,118,101,
	32,58,51,4,196,252,82,
	178,127,201,119,193,107,155,
	252,77,54,194,83,192,240
	},

	{
	141,117,43,233,154,235,63,
	50,253,75,91,22,195,180,
	105,62,225,65,245,173,73,
	222,82,82,21,138,31,105,
	125,103,13,104,162,169,56,
	165,203,198,233,117,38,240,
	39,243,174,64,209,60,76
	},

	{
	159,196,56,192,208,188,198,
	122,162,99,117,240,187,85,
	122,142,242,127,51,213,189,
	170,210,194,148,133,133,29,
	217,17,181,176,52,189,178,
	36,200,26,107,114,103,92,
	121,166,6,179,52,234,142
	},

	{
	164,250,146,128,92,129,33,
	77,59,62,251,236,133,203,
	203,174,137,91,50,172,10,
	10,235,227,82,61,235,101,
	200,199,150,159,83,13,162,
	42,100,220,210,25,21,56,
	254,76,23,196,161,169,214
	},

	{
	22,112,203,180,148,28,10,
	150,46,218,99,193,146,186,
	52,61,36,113,59,173,108,
	178,223,233,55,161,52,50,
	17,128,164,93,112,43,216,
	202,37,131,180,130,100,82,
	237,77,23,199,63,30,158
	},

	{
	47,156,173,221,226,110,149,
	164,39,71,206,74,250,7,
	218,158,122,242,131,252,231,
	165,119,158,248,92,168,3,
	119,157,186,136,214,160,95,
	7,206,124,253,149,155,145,
	105,46,239,35,23,126,58
	},

	{
	159,159,134,88,135,222,68,
	64,110,148,41,201,20,219,
	144,41,1,72,230,41,167,
	16,194,210,133,8,165,130,
	47,225,148,17,203,103,84,
	43,236,41,98,94,76,91,
	133,8,79,85,16,175,221
	},

	{
	115,161,236,118,192,144,104,
	255,59,191,32,78,18,14,
	108,203,171,32,254,80,206,
	178,84,132,206,60,193,226,
	4,8,188,193,118,133,91,
	87,13,9,191,67,23,181,
	124,134,134,191,130,95,195
	},

	{
	202,187,20,83,145,231,14,
	74,153,208,76,200,34,106,
	157,107,9,255,160,250,224,
	5,251,57,230,149,200,39,
	39,79,170,143,95,141,130,
	62,7,170,74,174,17,85,
	238,144,174,152,202,247,202
	},

	{
	173,144,151,112,43,60,201,
	219,175,238,226,103,153,58,
	119,15,237,206,33,193,243,
	253,102,63,183,24,77,166,
	242,11,72,143,127,79,246,
	188,238,128,118,67,87,183,
	175,79,239,6,108,52,153
	},

	{
	19,148,26,226,91,100,230,
	169,250,250,171,233,136,16,
	69,214,232,55,111,210,171,
	116,246,96,204,142,82,166,
	104,230,80,151,80,59,13,
	94,247,35,244,34,181,156,
	5,183,210,139,3,95,85
	},

	{
	125,219,35,9,131,243,232,
	189,133,142,219,41,228,14,
	55,114,188,66,24,210,163,
	124,99,75,61,165,94,228,
	127,6,12,114,246,253,243,
	77,231,101,85,4,164,200,
	117,117,240,63,15,76,203
	},

	{
	9,134,85,112,185,245,169,
	239,37,166,32,55,179,23,
	7,216,118,32,145,113,152,
	81,254,2,110,33,225,26,
	221,253,151,32,87,233,78,
	155,18,169,163,207,196,34,
	77,135,154,3,192,96,146
	},

	{
	75,91,117,7,210,246,189,
	146,84,107,248,11,41,245,
	123,204,73,243,191,15,151,
	245,1,109,44,157,204,112,
	153,55,210,68,226,149,209,
	80,22,29,254,243,76,121,
	172,17,1,242,167,176,116
	},

	{
	230,254,102,33,70,173,175,
	228,171,233,19,239,231,124,
	38,24,147,237,60,159,138,
	243,245,16,215,222,97,60,
	1,116,241,4,46,3,242,
	237,32,9,197,54,119,77,
	137,95,57,179,123,232,16
	},

	{
	183,187,60,61,212,166,108,
	187,190,151,215,122,188,39,
	86,57,254,185,238,247,79,
	142,209,107,232,255,138,122,
	212,48,23,47,163,228,255,
	32,224,187,246,195,5,116,
	28,160,96,142,147,222,171
	},

	{
	229,93,42,194,149,50,89,
	58,204,91,225,69,212,47,
	124,178,247,73,3,94,144,
	13,244,241,225,151,159,73,
	16,171,96,76,202,185,250,
	174,10,152,121,68,111,6,
	140,114,166,133,234,104,94
	},

	{
	186,157,156,42,213,188,78,
	242,32,136,103,58,86,99,
	171,229,203,151,101,196,15,
	109,148,140,4,130,208,135,
	52,214,212,167,66,145,243,
	54,61,240,104,223,212,87,
	181,68,19,247,26,217,165
	},

	{
	20,68,71,101,64,63,241,
	25,177,222,2,32,2,140,
	138,20,101,194,10,249,205,
	25,11,29,236,53,13,41,
	149,115,115,159,108,172,186,
	56,97,223,149,79,240,33,
	74,244,153,175,230,173,139
	},

	{
	112,160,137,249,193,254,166,
	20,237,27,169,28,25,166,
	89,133,11,238,230,171,153,
	149,249,253,37,58,38,48,
	226,198,210,91,107,161,50,
	129,73,109,104,128,240,157,
	106,209,245,142,188,44,209
	},

	{
	94,155,95,27,57,178,126,
	126,85,239,193,85,88,143,
	21,44,88,255,219,33,48,
	160,202,89,107,12,103,123,
	111,249,20,123,41,72,38,
	150,235,92,3,204,197,84,
	176,187,243,59,226,49,184
	},

	{
	202,228,64,73,214,118,70,
	4,246,243,163,181,137,217,
	140,24,167,19,201,69,35,
	1,179,95,32,201,86,26,
	111,210,1,98,46,226,39,
	226,217,237,225,141,89,245,
	240,244,44,2,143,156,58
	},

	{
	157,246,3,119,213,223,157,
	231,63,233,113,19,222,44,
	151,145,130,222,78,190,130,
	93,215,44,86,109,232,234,
	249,24,206,73,167,235,11,
	22,201,8,161,6,173,196,
	202,81,229,72,71,33,216
	},

	{
	245,6,229,112,241,89,47,
	99,172,118,22,20,193,113,
	230,122,251,107,255,10,232,
	55,158,24,188,30,159,178,
	246,6,211,101,134,171,245,
	216,223,48,231,212,198,167,
	71,142,46,234,237,200,4
	},
};

struct EVENT
{
	TIMER	TimeStamp;
	UINT32	uiFlags;
	UINT16	usDelay;
	UINT32	uiEvent;
	UINT32	uiDataSize;
	BYTE*	pData;

	EVENT(UINT16 delay, UINT32 event, UINT32 dataSize, BYTE* eventData) :
		TimeStamp(GetJA2Clock()),
		uiFlags(0),
		usDelay(delay),
		uiEvent(event),
		uiDataSize(dataSize),
		pData{ eventData }
	{
	}

	EVENT() :
		TimeStamp(GetJA2Clock()),
		uiFlags(0),
		usDelay(0),
		uiEvent(0),
		uiDataSize(0),
		pData{ nullptr }
	{}
};

#define			PRIMARY_EVENT_QUEUE			0
#define			SECONDARY_EVENT_QUEUE		1
#define			DEMAND_EVENT_QUEUE			2
#define			EVENT_EXPIRED				0x00000002

std::queue<EVENT> hEventQueue;
std::vector<EVENT> hDelayEventQueue;
std::queue<EVENT> hDemandEventQueue;

// GLobals used here, for each event structure used,
// Used as globals for stack reasons
EV_E_PLAYSOUND			EPlaySound;

EV_S_CHANGESTATE			SChangeState;
EV_S_CHANGEDEST				SChangeDest;
EV_S_SETPOSITION			SSetPosition;
EV_S_GETNEWPATH				SGetNewPath;
EV_S_BEGINTURN				SBeginTurn;
EV_S_CHANGESTANCE			SChangeStance;
EV_S_SETDIRECTION			SSetDirection;
EV_S_SETDESIREDDIRECTION	SSetDesiredDirection;
EV_S_BEGINFIREWEAPON		SBeginFireWeapon;
EV_S_FIREWEAPON				SFireWeapon;
EV_S_WEAPONHIT				SWeaponHit;
EV_S_STRUCTUREHIT			SStructureHit;
EV_S_WINDOWHIT				SWindowHit;
EV_S_MISS					SMiss;
EV_S_NOISE					SNoise;
EV_S_STOP_MERC				SStopMerc;
EV_S_SENDPATHTONETWORK		SUpdateNetworkSoldier;

extern	BOOLEAN				gfAmINetworked;


BOOLEAN ExecuteGameEvent( EVENT *pEvent );


BOOLEAN AddEvent(UINT32 uiEvent, UINT16 usDelay, PTR pEventData, UINT32 uiDataSize, UINT8 ubQueueID)
{
	BYTE* pData = (BYTE*)MemAlloc(uiDataSize);
	Assert(pData);
	memcpy(pData, pEventData, uiDataSize);

	// Add event to queue
	switch (ubQueueID)
	{
	case PRIMARY_EVENT_QUEUE:
		hEventQueue.emplace(usDelay, uiEvent, uiDataSize, pData);
		break;

	case SECONDARY_EVENT_QUEUE:
		hDelayEventQueue.emplace_back(usDelay, uiEvent, uiDataSize, pData);
		break;

	case DEMAND_EVENT_QUEUE:
		hDemandEventQueue.emplace(usDelay, uiEvent, uiDataSize, pData);
		break;

	default:
		Assert(FALSE);
		break;
	}

	return(TRUE);
}


static BOOLEAN RemoveEventFromSecondaryEventQueue(EVENT* ppEvent, UINT32 uiIndex)
{
	if (uiIndex >= hDelayEventQueue.size())
	{
		return(FALSE);
	}

	*ppEvent = hDelayEventQueue[uiIndex];
	hDelayEventQueue.erase(hDelayEventQueue.begin() + uiIndex);
	return(TRUE);
}


static BOOLEAN PopEvent(EVENT* ppEvent, UINT8 ubQueueID)
{
	// Get an event from queue, if one exists
	//
	switch (ubQueueID)
	{
	case PRIMARY_EVENT_QUEUE:
		if (!hEventQueue.empty())
		{
			*ppEvent = hEventQueue.front();
			hEventQueue.pop();
			return(TRUE);
		}
		break;

	case SECONDARY_EVENT_QUEUE:
		if (!hDelayEventQueue.empty())
		{
			*ppEvent = hDelayEventQueue.front();
			hDelayEventQueue.erase(hDelayEventQueue.begin());
			return(TRUE);
		}
		break;

	case DEMAND_EVENT_QUEUE:
		if (!hDemandEventQueue.empty())
		{
			*ppEvent = hDemandEventQueue.front();
			hDemandEventQueue.pop();
			return(TRUE);
		}
		break;

	default:
		Assert(FALSE);
		break;
	}

	return(FALSE);
}


static BOOLEAN FreeEventData(EVENT* pEvent)
{
	CHECKF(pEvent != NULL);

	MemFree(pEvent->pData);
	//MemFree(pEvent);

	return(TRUE);
}


UINT32 EventQueueSize(UINT8 ubQueueID)
{
	switch (ubQueueID)
	{
	case PRIMARY_EVENT_QUEUE:
		return(hEventQueue.size());
		break;

	case SECONDARY_EVENT_QUEUE:
		return(hDelayEventQueue.size());
		break;

	case DEMAND_EVENT_QUEUE:
		return(hDemandEventQueue.size());
		break;

	default:
		Assert(FALSE);
		return(-1);
		break;
	}
}


static BOOLEAN AddGameEventToQueue( UINT32 uiEvent, UINT16 usDelay, PTR pEventData, UINT8 ubQueueID )
{
	UINT32		uiDataSize;

	// Check range of Event ui
	if ( uiEvent < 0 || uiEvent > NUM_EVENTS )
	{
		// Set debug message!
			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Unknown event type");
			return( FALSE );
	}

	// Switch on event type and set size accordingly
	switch( uiEvent )
	{
			case E_PLAYSOUND:

				uiDataSize = sizeof( EV_E_PLAYSOUND );
				break;

			case S_CHANGESTATE:

				uiDataSize = sizeof( EV_S_CHANGESTATE );
				break;


			case S_CHANGEDEST:

				uiDataSize = sizeof( EV_S_CHANGEDEST );
				break;


			case S_SETPOSITION:

				uiDataSize = sizeof( EV_S_SETPOSITION );
				break;

			case S_GETNEWPATH:

				uiDataSize = sizeof( EV_S_GETNEWPATH );
				break;

			case S_BEGINTURN:

				uiDataSize = sizeof( EV_S_BEGINTURN );
				break;

			case S_CHANGESTANCE:

				uiDataSize = sizeof( EV_S_CHANGESTANCE );
				break;

			case S_SETDIRECTION:

				uiDataSize = sizeof( EV_S_SETDIRECTION );
				break;

			case S_SETDESIREDDIRECTION:

				uiDataSize = sizeof( EV_S_SETDESIREDDIRECTION );
				break;

			case S_FIREWEAPON:

				uiDataSize = sizeof( EV_S_FIREWEAPON );
				break;

			case S_BEGINFIREWEAPON:

				uiDataSize = sizeof( EV_S_BEGINFIREWEAPON );
				//Delay this event
				break;

			case S_WEAPONHIT:

				uiDataSize = sizeof( EV_S_WEAPONHIT );
				break;

			case S_STRUCTUREHIT:
				uiDataSize = sizeof( EV_S_STRUCTUREHIT );
				break;

			case S_WINDOWHIT:
				uiDataSize = sizeof( EV_S_STRUCTUREHIT );
				break;

			case S_MISS:
				uiDataSize = sizeof( EV_S_MISS );
				break;

			case S_NOISE:
				uiDataSize = sizeof( EV_S_NOISE );
				break;

			case S_STOP_MERC:
				uiDataSize = sizeof( EV_S_STOP_MERC );
				break;

			case S_SENDPATHTONETWORK:
				uiDataSize = sizeof(EV_S_SENDPATHTONETWORK);
				break;

			case 	S_UPDATENETWORKSOLDIER:
				uiDataSize = sizeof(EV_S_UPDATENETWORKSOLDIER);
				break;

			default:

				// Set debug msg: unknown message!
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Event Type mismatch");
				return( FALSE );

	}


	CHECKF( AddEvent( uiEvent, usDelay,	pEventData, uiDataSize, ubQueueID ) );

	// successful
	return( TRUE );
}


BOOLEAN AddGameEvent(UINT32 uiEvent, UINT16 usDelay, PTR pEventData)
{
	if (usDelay == DEMAND_EVENT_DELAY)
	{
		//DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("AddGameEvent: Sending Local and network #%d", uiEvent));
#ifdef NETWORKED
		if (gfAmINetworked)
			SendEventToNetwork(uiEvent, usDelay, pEventData);
#endif
		return(AddGameEventToQueue(uiEvent, 0, pEventData, DEMAND_EVENT_QUEUE));
	}
	else if (uiEvent < EVENTS_LOCAL_AND_NETWORK)
	{
		//DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("AddGameEvent: Sending Local and network #%d", uiEvent));
#ifdef NETWORKED
		if (gfAmINetworked)
			SendEventToNetwork(uiEvent, usDelay, pEventData);
#endif
		return(AddGameEventToQueue(uiEvent, usDelay, pEventData, PRIMARY_EVENT_QUEUE));
	}
	else if (uiEvent < EVENTS_ONLY_USED_LOCALLY)
	{
		//DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("AddGameEvent: Sending Local #%d", uiEvent));
		return(AddGameEventToQueue(uiEvent, usDelay, pEventData, PRIMARY_EVENT_QUEUE));
	}
	else if (uiEvent < EVENTS_ONLY_SENT_OVER_NETWORK)
	{
		//DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("AddGameEvent: Sending network #%d", uiEvent));
#ifdef NETWORKED
		if (gfAmINetworked)
			SendEventToNetwork(uiEvent, usDelay, pEventData);
#endif
		return(TRUE);
	}
	// There is an error with the event
	else
		return(FALSE);
}


BOOLEAN AddGameEventFromNetwork(UINT32 uiEvent, UINT16 usDelay, PTR pEventData)
{
	return(AddGameEventToQueue(uiEvent, usDelay, pEventData, PRIMARY_EVENT_QUEUE));
}


BOOLEAN	DequeAllGameEvents( BOOLEAN fExecute )
{
	EVENT pEvent;
	UINT32 uiQueueSize, i;
	BOOLEAN fCompleteLoop = FALSE;


	// First dequeue all primary events
	while( EventQueueSize( PRIMARY_EVENT_QUEUE ) > 0 )
	{
		// Get Event
		if (PopEvent( &pEvent, PRIMARY_EVENT_QUEUE) == FALSE )
		{
			return( FALSE );
		}

		if ( fExecute )
		{
			// Check if event has a delay and add to secondary queue if so
			if ( pEvent.usDelay > 0 )
			{
				AddGameEventToQueue( pEvent.uiEvent, pEvent.usDelay, pEvent.pData, SECONDARY_EVENT_QUEUE );
			}
			else
			{
				ExecuteGameEvent( &pEvent );
			}
		}

		// Delete event
		FreeEventData( &pEvent );
	};


	// NOW CHECK SECONDARY QUEUE FOR EVENTS
	uiQueueSize = EventQueueSize( SECONDARY_EVENT_QUEUE );

	for ( i = 0; i < uiQueueSize; i++ )
	{
		EVENT& pEventRef = hDelayEventQueue[i];
		// Check time
		if ( ( GetJA2Clock() - pEventRef.TimeStamp ) > pEventRef.usDelay )
		{
			if ( fExecute )
			{
				ExecuteGameEvent( &pEventRef );
			}

			// FLag as expired
			pEventRef.uiFlags = EVENT_EXPIRED;
		}
	}

	// Remove expired events from secondary event queue
	uiQueueSize = EventQueueSize(SECONDARY_EVENT_QUEUE);
	for (INT32 i = uiQueueSize-1; i >= 0; i--)
	{
		EVENT& pEventRef = hDelayEventQueue[i];
		if (pEventRef.uiFlags & EVENT_EXPIRED)
		{
			RemoveEventFromSecondaryEventQueue(&pEventRef, i);
			FreeEventData(&pEventRef);
		}
	}

	return( TRUE );
}


BOOLEAN DequeueAllDemandGameEvents( BOOLEAN fExecute )
{
	EVENT pEvent;

	// Dequeue all events on the demand queue (only)

	while( EventQueueSize( DEMAND_EVENT_QUEUE ) > 0 )
	{
		// Get Event
		if ( PopEvent( &pEvent, DEMAND_EVENT_QUEUE) == FALSE )
		{
			return( FALSE );
		}

		if ( fExecute )
		{
			// Check if event has a delay and add to secondary queue if so
			if ( pEvent.usDelay > 0 )
			{
				AddGameEventToQueue( pEvent.uiEvent, pEvent.usDelay, pEvent.pData, SECONDARY_EVENT_QUEUE );
			}
			else
			{
				ExecuteGameEvent( &pEvent );
			}
		}

		// Delete event
		FreeEventData( &pEvent );

	};

	return( TRUE );
}


BOOLEAN ExecuteGameEvent( EVENT *pEvent )
{
	SOLDIERTYPE		*pSoldier;

	// Switch on event type
	switch( pEvent->uiEvent )
	{
			case E_PLAYSOUND:

				memcpy( &EPlaySound, pEvent->pData, pEvent->uiDataSize );

				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Play Sound");
				PlayJA2Sample( EPlaySound.usIndex, EPlaySound.usRate, EPlaySound.ubVolume, EPlaySound.ubLoops, EPlaySound.uiPan );
				break;

			case S_CHANGESTATE:

				memcpy( &SChangeState, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SChangeState.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SChangeState.uiUniqueId )
				{
					break;
				}

				// Call soldier function
//				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Event Pump: ChangeState %S (%d)", gAnimControl[ SChangeState.ubNewState ].zAnimStr, SChangeState.usSoldierID ) );
				pSoldier->EVENT_InitNewSoldierAnim( SChangeState.usNewState, SChangeState.usStartingAniCode, SChangeState.fForce );
				break;

			case S_CHANGEDEST:

				memcpy( &SChangeDest, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SChangeDest.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Event Pump: Invalid Soldier ID #%d", SChangeDest.usSoldierID) );
					break;
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SChangeDest.uiUniqueId )
				{
					break;
				}

				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Change Dest");
				pSoldier->EVENT_SetSoldierDestination( (UINT8) SChangeDest.usNewDestination );
				break;

			case S_SETPOSITION:

				memcpy( &SSetPosition, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SSetPosition.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SSetPosition.uiUniqueId )
				{
					break;
				}

				// Call soldier function
//				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Event Pump: SetPosition ( %f %f ) ( %d )", SSetPosition.dNewXPos, SSetPosition.dNewYPos, SSetPosition.usSoldierID ) );
				pSoldier->EVENT_SetSoldierPosition( SSetPosition.dNewXPos, SSetPosition.dNewYPos );
				break;

			case S_GETNEWPATH:

				memcpy( &SGetNewPath, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SGetNewPath.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SGetNewPath.uiUniqueId )
				{
					break;
				}
				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: GetNewPath");
				pSoldier->EVENT_GetNewSoldierPath( SGetNewPath.sDestGridNo, SGetNewPath.usMovementAnim );
				break;

			case S_BEGINTURN:

				memcpy( &SBeginTurn, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SBeginTurn.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SBeginTurn.uiUniqueId )
				{
					break;
				}

				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: BeginTurn");
				pSoldier->EVENT_BeginMercTurn( FALSE, 0 );
				break;

			case S_CHANGESTANCE:

				memcpy( &SChangeStance, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SChangeStance.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SChangeStance.uiUniqueId )
				{
					break;
				}
				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: ChangeStance");
				pSoldier->ChangeSoldierStance( SChangeStance.ubNewStance );
				break;

			case S_SETDIRECTION:

				memcpy( &SSetDirection, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SSetDirection.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SSetDirection.uiUniqueId )
				{
					break;
				}

				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Event Pump: SetDirection: Dir( %d )", SSetDirection.usNewDirection)	);
				pSoldier->EVENT_SetSoldierDirection( SSetDirection.usNewDirection );
				break;

			case S_SETDESIREDDIRECTION:

				memcpy( &SSetDesiredDirection, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SSetDesiredDirection.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SSetDesiredDirection.uiUniqueId )
				{
					break;
				}

				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Event Pump: SetDesiredDirection: Dir( %d )", SSetDesiredDirection.usDesiredDirection)	);
				pSoldier->EVENT_SetSoldierDesiredDirection( (UINT8) SSetDesiredDirection.usDesiredDirection );
				break;


			case S_BEGINFIREWEAPON:

				memcpy( &SBeginFireWeapon, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SBeginFireWeapon.usSoldierID ) == FALSE )
				{
					pSoldier = NULL;
					break;
					// Handle Error?
					// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
				}

				// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SBeginFireWeapon.uiUniqueId )
				{
					break;
				}

				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Begin Fire Weapon");
				pSoldier->sTargetGridNo = SBeginFireWeapon.sTargetGridNo;
				pSoldier->bTargetLevel = SBeginFireWeapon.bTargetLevel;
				pSoldier->bTargetCubeLevel = SBeginFireWeapon.bTargetCubeLevel;
				pSoldier->EVENT_FireSoldierWeapon( SBeginFireWeapon.sTargetGridNo );
				break;

			case S_FIREWEAPON:

				memcpy( &SFireWeapon, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SFireWeapon.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

					// check for error
				if( pSoldier->uiUniqueSoldierIdValue != SFireWeapon.uiUniqueId )
				{
					break;
				}


				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: FireWeapon");
				pSoldier->sTargetGridNo = SFireWeapon.sTargetGridNo;
				pSoldier->bTargetLevel = SFireWeapon.bTargetLevel;
				pSoldier->bTargetCubeLevel = SFireWeapon.bTargetCubeLevel;
				FireWeapon( pSoldier, SFireWeapon.sTargetGridNo	);
				break;


			case S_WEAPONHIT:

				memcpy( &SWeaponHit, pEvent->pData, pEvent->uiDataSize );
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Event Pump: WeaponHit %d Damage", SWeaponHit.sDamage ) );
				WeaponHit( SWeaponHit.usSoldierID, SWeaponHit.usWeaponIndex, SWeaponHit.sDamage, SWeaponHit.sBreathLoss, SWeaponHit.usDirection, SWeaponHit.sXPos, SWeaponHit.sYPos, SWeaponHit.sZPos, SWeaponHit.sRange, SWeaponHit.ubAttackerID, SWeaponHit.fHit, SWeaponHit.ubSpecial, SWeaponHit.ubLocation );
				break;

			case S_STRUCTUREHIT:

				memcpy( &SStructureHit, pEvent->pData, pEvent->uiDataSize );
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Event Pump: StructureHit" ) );
				StructureHit( SStructureHit.iBullet, SStructureHit.usWeaponIndex, SStructureHit.bWeaponStatus, SStructureHit.ubAttackerID, SStructureHit.sXPos, SStructureHit.sYPos, SStructureHit.sZPos, SStructureHit.usStructureID, SStructureHit.iImpact, TRUE );
				break;

			case S_WINDOWHIT:

				memcpy( &SWindowHit, pEvent->pData, pEvent->uiDataSize );
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Event Pump: WindowHit" ) );
				WindowHit( SWindowHit.sGridNo, SWindowHit.usStructureID, SWindowHit.fBlowWindowSouth, SWindowHit.fLargeForce );
				break;

			case S_MISS:

				memcpy( &SMiss, pEvent->pData, pEvent->uiDataSize );
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Event Pump: Shot Miss ( obsolete )" ) );
				//ShotMiss( SMiss.ubAttackerID );
				break;

			case S_NOISE:
				memcpy( &SNoise, pEvent->pData, pEvent->uiDataSize );
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Event Pump: Noise from %d at %d/%d, type %d volume %d", SNoise.ubNoiseMaker, SNoise.sGridNo, SNoise.bLevel, SNoise.ubNoiseType, SNoise.ubVolume ) );
				OurNoise( SNoise.ubNoiseMaker, SNoise.sGridNo, SNoise.bLevel, SNoise.ubTerrType, SNoise.ubVolume, SNoise.ubNoiseType, SNoise.zNoiseMessage );
				break;

			case S_STOP_MERC:

				memcpy( &SStopMerc, pEvent->pData, pEvent->uiDataSize );

				// Get soldier pointer from ID
				if ( GetSoldier( &pSoldier, SStopMerc.usSoldierID ) == FALSE )
				{
					// Handle Error?
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Soldier ID");
					break;
				}

				if( pSoldier->uiUniqueSoldierIdValue != SStopMerc.uiUniqueId )
				{
					break;
				}

				// Call soldier function
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Event Pump: Stop Merc at Gridno %d", SStopMerc.sGridNo ));
				pSoldier->EVENT_StopMerc( SStopMerc.sGridNo, SStopMerc.ubDirection );
				break;


			default:

				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Event Pump: Invalid Event Received");
				return( FALSE );

	}

	return( TRUE );
}


BOOLEAN ClearEventQueue( void )
{
	// clear out the event queue
	EVENT pEvent;
	while( EventQueueSize( PRIMARY_EVENT_QUEUE ) > 0 )
	{
		// Get Event
		if (PopEvent( &pEvent, PRIMARY_EVENT_QUEUE) == FALSE )
		{
			return( FALSE );
		}
		FreeEventData(&pEvent);
	}

	return( TRUE );
}
