#pragma once
#include "Jass.h"
#include "Natives.h"
#include "myJASSConstants.h"
#include "MapBases.h"

extern HTIMER vTimerGame;

//typedef HPLAYER(fFun)(void);
typedef Single(fFun)(HTIMER);

struct sParamEndGame
{
	fFun *pFun;
	HTIMER *pTimerGame;
};

struct sRegionUnitClear
{
	real vX;
	real vY;
	real vRadius;
	unsigned short vIdDataUnit;
};

struct sStackChains
{
	unsigned short vIdStackChain;
	bool vMandatoryTrain;
	unsigned short vQTrain;
	unsigned short vNResearch;
	unsigned short vCommentUnit;
	integer vId;
	unsigned short vComment;
	unsigned short vStage;
	unsigned short vN;
	sStackChains *vNext;
	//sStackChains *vForerunner;
	char *vName;
	unsigned short vAction;
	bool vComplite;
	sStackChains *vForerunner;
	HumanPlayer *pHumanPlayer;
	bool vTimer;
	real vTime;
	unsigned short vStageParamPlayer;
};

struct sPlayerUser
{
	char vKeyPlayer[3];
	HPLAYER vPlayer;
	HPLAYERCOLOR vNPlayer;
	bool vDead;
	char vName[200];
	HTRIGGER hTriggerPlayerLeave;
	bool vLeave;
};

struct sRect
{
	unsigned short vX1;
    unsigned short vY1;
    unsigned short vX2;
    unsigned short vY2;
};

struct sRect2
{
	unsigned short vX1;
    unsigned short vY1;
    unsigned short vX2;
    unsigned short vY2;
	unsigned short vvi2,vvj2;
	unsigned short vInt;
	unsigned short vX;
    unsigned short vY;
	unsigned short vCount2;
	unsigned short vFill_1;
	unsigned short vFill_2;
	unsigned short vFlag;
	unsigned short vDiff;
};

struct sRect3
{
	short vX1;
    short vY1;
    short vX2;
    short vY2;
};

struct DataGoTo
{
	unsigned short vIdDataUnit;
	real vTimeGoTo;
	real vTimeElapsedGoTo;
	unsigned short* pFillMap;
	sRect *vMassRect;
	unsigned int *vMassRect2;
	unit vUnit;
	DataGoTo *next;

    unsigned int vR;
    unsigned short vX3;
    unsigned short vY3;
	sRect2 vRect4;
    unsigned short vX4;
    unsigned short vY4;
	sRect2 vRect5;
    unsigned int vInt2;
	unsigned short vFlagDT;
	unsigned int vR2;
	unsigned short vCurrentIntFill;
	unsigned short vNextIntFill;
	integer vId;
	real vX_Unit;
	real vY_Unit;
	unsigned short vCount;
	unsigned int vFlag;
	bool IdetPoPuti;

	sRect2 vRect1;
	sRect2 vRect2;
	sRect2 vRect3;
	sRect3 vRect3_2;
	sRect3 vRect3_3;
	unsigned int vN_Rect;
	unsigned int vN_Rect_2;
	unsigned int vN_Rect_3;
	unsigned int i2;
    real vRadius_Unit;
    unsigned short vDiff;
	unsigned int vvi,vvj,vvh;
	int vvz;

	unsigned int vInt3;
	unsigned short vResult;

	unsigned short vStorona;
	bool Fly;
	unsigned short vResultFill;
	unsigned int vIntFill;
	unsigned int i3;
	real vTime;
	bool vBoolTimer;
	bool vCelNeDostignuta;
	real vTimeForSpeed;
	unsigned short vAction;
	char *vActionStr;
	double vRad;
	int vNapravlenie;
	short vBC;
	short vAC;
	int vNapravlenie2;

	bool vPriority;

	HANDLE hThreadGoTo;

	integer vForerunnerClifLevel;
	integer vSubsequentClifLevel;
	bool vStartThread;
	unsigned short vCountBlink;
	unsigned int vMaxRect;

	float vTimeForBlink;
	unsigned int vMaxR;
	bool vFlag1;
	sRect2 vRect6;
	real vG;
	bool vTeleport1;
	bool vTeleport2;

	double vNapravlenieZ;
};

struct sDataSpell
{
	integer vId;
	real CoolDown;
	unsigned short lvl;
	real Damage;
	bool Available;
	bool vCast;
	real vRadius;
	real vTimeStartCoolDown;
	real vTimeEndCoolDown;
	real vMana;
	real vTimeCast;

	bool fInit()
	{
		vId = NULL;
		CoolDown = 0;
		lvl = 0;
		Damage = 0;
		Available = FALSE;
		vCast = FALSE;
		vRadius = 0;
		vTimeStartCoolDown = 0;
		vTimeEndCoolDown = 0;
		vMana = 0;
		vTimeCast = 0;
		return TRUE;
	}
};
 
class sReal
{
public:
    sReal(real v = 0) : value(v) 
    { }
    
    sReal & operator=(real v)
    {
        // тут добавляешь свое отслеживание
		if (v == 0)
		{
			value = v;
		}
		else
		{
			value = v;
		}
        value = v;
        return *this;
    }
    
    operator real() const
    {
        return value;
    }

	operator real *()
    {
        return &value;
    }

	real* operator&()
    {
        return &value;
    }

	const real operator-(const real& rv) const {
        return (value - rv);
    }

	const real operator+(const real& rv) const {
        return (value + rv);
    }

	const real operator-(const int& rv) const {
        return (value - rv);
    }

	const real operator+(const int& rv) const {
        return (value + rv);
    }

	const bool operator<(const real& rv) const {
        return (value < rv);
    }

	const bool operator>(const real& rv) const {
        return (value > rv);
    }
    
private:
    real value;
};

struct Coordinates
{
	real X;
	real Y;
};

struct DataUnit
{
	bool Permission;
	bool PermissionMove;
	bool Atakovan;
	bool Atakuet;
	unit TargetUnit;
	HTIMER vTimerAttacked;
	bool Move;
	bool Harvest;
	HTIMER vTimerMove;
	DataGoTo *pPut;
	unit WhichUnit;
	bool Zdanie;
	HPLAYERCOLOR vNPlayer;
	Coordinates LastCoordinates;
	bool Steals;
	real vTimeCompliteBuild;
	real vTimeStartBuild;
	real vTimeEndBuild;
	real vTimeCompliteResearch;
	real vTimeStartResearch;
	real vTimeEndResearch;
	real vTimeCompliteTrain;
	real vTimeStartTrain;
	real vTimeEndTrain;
	bool Train;
	integer vIdTrain;
	bool Postroeno;
	bool Upgrade;
	bool Upgrade2;
	bool fGetPostroeno()
	{
		if (this->Postroeno == TRUE)
		{
			return TRUE;
		}
		if (this->Zdanie == TRUE)
		{
			if (this->vTimeEndBuild < TimerGetElapsed(vTimerGame) &&
				(GetUnitState(this->WhichUnit, UNIT_STATE_MAX_LIFE) -
				GetUnitState(this->WhichUnit, UNIT_STATE_LIFE) <= 1))
			{
				this->Postroeno = TRUE;
				return TRUE;
			}
		}
		return FALSE;
	}
	bool Blinked;
	bool Researched;
	bool Researching;
	bool Flag;
	unsigned short vNResearch;
	integer vIdResearch;
	bool Lvl;

	bool vGoTo;
	integer vNlvl;
	bool Dead;
	HTRIGGER hTriggerUnitDeath;
	HTRIGGER hTriggerUnitResurrected;
	unsigned short vStorona;
	bool VidenProtivniku;
	integer vId;
	HPLAYER vPlayer;

	real vRadius_Unit;
    unsigned short vDiff;
	sRect2 vRect1;

	unsigned short vIdDataUnit;
	bool Fly;
	real vTimeForSpeed;

	HTRIGGER hTriggerUnitAllEvents;
	HTRIGGER hTriggerUnitConstructFinish;
	HTRIGGER hTriggerUnitResearchFinish;
	HTRIGGER hTriggerUnitResearchStart;
	
	unsigned short vAction;
	unsigned short vActionN;
	unsigned short vCountActions;
	unsigned short vActionFinish;

	unsigned short vIdBuild;
	integer vIntForGoTo;

	unsigned short vLastAction;

	char *vKeyUnit;
	bool vSync;
	bool vSyncClean;
	char *vKeyLocalPlayer;
	real vTimeSync;
	bool vAI;

	bool EnemyAdd;
	Coordinates LastCoordinatesForEnemy;
	Coordinates CoordinatesForGoToGlobal;
	bool vGoToGlobal;
	bool vPickupItem;
	bool vRaisingClifLevel;
	real vTimeRaisingClifLevel;

	sSmallCage *vHead;
	real vTimeGo;
	real vTimeGoTo;
	real vTimeGoBuild;
	bool vBoolTimeGoBuild;
	integer vIdOrder;

	char *vName;
	bool vHelping;
	unsigned short vStageHelp;
	real vTimeSignalToHelp;
	sBase *vHelpBase;
	unsigned int vInt3;
	integer vPosRepair;
	integer vPosHarvesting;
	real vTimeGoHarvesting;
	int vCountGoHarvesting;
	bool vHelpingReset;
	bool vFlagBuild;
	bool vFlagBuild2;
	HTRIGGER hTriggerUnitAttacked;

	void *pClass;
	int vNClass;

	real vTimeCast;
	real vTimeEndGoTo;

	real vTimeAttacked;
	unsigned short vCountBlink;
};

struct IdDataUnit
{
	unsigned short vId;
	DataUnit *pDataUnit;
	unsigned short vIdForComments;
};

struct ParamPlayer
{
	HPLAYER vPlayer;
	HPLAYERCOLOR vAI;
	unsigned short vStage;
	HTIMER vTimerPlayer;

	unsigned short MAX_UNIT;
	unsigned short MAX_RESEARCH;
	bool vResearch[300];
	IdDataUnit vUnit[300];

	static const unsigned short MAX_NAMBER_OF_TREES = 6;
	HDESTRUCTABLE vTree[MAX_NAMBER_OF_TREES];

	real vTimerGetElapsed;

	bool vSync;
	bool vSyncEnd;
	char vKeyAIPlayer[3];
	int vCountForLoopGame;

	bool fFree()
	{
		return TRUE;
	}

	bool fFreeAllTree()
	{
		unsigned short vvi;
		for (vvi = 0; vvi < MAX_NAMBER_OF_TREES; vvi++)
		{
			fFreeTree(vvi);
		}
		return TRUE;
	}

	bool fAddTree(HDESTRUCTABLE vDest)
	{
		unsigned short vvi;
		for (vvi = 0; vvi < MAX_NAMBER_OF_TREES; vvi++)
		{
			if (vTree[vvi] == 0)
			{
				vTree[vvi] = vDest;
				return TRUE;
			}
		}
		return FALSE;
	}

	bool fFreeTree(unsigned short vN)
	{
		if (vN < 0 || vN >= MAX_NAMBER_OF_TREES) return FALSE;
		vTree[vN] = 0;
		return TRUE;
	}

	bool fInit(unsigned short vQ_Units, unsigned short vQ_Researchs)
	{
		unsigned short vvi;
		MAX_UNIT = vQ_Units;
		MAX_RESEARCH = vQ_Researchs;
		for (vvi = 0; vvi < MAX_UNIT; vvi++)
		{
			fFreeUnit(vvi);
		}
		for (vvi = 0; vvi < MAX_RESEARCH; vvi++)
		{
			fFreeResearch(vvi);
		}
		for (vvi = 0; vvi < MAX_NAMBER_OF_TREES; vvi++)
		{
			fFreeTree(vvi);
		}
		vStage = 0;
		vTimerGetElapsed = 0;
		vSyncEnd = FALSE;
		vSync = FALSE;
		if (vAI >= 0 && vAI <= 16)
		{
			sprintf(vKeyAIPlayer,"%d\0",vAI);
		}
		else
		{
			sprintf(vKeyAIPlayer,"\0");
		}
		vCountForLoopGame = 0;
		return TRUE;
	}

	bool fFreeUnit(integer vN)
	{
		if (vN < 0 || vN >= MAX_UNIT) return FALSE;
		vUnit[vN].vId = -1;
		vUnit[vN].pDataUnit = NULL;
		vUnit[vN].vIdForComments = COMMENT_NO_UNIT;
		return TRUE;
	}

	bool fFreeResearch(integer vN)
	{
		if (vN < 0 || vN >= MAX_RESEARCH) return FALSE;
		vResearch[vN] = FALSE;
		return TRUE;
	}
};

struct StackForUnits
{
	IdDataUnit vIdDataUnit2;
	StackForUnits *next;
	unsigned short vIdForComments;
	unsigned short vN;
};

struct sDataUnit2
{
	sDataUnit2 *vNext;
	sDataUnit2 *vForerunner;
	unit vUnit;
	HPLAYER vPlayer;
	HPLAYERCOLOR vNPlayer;
	integer vId;
	unsigned short vIdDataUnit;
	unsigned short vN;
	DataUnit *pDataUnit;
};

struct sAction
{
	bool Busy;
	DataUnit *pDataUnit;
	integer vIdOrder;
	HLOCATION vLocation;
	integer vIdUnit;
	real vX;
	real vY;
	HWIDGET vTarget;
	int vNFunction;
	int vPriority;
	real vTimeAppointments;

	bool fCopy (sAction * pAction)
	{
		if (pAction == NULL) return FALSE;
		Busy = pAction->Busy;
		pDataUnit = pAction->pDataUnit;
		vIdOrder = pAction->vIdOrder;
		vLocation = pAction->vLocation;
		vIdUnit = pAction->vIdUnit;
		vX = pAction->vX;
		vY = pAction->vY;
		vTarget = pAction->vTarget;
		vNFunction = pAction->vNFunction;
		vPriority = pAction->vPriority;
		vTimeAppointments = pAction->vTimeAppointments;
		return TRUE;
	}
};

extern IdDataUnit vDataUnits[MAX_COUNT_UNITS];
extern void fAddAllDataUnitOfPlayerWorker(HPLAYER vPlayer);
extern void fAddAllDataUnitOfPlayer(HPLAYER vPlayer);
extern integer fFindIToMap (integer vIntIn);
extern unsigned short fDelDataUnit(unsigned short vIdDataUnit);
extern DataUnit * fGetDataUnit(HUNIT whichUnit);
extern bool fIsVampire(integer vId);
extern unsigned short fConverterX (real X);
extern unsigned short fConverterY (real Y);
extern real fG(real vX1, real vY1, real vX2, real vY2);
extern bool fFindIToMapCenter (integer vIntIn, real *vX, real *vY);
extern unsigned short fFindBaseByDataUnit (DataUnit *pDataUnit);
extern unsigned int fConvertXYToI (unsigned short vX, unsigned short vY);
extern unsigned short vMaxBase;
extern unsigned short vNLastStackForUnits;
extern unsigned short vQUnitsInBase[JASS_NumBase_MAX];
extern StackForUnits vStackForUnits[MAX_COUNT_UNITS];
extern bool fIsSlayer(integer vId);
extern bool fIsVampire(integer vId);
extern bool fIsMainHuman(integer vId);
extern bool fGetAttackRadius(integer vId, real *vRadius);
extern LongBool (__cdecl *_IssueImmediateOrderById) (HUNIT whichUnit, Integer order);
extern LongBool (__cdecl *_IssuePointOrderById) (HUNIT whichUnit, Integer order, PSingle x, PSingle y);
extern LongBool (__cdecl *_IssuePointOrderByIdLoc) (HUNIT whichUnit, Integer order, HLOCATION whichLocation);
extern LongBool (__cdecl *_IssueTargetOrderById) (HUNIT whichUnit, Integer order, HWIDGET targetWidget);
extern LongBool (__cdecl *_IssueBuildOrderById) (HUNIT whichPeon, Integer unitId, PSingle x, PSingle y);
extern void fLog(int vFlag, char *vText);
extern char vTest[1000];
extern bool fNullUnit(unit WhichUnit);
extern bool fNull2(unsigned int vUI);
extern sAction vMassActions[MAX_COUNT_UNITS];
extern int vNLastMassActions;
extern unsigned int fConverterI(real vX, real vY);
extern real fRadius_Unit (integer vID_UNIT);
extern int fPriorityAttackUnit(DataUnit *pDataUnit, DataUnit *pDataUnitTarget);
extern void fRefreshLastCoordinates(DataUnit *pDataUnit);
extern real vTimerGetElapsedGlobal;
extern integer vGlobalNAI;
extern bool fGetTimeCast(integer vId, real *vTimeCast);
extern unsigned short fRemoteness2(DataUnit* pDataUnit1, DataUnit* pDataUnit2);

class sAction2
{
public:
	char *vInfo;
	sAction *pAction;
	int vN;
	sAction2 *vNext;
	sAction2 *vForerunner;
	int vN_In;

	sAction2 ();
	~sAction2();
	bool fCopy(sAction2 *pAction2);
};

class sActionsPlayer
{
public:
	static const int MAX_Q_ACTIONS_PLAYER = 500;
	sAction2 vMassNActionsPlayer[MAX_Q_ACTIONS_PLAYER];
	int vLastN;
	int *pQActions;

	int vvi;
	int vvj;
	bool vFree;
	bool vSort;
	bool vRemove;
	sAction *pActionTest;
	sAction *pAction1;
	sAction *pAction2;
	sAction2 vTemp;
	int vNAction;
	int vNAction2;
	sAction2 *pActionLast;
	sAction2 *pAction2Test;

	sActionsPlayer ();
	void fInit (int *pQActions2);
	bool fAddAction2(sAction2 *vAddAction2);
	bool fCheckUnit(unit WhichUnit);
	sAction * fGetAction(unit WhichUnit);
	sAction2 * fGetAction2(unit WhichUnit);
	bool fDelActionUnit(unit WhichUnit);
	bool fDeleteAction2(int vN_In);
	bool fDeleteAction2(sAction2 *vAction2);
	bool fDeleteAction(sAction *vAction);
	bool fDelAllActions2();
	bool fDelAllActions();
	bool fSortNull();
	bool fRemoveOldActions();
	bool fSortPriority();
	sAction2 * fGetAction2First ();
	sAction2 * fGetAction2Last ();
	sAction * fNewAction();
	sAction2 * fNewAction2();
	sAction * fGetAction (int vN_In);
	sAction2 * fGetAction2 (sAction * pAction);
	sAction2 * fGetAction2 (int vN_In);
	bool fAddAction(unit WhichUnit, integer vIdOrder, integer vIdUnit, HLOCATION vLocation, real vX, real vY, HWIDGET vTarget, int vNFunction, int vPriority, real vTimeAppointments);
	int fNFreeAction();
	int fNFreeAction2();
};

class sStackActions
{
public:
	sActionsPlayer vActionsPlayer;
	sAction2 *vFirst;
	sAction2 *vLast;
	int vQActions;

	ParamPlayer *pParamPlayer;
	sAction2 *vToPerformAction;
	sAction2 *vTestAction2;
	sAction2 *vNext;
	int vvi;
	
	DataUnit *pTestDataUnit;
	real vTimerGetElapsed;

	~sStackActions();
	bool fInitStackActions(ParamPlayer *pParamPlayer2);
	bool fAddAction2ToStack(sAction2 *vAddAction2);
	bool fCheckUnit(unit WhichUnit);
	bool fDelAllActions2();
	bool fDelAllActions();
	void fSetTimerGetElapsed(real vTimerGetElapsed2);
	bool fAddAction(unit WhichUnit, integer vIdOrder, integer vIdUnit, HLOCATION vLocation, real vX, real vY, HWIDGET vTarget, int vNFunction, int vPriority, real vTimeAppointments);
	bool fRemoveOldActions();
	bool fCompare4(sAction2 *pActionOld, sAction2 *pActionNew);
	bool fCompare4(sAction2 *pAction, sStackActions * pStackActions);
	bool fCompare3(sAction2 *pActionOld, sAction2 *pActionNew);
	bool fCompare3(sAction2 *pAction, sStackActions * pStackActions);
	bool fCompare(sAction2 *pActionOld, sAction2 *pActionNew);
	bool fCompare(sAction2 *pAction, sStackActions * pStackActions);
	bool fCompare2(sAction2 *pActionOld, sAction2 *pActionNew);
	bool fCompare2(sAction2 *pAction, sStackActions * pStackActions);
	void fRefreshStack();
	bool fActionDistributor(sStackActions * pStackActions);
	bool fToPerform(sStackActions * pPreviousStackActions);
	bool fRestoreStackConnections();
	bool fSortPriority();
	Boolean IssueImmediateOrderById(HUNIT whichUnit, Integer order);
	Boolean IssuePointOrderById(HUNIT whichUnit, Integer order, Single x, Single y);
	Boolean IssuePointOrderByIdLoc(HUNIT whichUnit, Integer order, HLOCATION whichLocation);
	Boolean IssueTargetOrderById(HUNIT whichUnit, Integer order, HWIDGET targetWidget);
	Boolean IssueBuildOrderById(HUNIT whichPeon, Integer unitId, Single x, Single y);
};

struct sActionStackForDelAndCreateUnit
{
	sDataUnit2 *pCurrentDataUnit2;
	sDataUnit2 *pLastDataUnit2;
	sDataUnit2 vDataUnit2[MAX_COUNT_UNITS];
	unsigned short vNLastDataUnit2;

	unsigned short vN;
	integer vId;
	HPLAYER vPlayer;
	HPLAYERCOLOR vNPlayer;
	unsigned short vvi;
	sDataUnit2 *pDataUnit2;

	sDataUnit2 *vCurrent;
	sDataUnit2 *vNext;
	unsigned short vIdDataUnit;

	DataUnit *pDataUnit;

	bool fNullVar()
	{
		pCurrentDataUnit2 = NULL;
		pLastDataUnit2 = NULL;
		vNLastDataUnit2 = NO_UNIT;
		return TRUE;
	}

	bool fInit()
	{
		fNullVar();
		for (unsigned short vvi = 0; vvi < MAX_COUNT_UNITS; vvi++)
		{
			vDataUnit2[vvi].vNext = 0;
			vDataUnit2[vvi].vForerunner = 0;
			vDataUnit2[vvi].vUnit = 0;
			vDataUnit2[vvi].vIdDataUnit = NO_UNIT;
			vDataUnit2[vvi].vId = 0;
			vDataUnit2[vvi].vNPlayer = 0;
			vDataUnit2[vvi].vPlayer = 0;
			vDataUnit2[vvi].vN = vvi;
		}
		return TRUE;
	}

	bool fFreeOneStackForUnit(unsigned short vN)
	{
		if (vN < 0 || vN >= MAX_COUNT_UNITS) return FALSE;
		if (vDataUnit2[vN].vForerunner)
		{
			vDataUnit2[vN].vForerunner->vNext = vDataUnit2[vN].vNext;
		}
		else
		{
			if (vDataUnit2[vN].vNext)
			{
				pCurrentDataUnit2 = vDataUnit2[vN].vNext;
			}
			else
			{
				pCurrentDataUnit2 = NULL;
				pLastDataUnit2 = NULL;
			}
		}
		vDataUnit2[vN].vNext = 0;
		vDataUnit2[vN].vForerunner = 0;
		vDataUnit2[vN].vUnit = 0;
		vDataUnit2[vN].vId = 0;
		vDataUnit2[vN].vNPlayer = 0;
		vDataUnit2[vN].vPlayer = 0;
		vDataUnit2[vN].vIdDataUnit = NO_UNIT;
		return TRUE;
	}

	// Найти в стеке по vIdDataUnit
	sDataUnit2 * fFindDataUnit2(unsigned short vIdDataUnit)
	{
		if (vIdDataUnit < 0 || vIdDataUnit >= MAX_COUNT_UNITS) return NULL;
		for (vvi = 0; vvi < vNLastDataUnit2; vvi++)
		{
			if (vDataUnit2[vvi].vIdDataUnit == vIdDataUnit)
			{
				return &vDataUnit2[vvi];
			}
		}
		return NULL;
	}

	// Удалить из стека
	unsigned short fDelDataUnit(unsigned short vN)
	{
		if (vN < 0 || vN >= MAX_COUNT_UNITS) return 0;
		fFreeOneStackForUnit(vN);
		/*if (pLastDataUnit2)
		{
			pLastDataUnit2->vNext = &vDataUnit2[vIdDataUnit];
			pLastDataUnit2 = &vDataUnit2[vIdDataUnit];
		}
		else
		{
			pLastDataUnit2 = &vDataUnit2[vIdDataUnit];
			pCurrentDataUnit2 = &vDataUnit2[vIdDataUnit];
		}*/
		if (vN == vNLastDataUnit2)
		{
			if (vN > 0)
			{
				vNLastDataUnit2--;
			}
			else if (vN == 0)
			{
				vNLastDataUnit2 = NO_UNIT;
			}
		}
		return 1;
	}

	// Добавить в стек
	unsigned short fAddDataUnit(sDataUnit2 *pDataUnit2)
	{
		if (pDataUnit2 == NULL) return 0;
		vN = fFindFreeNInSteckDataUnit2();
		if (vN < 0 || vN >= MAX_COUNT_UNITS) return 0;
		vDataUnit2[vN].vNext = NULL;
		vDataUnit2[vN].vUnit = pDataUnit2->vUnit;
		vDataUnit2[vN].vId = pDataUnit2->vId;
		vDataUnit2[vN].vNPlayer = pDataUnit2->vNPlayer;
		vDataUnit2[vN].vPlayer = pDataUnit2->vPlayer;
		vDataUnit2[vN].vIdDataUnit = pDataUnit2->vIdDataUnit;
		vDataUnit2[vN].pDataUnit = pDataUnit2->pDataUnit;
		if (pLastDataUnit2)
		{
			vDataUnit2[vN].vForerunner = pLastDataUnit2;
			pLastDataUnit2->vNext = &vDataUnit2[vN];
			pLastDataUnit2 = &vDataUnit2[vN];
		}
		else
		{
			vDataUnit2[vN].vForerunner = NULL;
			pLastDataUnit2 = &vDataUnit2[vN];
			pCurrentDataUnit2 = &vDataUnit2[vN];
		}
		if (vN > vNLastDataUnit2)
		{
			vNLastDataUnit2 = vN;
		}
		return 1;
	}

	// Добавить в стек создания юнита
	unsigned short fCreateDataUnit(unit vUnit)
	{
		if (vUnit <= 0) return NO_UNIT;
		vId = GetUnitTypeId(vUnit);
		if (vId == 0)
		{
			sprintf(vTest,"TUT6!!!");
			fLog(888,vTest);
			//return NO_UNIT;
		}
		vPlayer = GetOwningPlayer(vUnit);
		vNPlayer = GetPlayerColor(vPlayer);
		vN = fFindFreeNInSteckDataUnit2(vId,vNPlayer);
		if (vN >= 0 && vN < MAX_COUNT_UNITS)
		{
			vDataUnit2[vN].vUnit = vUnit;
			vDataUnit2[vN].vId = vId;
			vDataUnit2[vN].vPlayer = vPlayer;
			vDataUnit2[vN].vNPlayer = vNPlayer;
			vDataUnit2[vN].vNext = NULL;
			if (pLastDataUnit2)
			{
				pLastDataUnit2->vNext = &vDataUnit2[vN];
				pLastDataUnit2 = &vDataUnit2[vN];
			}
			else
			{
				pLastDataUnit2 = &vDataUnit2[vN];
				pCurrentDataUnit2 = &vDataUnit2[vN];
			}
			return vN;
		}
		return NO_UNIT;
	}

	// Найти свободную позицию в стеке
	unsigned short fFindFreeNInSteckDataUnit2()
	{
		if (vNLastDataUnit2 == NO_UNIT)
		{
			vNLastDataUnit2 = MAX_OLD_UNITS + 1;
			return vNLastDataUnit2;
		}
		if (vNLastDataUnit2 >= 0 && vNLastDataUnit2 < MAX_COUNT_UNITS)
		{
			if (vNLastDataUnit2 + 1 < MAX_COUNT_UNITS)
			{
				vNLastDataUnit2++;
				return vNLastDataUnit2;
			}
			for (unsigned short vvi = vNLastDataUnit2; vvi >= 0; vvi--)
			{
				if (vDataUnit2[vvi].vUnit == 0)
				{
					vNLastDataUnit2 = vvi;
				}
				else
				{
					if (vvi == vNLastDataUnit2)
					{
						break;
					}
					else
					{
						return vNLastDataUnit2;
					}
				}
				if (vvi == 0) break;
			}
			for (unsigned short vvi = 0; vvi < vNLastDataUnit2; vvi++)
			{
				if (vDataUnit2[vvi].vUnit == 0)
				{
					return vvi;
				}
			}
		}
		return LIMIT_UNIT;
	}

	// Поиск свободного номера в стаке создания и удаления данных для юнитов
	unsigned short fFindFreeNInSteckDataUnit2(integer vId, HPLAYERCOLOR vNPlayer)
	{
		if (vId < 0 || vNPlayer < 0) return NO_UNIT;
		if (fIsSlayer(vId))
		{
			if (fGetDataUnit((unsigned short)(vNPlayer + 12)) != NULL)
			{
				return NO_UNIT;
			}
			return (unsigned short)(vNPlayer + 12);
		}
		if (fIsVampire(vId) ||
			fIsMainHuman(vId))
		{
			return (unsigned short)(vNPlayer);
		}
		return fFindFreeNInSteckDataUnit2();
	}
};

struct ActionStackForUnits
{
	StackForUnits *first;
	StackForUnits *last;
	//bool Busy;
	ParamPlayer *pParamPlayer;
	integer vQNewUnit;
	unsigned short vN;
	StackForUnits *pStackForUnits;
	StackForUnits *current;
	integer vIdOrderCurrent;
	int vvi;
	integer vQ;
	StackForUnits *next;
	HPLAYER vPlayer;
	DataUnit * pDataUnit;
	unsigned short vBase;
	unsigned short vMaxQ;
	StackForUnits *forerunner;
	StackForUnits *current2;

	DataUnit * fGetNearestUnit(DataUnit *pDataUnit);

	bool fInitStackForUnits(ParamPlayer *pParamPlayer2)
	{
		if (pParamPlayer2 == NULL) return FALSE;
		first = NULL;
		last = NULL;
		//Busy = FALSE;
		pParamPlayer = pParamPlayer2;
		vQNewUnit = 0;
		return TRUE;
	}

	unsigned short fFindFreeNInStackForUnits()
	{
		if (vNLastStackForUnits == NO_UNIT)
		{
			vNLastStackForUnits = 0;
			return vNLastStackForUnits;
		}
		if (vNLastStackForUnits >= 0 && vNLastStackForUnits < MAX_COUNT_UNITS)
		{
			if (vNLastStackForUnits + 1 < MAX_COUNT_UNITS)
			{
				vNLastStackForUnits++;
				return vNLastStackForUnits;
			}
			for (unsigned short vvi = vNLastStackForUnits; vvi >= 0; vvi--)
			{
				if (vStackForUnits[vvi].vIdDataUnit2.pDataUnit == 0)
				{
					vNLastStackForUnits = vvi;
				}
				else
				{
					if (vvi == vNLastStackForUnits)
					{
						break;
					}
					else
					{
						return vNLastStackForUnits;
					}
				}
				if (vvi == 0) break;
			}
			for (unsigned short vvi = 0; vvi < vNLastStackForUnits; vvi++)
			{
				if (vStackForUnits[vvi].vIdDataUnit2.pDataUnit == 0)
				{
					return vvi;
				}
			}
		}
		return LIMIT_UNIT;
	}

	bool fAddStackForUnits(unsigned short vId, DataUnit *pDataUnit, unsigned short vComment)
	{
		vN = fFindFreeNInStackForUnits();
		if (vN < 0 || vN >= MAX_COUNT_UNITS)
		{
			return FALSE;
		}
		pStackForUnits = &vStackForUnits[vN];
		pStackForUnits->vIdDataUnit2.vId = vId;
		pStackForUnits->vIdDataUnit2.pDataUnit = pDataUnit;
		pStackForUnits->vIdForComments = vComment;
		if (fAddStackForUnits(pStackForUnits) == FALSE)
		{
			fFreeOneStackForUnit(pStackForUnits);
		}
		return TRUE;
	}

	bool fFreeOneStackForUnit(StackForUnits *pStackForUnits)
	{
		if (pStackForUnits == NULL) return FALSE;
		pStackForUnits->next = 0;
		pStackForUnits->vIdDataUnit2.vId = NO_UNIT;
		pStackForUnits->vIdDataUnit2.pDataUnit = NULL;
		pStackForUnits->vIdDataUnit2.vIdForComments = COMMENT_NO_UNIT;
		pStackForUnits->vIdForComments = COMMENT_NO_UNIT;
		if (pStackForUnits->vN == vNLastStackForUnits)
		{
			if (pStackForUnits->vN > 0)
			{
				vNLastStackForUnits--;
			}
			else if (pStackForUnits->vN == 0)
			{
				vNLastStackForUnits = NO_UNIT;
			}
		}
		return TRUE;
	}

	bool fAddStackForUnits(StackForUnits *add)
	{
		//while(Busy == TRUE);
		if (add == NULL) return FALSE;
		add->next = NULL;
		if (!fNull2((unsigned int)last))
		{
			if (last->next == NULL)
			{
				last->next = add;
				last = add;
			}
			else
			{
				return FALSE;
			}
		}
		else
		{
			first = add;
			last = add;
			vQNewUnit = 0;
		}
		//add->Used = FALSE;
		if (add->vIdForComments == COMMENT_NEW_UNIT)
		{
			vQNewUnit++;
		}
		return TRUE;
	}

	StackForUnits * fGetStackForUnits(unsigned short vIdForComments)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				return current;
			}
			current = current->next;
		}
		return NULL;
	}

	integer fGetIdDataUnit(unsigned short vIdForComments)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				return current->vIdDataUnit2.vId;
			}
			current = current->next;
		}
		return NULL;
	}

	DataUnit * fGetDataUnit(unsigned short vIdForComments)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				return current->vIdDataUnit2.pDataUnit;
			}
			current = current->next;
		}
		return NULL;
	}

	DataUnit * fGetDataUnit(unsigned short vIdForComments, integer vId)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				if (current->vIdDataUnit2.pDataUnit)
				{
					if (current->vIdDataUnit2.pDataUnit->vId == vId)
					{
						return current->vIdDataUnit2.pDataUnit;
					}
				}
			}
			current = current->next;
		}
		return NULL;
	}

	DataUnit * fGetDataUnit(unsigned short vIdForComments, DataUnit* pDataUnit, integer vId)
	{
		if (pDataUnit == NULL) return NULL;
		real vRadius;
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				if (current->vIdDataUnit2.pDataUnit)
				{
					if (current->vIdDataUnit2.pDataUnit->vId == vId)
					{
						if (IsUnitVisible(current->vIdDataUnit2.pDataUnit->WhichUnit,pDataUnit->vPlayer) == TRUE)
						{
							fGetAttackRadius(pDataUnit->vId,&vRadius);
							if (vRadius > 0)
							if (fG(pDataUnit->LastCoordinates.X,
							       pDataUnit->LastCoordinates.Y,
							       current->vIdDataUnit2.pDataUnit->LastCoordinatesForEnemy.X,
							       current->vIdDataUnit2.pDataUnit->LastCoordinatesForEnemy.Y) <= vRadius)
							{
								return current->vIdDataUnit2.pDataUnit;
							}
						}
					}
				}
			}
			current = current->next;
		}
		return NULL;
	}

	IdDataUnit * fGetIdDataUnit(unsigned short vIdForComments, integer vId)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				if (current->vIdDataUnit2.pDataUnit)
				{
					if (current->vIdDataUnit2.pDataUnit->vId == vId)
					{
						return &current->vIdDataUnit2;
					}
				}
			}
			current = current->next;
		}
		return NULL;
	}

	DataUnit * fGetDataUnit(integer vId, bool vHarvest)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdDataUnit2.pDataUnit)
			{
				if (current->vIdDataUnit2.pDataUnit->vId == vId &&
					current->vIdDataUnit2.pDataUnit->Harvest == vHarvest)
				{
					return current->vIdDataUnit2.pDataUnit;
				}
			}
			current = current->next;
		}
		return NULL;
	}

	DataUnit * fGetDataUnit(unsigned short vIdForComments, integer vId, bool vHarvest)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				if (current->vIdDataUnit2.pDataUnit)
				{
					if (current->vIdDataUnit2.pDataUnit->vId == vId &&
						current->vIdDataUnit2.pDataUnit->Harvest == vHarvest)
					{
						return current->vIdDataUnit2.pDataUnit;
					}
				}
			}
			current = current->next;
		}
		return NULL;
	}

	DataUnit * fGetDataUnit(unsigned short vIdForComments, integer vId, integer vIdOrder)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				if (current->vIdDataUnit2.pDataUnit)
				{
					vIdOrderCurrent = GetUnitCurrentOrder(current->vIdDataUnit2.pDataUnit->WhichUnit);
					if (current->vIdDataUnit2.pDataUnit->vId == vId &&
						vIdOrderCurrent == vIdOrder)
					{
						return current->vIdDataUnit2.pDataUnit;
					}
				}
			}
			current = current->next;
		}
		return NULL;
	}

	DataUnit * fGetDataUnit(integer vId, integer vIdOrder)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdDataUnit2.pDataUnit && !fNull2((unsigned int)current->vIdDataUnit2.pDataUnit))
			{
				vIdOrderCurrent = GetUnitCurrentOrder(current->vIdDataUnit2.pDataUnit->WhichUnit);					
				if (current->vIdDataUnit2.pDataUnit->vId == vId &&
					vIdOrderCurrent == vIdOrder)
				{
					return current->vIdDataUnit2.pDataUnit;
				}
			}
			current = current->next;
		}
		return NULL;
	}

	unsigned short fGetComment(DataUnit *pDataUnit)
	{
		if (pDataUnit == NULL) return NO_UNIT;
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdDataUnit2.pDataUnit && !fNull2((unsigned int)current->vIdDataUnit2.pDataUnit))
			{
				if (current->vIdDataUnit2.pDataUnit == pDataUnit)
				{
					return current->vIdForComments;
				}
			}
			current = current->next;
		}
		return NO_UNIT;
	}

	bool fSetComment(unsigned short vIdForComments, integer vId, unsigned short vIdForCommentsNew)
	{
		current = first;
		current2 = NULL;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				if (current->vIdDataUnit2.pDataUnit)
				{
					if (current->vIdDataUnit2.pDataUnit->vId == vId ||
						current->vIdDataUnit2.pDataUnit->vIdTrain == vId)
					{
						//if (GetUnitTypeId(current->vIdDataUnit2.pDataUnit->WhichUnit) != 0)
						//{
							if (current2 == NULL)
							{
								current2 = current;
							}
						//}
					}
				}
			}
			current = current->next;
		}
		if (current2)
		{
			if (current2->vIdForComments == COMMENT_NEW_UNIT)
			{
				vQNewUnit--;
			}
			current2->vIdForComments = vIdForCommentsNew;
			//current->Used = TRUE;
			if (current2->vIdForComments != COMMENT_NEW_UNIT)
			{
				pParamPlayer->vUnit[current2->vIdForComments].vId = current2->vIdDataUnit2.vId;
				pParamPlayer->vUnit[current2->vIdForComments].pDataUnit = current2->vIdDataUnit2.pDataUnit;
				pParamPlayer->vUnit[current2->vIdForComments].vIdForComments = current2->vIdForComments;
			}
			return TRUE;
		}
		return FALSE;
	}

	bool fSetCommentAll(unsigned short vIdForComments, integer vId, unsigned short vIdForCommentsNew)
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == vIdForComments)
			{
				if (current->vIdDataUnit2.pDataUnit)
				{
					if (current->vIdForComments == COMMENT_NEW_UNIT)
					{
						vQNewUnit--;
					}
					if (current->vIdDataUnit2.pDataUnit->vId == vId)
					{
						current->vIdForComments = vIdForCommentsNew;
						//current->Used = TRUE;
					}
					
				}
			}
			current = current->next;
		}
		return true;
	}

	bool fIsUnit()
	{
m1:;
		if (!fNull2((unsigned int)first))
		{
			if (first->vIdDataUnit2.pDataUnit &&
				first->vIdDataUnit2.pDataUnit->Dead == FALSE)
			{
				return TRUE;
			}
			else
			{
				fFreeStackForUnits(first->vIdDataUnit2.vId);
				goto m1;
			}
		}
		return FALSE;
	}

	integer fGetQuantityUnits(integer vId)
	{
		vQ = 0;
		current = first;
		next = NULL;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdDataUnit2.pDataUnit)
			{
				if (current->vIdDataUnit2.pDataUnit->vId == vId ||
					current->vIdDataUnit2.pDataUnit->vIdTrain == vId)
				{
					if (GetUnitTypeId(current->vIdDataUnit2.pDataUnit->WhichUnit) != 0)
					{
						vQ++;
					}
				}
			}
			current = current->next;
		}
		return vQ;
	}

	integer fGetQuantityUnits()
	{
		vQ = 0;
		current = first;
		next = NULL;
		while (!fNull2((unsigned int)current))
		{
			if (!fNull2((unsigned int)current->vIdDataUnit2.pDataUnit))
			{
				if (GetUnitTypeId(current->vIdDataUnit2.pDataUnit->WhichUnit) != 0)
				{
					vQ++;
				}
			}
			current = current->next;
		}
		return vQ;
	}

	bool fFilterOutDead()
	{
		current = first;
		next = NULL;
		while (!fNull2((unsigned int)current))
		{
			next = current->next;
			if (!fNull2((unsigned int)current->vIdDataUnit2.pDataUnit))
			{
				pDataUnit = vDataUnits[current->vIdDataUnit2.pDataUnit->vIdDataUnit].pDataUnit;
				if (current->vIdDataUnit2.pDataUnit->Dead == TRUE ||
					current->vIdDataUnit2.pDataUnit != pDataUnit)
				{
					fFreeStackForUnits(current->vIdDataUnit2.vId);
				}
			}
			current = next;
		}
		return TRUE;
	}

	integer fFindInt(integer vId, unsigned short vBase)
	{
		current = first;
		next = NULL;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdDataUnit2.pDataUnit &&
				current->vIdDataUnit2.pDataUnit->vId == vId)
			{
				if (current->vIdDataUnit2.pDataUnit->Dead == TRUE ||
					GetUnitTypeId(current->vIdDataUnit2.pDataUnit->WhichUnit) == 0 ||
					(pParamPlayer != NULL &&
					IsVisibleToPlayer(current->vIdDataUnit2.pDataUnit->LastCoordinatesForEnemy.X,
									  current->vIdDataUnit2.pDataUnit->LastCoordinatesForEnemy.Y,
									  pParamPlayer->vPlayer) == TRUE &&
					IsUnitVisible(current->vIdDataUnit2.pDataUnit->WhichUnit,
								  pParamPlayer->vPlayer) == FALSE))
				{
					next = current->next;
					fFreeStackForUnits(current->vIdDataUnit2.vId);
					current = next;
					continue;
				}
				else
				{
					if (fFindBaseByDataUnit(current->vIdDataUnit2.pDataUnit) == vBase)
					{
						return fConvertXYToI(fConverterX(current->vIdDataUnit2.pDataUnit->LastCoordinatesForEnemy.X),
											 fConverterY(current->vIdDataUnit2.pDataUnit->LastCoordinatesForEnemy.Y));
					}
				}
			}
			current = current->next;
		}
		return vSizeMap;
	}

	DataUnit * fGetFirstUnit()
	{
		if (!fNull2((unsigned int)first))
		{
			return first->vIdDataUnit2.pDataUnit;
		}
		return NULL;
	}

	DataUnit * fFindNewUnit()
	{
		current = first;
		pDataUnit = NULL;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdDataUnit2.pDataUnit)
			{
				if (current->vIdForComments == COMMENT_NEW_UNIT)
				{
					pDataUnit = current->vIdDataUnit2.pDataUnit;
					fFreeStackForUnits(current->vIdDataUnit2.vId);
					return pDataUnit;
				}
			}
			current = current->next;
		}
		return pDataUnit;
	}

	unsigned short fFindBase()
	{
		current = first;
		next = NULL;
		for (int vvi = 0; vvi < vMaxBase+1; vvi++)
		{
			vQUnitsInBase[vvi] = 0;
		}
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdDataUnit2.pDataUnit)
			{
				if (current->vIdDataUnit2.pDataUnit->Dead == TRUE ||
					(pParamPlayer != NULL &&
					IsVisibleToPlayer(current->vIdDataUnit2.pDataUnit->LastCoordinatesForEnemy.X,
									  current->vIdDataUnit2.pDataUnit->LastCoordinatesForEnemy.Y,
									  pParamPlayer->vPlayer) == TRUE &&
					IsUnitVisible(current->vIdDataUnit2.pDataUnit->WhichUnit,
								  pParamPlayer->vPlayer) == FALSE))
				{
					next = current->next;
					fFreeStackForUnits(current->vIdDataUnit2.vId);
					current = next;
					continue;
				}
				else
				{
					vBase = fFindBaseByDataUnit(current->vIdDataUnit2.pDataUnit);
					if (vBase >= 1 && vBase <= vMaxBase)
						vQUnitsInBase[vBase]++;
					if (vBase == 0 ||
						vBase == JASS_SLAYERPLACE ||
						//vBase == JASS_DANCEPOOL ||
						vBase == JASS_PATH_BLIGHT ||
						vBase == JASS_WATER_LEVEL_1 ||
						vBase == JASS_PATH_NOWATER)
						vQUnitsInBase[0]++;
				}
			}
			current = current->next;
		}
		vMaxQ = 0;
		vBase = DO_NOT_FIND_BASE;
		for (int vvi = 0; vvi <= vMaxBase; vvi++)
		{
			if (vMaxQ < vQUnitsInBase[vvi] &&
				vQUnitsInBase[vvi] != 0)
			{
				vMaxQ = vQUnitsInBase[vvi];
				vBase = vvi;
			}
		}
		return vBase;
	}

	void fGetResearchFinish()
	{
		current = first;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdDataUnit2.pDataUnit && !fNull2((unsigned int)current->vIdDataUnit2.pDataUnit))
			{
				if (current->vIdForComments < COMMENT_NO_UNIT &&
					current->vIdDataUnit2.pDataUnit->Zdanie == TRUE &&
					current->vIdDataUnit2.pDataUnit->Researched == TRUE)
				{
					current->vIdDataUnit2.pDataUnit->Researched = FALSE;
					current->vIdDataUnit2.pDataUnit->Researching = FALSE;
					pParamPlayer->vResearch[current->vIdDataUnit2.pDataUnit->vNResearch] = TRUE;
				}
			}
			current = current->next;
		}
	}

	void fFreeStackForUnits(unsigned short vIdDataUnit)
	{
		current = first;
		next = NULL;
		forerunner = NULL;
		while (!fNull2((unsigned int)current))
		{
			next = current->next;
			if (current->vIdDataUnit2.vId == vIdDataUnit)
			{
				if (next)
				{
					if (forerunner)
					{
						forerunner->next = next;
					}
					else
					{
						first = next;
					}
				}
				else
				{
					if (forerunner)
					{
						last = forerunner;
						forerunner->next = NULL;
					}
					else
					{
						first = NULL;
						last = NULL;
					}
				}
				if (current->vIdForComments != COMMENT_NEW_UNIT && current->vIdForComments != COMMENT_NO_UNIT)
				{
					pParamPlayer->fFreeUnit(current->vIdForComments);
				}
				if (current->vIdForComments == COMMENT_NEW_UNIT)
				{
					vQNewUnit--;
				}
				fFreeOneStackForUnit(current);
				return;
			}
			forerunner = current;
			current = current->next;
		}
	}

	void fFreeStackForUnits(DataUnit *pDataUnit)
	{
		if (pDataUnit == NULL) return;
		current = first;
		next = NULL;
		forerunner = NULL;
		while (!fNull2((unsigned int)current))
		{
			next = current->next;
			if (pDataUnit && !fNull2((unsigned int)pDataUnit) &&
				current->vIdDataUnit2.pDataUnit && !fNull2((unsigned int)current->vIdDataUnit2.pDataUnit) &&
				pDataUnit == current->vIdDataUnit2.pDataUnit)
			{
				if (next)
				{
					if (forerunner)
					{
						forerunner->next = next;
					}
					else
					{
						first = next;
					}
				}
				else
				{
					if (forerunner)
					{
						last = forerunner;
						forerunner->next = NULL;
					}
					else
					{
						first = NULL;
						last = NULL;
					}
				}
				if (current->vIdForComments != COMMENT_NEW_UNIT && current->vIdForComments != COMMENT_NO_UNIT)
				{
					if (!fNull2((unsigned int)pParamPlayer))
					{
						pParamPlayer->fFreeUnit(current->vIdForComments);
					}
				}
				if (current->vIdForComments == COMMENT_NEW_UNIT)
				{
					vQNewUnit--;
				}
				fFreeOneStackForUnit(current);
				return;
			}
			forerunner = current;
			current = current->next;
		}
	}

	void fFreeStackForUnitsAll()
	{
		current = first;
		next = NULL;
		while (!fNull2((unsigned int)current))
		{
			if (current->vIdForComments == COMMENT_NEW_UNIT)
			{
				vQNewUnit--;
			}
			next = current->next;
			fFreeOneStackForUnit(current);
			current = next;
		}
		first = NULL;
		last = NULL;
	}
};

struct sInventory
{
	static const unsigned short MAX_SLOT = 6;
	HITEM vItemInSlot[MAX_SLOT];
	DataUnit *pDataUnit;
	integer vGold;
	integer vWood;
	integer vGoldPlayer;
	integer vWoodPlayer;
	real vG;
	integer vSlotByShop;
	bool vInit;

	sInventory ()
	{
		vInit = FALSE;
	}

	bool fInit(DataUnit *pDataUnit2)
	{
		if (pDataUnit == NULL) return FALSE;
		int vvi;
		for (vvi = 0; vvi < MAX_SLOT; vvi++)
		{
			vItemInSlot[vvi] = 0;
		}
		pDataUnit = pDataUnit2;
		vInit = TRUE;
		return TRUE;
	}

	bool fRefreshInventory()
	{
		if (fNull2((unsigned int)pDataUnit)) return FALSE;
		for (vSlotByShop = 0; vSlotByShop < MAX_SLOT; vSlotByShop++)
		{
			if (fSetItemToSlot(UnitItemInSlot(pDataUnit->WhichUnit,vSlotByShop),vSlotByShop) == FALSE)
			{
				return FALSE;
			}
		}
		return TRUE;
	}

	integer vQFreeSlots()
	{
		int vvi;
		integer vQ;
		vQ = 0;
		for (vvi = 0; vvi < MAX_SLOT; vvi++)
		{
			if (vItemInSlot[vvi] == 0)
			{
				vQ++;
			}
		}
		return vQ;
	}

	bool fAddItem(HITEM vItem)
	{
		if (vItem == NULL) return FALSE;
		int vvi;
		for (vvi = 0; vvi < MAX_SLOT; vvi++)
		{
			if (vItemInSlot[vvi] == 0)
			{
				vItemInSlot[vvi] = vItem;
				return TRUE;
			}
		}
		return FALSE;
	}

	bool fSetItemToSlot(HITEM vItem, integer vSlot)
	{
		if (vItem == NULL && (vSlot < 0 || vSlot > 6)) return FALSE;
		vItemInSlot[vSlot] = vItem;
		return TRUE;
	}

	integer fGetSlotByItem(HITEM vItem)
	{
		if (vItem == NULL) return NULL;
		int vvi;
		for (vvi = 0; vvi < MAX_SLOT; vvi++)
		{
			if (vItemInSlot[vvi] == vItem)
			{
				return vvi;
			}
		}
		return NULL;
	}

	HITEM fGetItem(integer vIdItem)
	{
		if (vIdItem == NULL) return NULL;
		int vvi;
		for (vvi = 0; vvi < MAX_SLOT; vvi++)
		{
			if (GetItemTypeId(vItemInSlot[vvi]) == vIdItem)
			{
				return vItemInSlot[vvi];
			}
		}
		return NULL;
	}

	integer fQItems(integer vIdItem)
	{
		if (vIdItem == NULL) return 0;
		int vvi;
		int vQ;
		vQ = 0;
		for (vvi = 0; vvi < MAX_SLOT; vvi++)
		{
			if (GetItemTypeId(vItemInSlot[vvi]) == vIdItem)
			{
				vQ++;
			}
		}
		return vQ;
	}
};

struct sUnitParam
{
	unit vTarget;
	real vHPTarget;
	//DataUnit *pDataUnit;
	//unsigned short vIdDataUnit;
	bool vAttack;
	real vRadiusAttack;
	bool vRetreat;
	IdDataUnit *pDataUnits;
	int vRole;
	//bool vHoldPosition;

};

struct sVampire
{
	sInventory vInventory;
	sUnitParam vUnitParam;
	sDataSpell vEnlightenment;
	sDataSpell vHealingwave;
	sDataSpell vStealth;
	sDataSpell vLightning;

	integer vHeroStr;
	integer vHeroAgi;
	integer vHeroInt;
	integer vHeroLevel;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vTarget = 0;
		vUnitParam.vRetreat = FALSE;
		vHeroStr = 0;
		vHeroAgi = 0;
		vHeroInt = 0;
		vHeroLevel = 0;
		return TRUE;
	}

};

struct sTini
{
	sUnitParam vUnitParam;
	bool vSmartFireInfernal;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vTarget = 0;
		vUnitParam.vRetreat = FALSE;
		return TRUE;
	}

};

struct sInfernal
{
	sUnitParam vUnitParam;
	bool vFire;
	real vTimeAttackTower;
	unit vForerunnerUnit;
	bool vSmartVampire;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vTarget = 0;
		vUnitParam.vRetreat = FALSE;
		return TRUE;
	}

};

struct sDataVampires
{
	static const unsigned short MAX_FARSIGHT = 2;
	static const unsigned short MAX_FARSIGHT_FOR_BASES = 108;
	bool vAttack;
	unsigned short vBaseHuman;
	DataGoTo *pPutGlobal;
	unsigned short vQFarsight;
	Coordinates vMassCoordinatesForFarsight[MAX_FARSIGHT];
	bool vBaseFarsight[MAX_FARSIGHT_FOR_BASES];
	real vTimeFarsight[MAX_FARSIGHT_FOR_BASES];
	unsigned short vCountFarsight;
	bool vWall;
	bool vTiniGo;
	DataUnit * pMainHumanBreeze;
	real vTimerMainHumanBreeze;
	bool vFlagBreeze;
	bool vTypeBazeOneCell;
	bool vDansePool;
	
	bool vKillInfernals;

	ActionStackForUnits vActionStackForUnitsEnemy;

	bool vFalgNextBase;
	real vTimeNextBase;
	real vLastProcHPWall;
	real vTimeAttackWall;
	real vTimerThread;

	bool fInit()
	{
		vBaseHuman = DO_NOT_FIND_BASE;
		vQFarsight = 0;
		vCountFarsight = 0;
		vWall = FALSE;
		vTiniGo = FALSE;
		pMainHumanBreeze = NULL;
		vTimerMainHumanBreeze = 0;
		vFlagBreeze = FALSE;
		vTypeBazeOneCell = FALSE;
		vDansePool = FALSE;
		vKillInfernals = FALSE;
		vFalgNextBase = FALSE;
		vTimeNextBase = 0;
		vLastProcHPWall = 0;
		vTimeAttackWall = 0;
		vAttack = FALSE;
		fRefreshAllFarsight();
		vTimerThread = 0;
		return TRUE;
	}

	bool fAddCoordinatesForFarsight(real vX, real vY)
	{
		if (vQFarsight >= MAX_FARSIGHT) return FALSE;
		vMassCoordinatesForFarsight[vQFarsight].X = vX;
		vMassCoordinatesForFarsight[vQFarsight].Y = vY;
		vQFarsight++;
		vCountFarsight++;
		return TRUE;
	}

	bool fNoFarsightBase()
	{
		int vvi;
		for (vvi = JASS_NumBase_MIN; vvi <= vMaxBase; vvi++)
		{
			if (vBaseFarsight[vvi] == FALSE) return FALSE;
		}
		return TRUE;
	}

	bool fNoFarsightPlus()
	{
		if (vBaseFarsight[JASS_SLAYERPLACE] == FALSE) return FALSE;
		if (vBaseFarsight[JASS_DANCEPOOL] == FALSE) return FALSE;
		if (vBaseFarsight[JASS_PATH_BLIGHT] == FALSE) return FALSE;
		return TRUE;
	}

	bool fFreeFarsight()
	{
		vQFarsight = 0;
		return TRUE;
	}

	bool fRefreshAllFarsight()
	{
		int vvi;
		for (vvi = 0; vvi <= MAX_FARSIGHT_FOR_BASES; vvi++)
		{
			vBaseFarsight[vvi] = FALSE;
		}
		vCountFarsight = 0;
		return TRUE;
	}

	bool fIsBaseFarsight(integer vBase)
	{
		if (vBase < JASS_NumBase_MIN || vBase > MAX_FARSIGHT_FOR_BASES) return FALSE;
		if (vBaseFarsight[vBase] == FALSE) return FALSE;
		return TRUE;
	}

	bool fNextBaseFarsight(unsigned short vFlag)
	{
		if (vQFarsight >= MAX_FARSIGHT) return FALSE;
		integer vBase;
		integer vCount;
		Coordinates vCoordinates;
		unsigned short vNBase;
		vCount = 0;
		if (vFlag == 0)
		while(vCount <= vMaxBase+10)
		{
			vBase = GetRandomInt(0,vMaxBase);//rand() % (vMaxBase + 1);
			if (vBase != 0 && fFindIToMap(vBase) != -1)
			if (fIlluminationOfBase(vBase) == TRUE) return TRUE;
			vCount++;
		}
		if (vFlag == 1)
		if (1)
		{
			if (1)
			{
				vBase = GetRandomInt(0,2);//rand() % (2 + 1);
				switch(vBase)
				{
				case 0:
					vBase = JASS_SLAYERPLACE;
					break;
				case 1:
					vBase = JASS_DANCEPOOL;
					break;
				case 2:
					vBase = JASS_PATH_BLIGHT;
					break;
				}
			}
			if (fIlluminationOfBase(vBase) == TRUE) return TRUE;
		}
		if (vFlag == 2)
		if (1)
		{
			while (vCount<JASS_NumBase_MAX)
			{
				vNBase = GetRandomInt(0,35);//rand()%36;
				if ((vMaxBase + 1 + vNBase) <= JASS_NumBase_MAX)
				if (vBaseFarsight[vMaxBase + 1 + vNBase] == FALSE)
				{
					vCoordinates.X = (16000 / 6)*(float)(vNBase%6) - 8000 + 1333;
					vCoordinates.Y = (-16000 / 6)*(float)(vNBase/6) + 8000 - 1333;
					vBaseFarsight[vMaxBase + 1 + vNBase] = TRUE;
					fAddCoordinatesForFarsight(vCoordinates.X,vCoordinates.Y);
					return TRUE;
				}
				vCount++;
			}
		}
		return FALSE;
	}

	bool fRefreshBaseFarsight(integer vBase)
	{
		if (vBase < 0 || vBase > MAX_FARSIGHT_FOR_BASES) return FALSE;
		vBaseFarsight[vBase] = FALSE;
		return TRUE;
	}

	bool fIlluminationOfBase(integer vBase)
	{
		if (vBase < 0 || vBase > MAX_FARSIGHT_FOR_BASES) return FALSE;
		if (vBaseFarsight[vBase] == TRUE) return FALSE;
		Coordinates vCoordinatesBase;
		if (fFindCoordinatesBase(vBase,&vCoordinatesBase.X,&vCoordinatesBase.Y) == FALSE) return FALSE;
		if (fAddCoordinatesForFarsight(vCoordinatesBase.X,vCoordinatesBase.Y) == FALSE) return FALSE;
		vBaseFarsight[vBase] = TRUE;
		return TRUE;
	}

	bool fFindCoordinatesBase(integer vBase, real *vX, real *vY)
	{
		if (vBase < 0 || vBase > MAX_FARSIGHT_FOR_BASES) return FALSE;
		if (vBase == 0)
		{
			*vX = -1500;
			*vY = -1500;
		}
		else
		{
			if (fFindIToMapCenter(vBase,vX,vY) == FALSE) return FALSE;
		}
		return TRUE;
	}
};

struct sMainHuman
{
	sUnitParam vUnitParam;
	Integer vPosRepair;
	sDataSpell vManaBurn;
	real vTimeResearchEndRifles;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_BUILDER;
		vUnitParam.vTarget = 0;
		vPosRepair = 0;
		vManaBurn.fInit();
		vTimeResearchEndRifles = 0;
		return TRUE;
	}
};

struct sSlayer
{
	sUnitParam vUnitParam;

	sDataSpell vTrackerSpell;
	sDataSpell vAvatarSpell;
	sDataSpell vImmortalityBuildSpell;
	sDataSpell vEnsnareSpell;

	integer vHeroStr;
	integer vHeroAgi;
	integer vHeroInt;
	integer vHeroLevel;
	
	HITEM vGoldCoin;
	bool vJumpSlayerToManaWell;
	bool vJumpSlayerToSlayerPlace;
	bool vVampireToManaWell;
	bool vJumpSlayerToBase;
	bool vFewHPSlayer;
	bool vScoutingBySlayer;
	bool vTimeManaWell;
	bool vHoardSlayerToMana;
	bool vJampSlayerDefence;
	bool vSlayerInBase;
	bool vSlayerGoBuyToolKit;
	bool vSlayerGoInvulnerability;
	bool vSlayerGoInBase;
	bool vSlayerCallTheEngineers;
	bool vSlayerEngineersAreCalledIn;

	bool vSlayerInit;
	bool vSlayerResurrected;

	real vTimeSlayerOnManaWell;

	sInventory vInventorySlayer;

	real vTimeHPSlayer;
	real vTimeResSlayer;
	bool vSlayerDefense;
	sBase * vBaseSlayerDefense;

	bool vAvatar;
	bool vTracker;
	bool vTrackerCalled;
	unsigned int vPosSlayerDefense;

	bool vTwoMinutes;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_ATTACKER;
		vUnitParam.vTarget = 0;
		vTrackerSpell.fInit();
		vAvatarSpell.fInit();
		vImmortalityBuildSpell.fInit();
		vEnsnareSpell.fInit();
		
		vGoldCoin = 0;
		vJumpSlayerToManaWell = FALSE;
		vHoardSlayerToMana = FALSE;
		vJumpSlayerToSlayerPlace = FALSE;
		vVampireToManaWell = FALSE;
		vJumpSlayerToBase = FALSE;
		vJampSlayerDefence = FALSE;
		vSlayerInBase = FALSE;
		vSlayerGoBuyToolKit = FALSE;
		vSlayerGoInvulnerability = FALSE;
		vSlayerGoInBase = FALSE;
		vSlayerCallTheEngineers = FALSE;
		vSlayerEngineersAreCalledIn = FALSE;
		vSlayerInit = FALSE;
		vSlayerResurrected = FALSE;
		vFewHPSlayer = FALSE;
		vTimeSlayerOnManaWell = 0;
		vScoutingBySlayer = FALSE;
		vTimeHPSlayer = 0;
		vTimeManaWell = FALSE;
		vTimeResSlayer = 0;
		vSlayerDefense = FALSE;
		vBaseSlayerDefense = NULL;
		vAvatar = FALSE;
		vTracker = FALSE;
		vTrackerCalled = FALSE;
		vTwoMinutes = FALSE;
		vHeroStr = 0;
		vHeroAgi = 0;
		vHeroInt = 0;
		vHeroLevel = 0;
		return TRUE;
	}
};

struct sWorker
{
	sUnitParam vUnitParam;
	Integer vPosHarvester;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_HARVESTER;
		vUnitParam.vTarget = 0;
		vPosHarvester = 0;
		return TRUE;
	}
};

struct sFurbolg
{
	sUnitParam vUnitParam;
	Integer vPosRepair;
	Integer vPosHarvester;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_HARVESTER;
		vUnitParam.vTarget = 0;
		vPosRepair = 0;
		vPosHarvester = 0;
		return TRUE;
	}
};

struct sOrc
{
	sUnitParam vUnitParam;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_BUILDER;
		vUnitParam.vTarget = 0;
		return TRUE;
	}
};

struct sSven
{
	sUnitParam vUnitParam;
	Integer vPosHarvester;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_HARVESTER;
		vUnitParam.vTarget = 0;
		vPosHarvester = 0;
		return TRUE;
	}
};

struct sOgonek
{
	sUnitParam vUnitParam;
	Integer vPosHarvester;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_HARVESTER;
		vUnitParam.vTarget = 0;
		vPosHarvester = 0;
		return TRUE;
	}
};

struct sSatyr
{
	sUnitParam vUnitParam;
	Integer vPosHarvester;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_HARVESTER;
		vUnitParam.vTarget = 0;
		vPosHarvester = 0;
		return TRUE;
	}
};

struct sGoblin
{
	sUnitParam vUnitParam;
	Integer vPosRepair;

	bool fInit()
	{
		vUnitParam.vAttack = FALSE;
		vUnitParam.vRadiusAttack = 0;
		vUnitParam.vRole = CONST_ROLE_HARVESTER;
		vUnitParam.vTarget = 0;
		vPosRepair = 0;
		return TRUE;
	}
};


struct sDataHumans
{
	ActionStackForUnits vActionStackForUnitsEnemy;
	ActionStackForUnits vActionStackForUnitsEnemy2;
	bool vFlagHelp1;
	sBase *vBaseHelp1;
	bool vFlagHelp2;
	sBase *vBaseHelp2;
	bool vFirstGold;
	bool vBuyGold;
	bool vAttackGrave;
	real vTimeSignalToHelp;
	bool vEra1All;
	bool vVampireToManaWell;
	
	Coordinates vCoordinatesSlayerPlace;
	Coordinates vCoordinatesManaWell;

	sBase *vBaseHelp1Wall;
	sBase *vBaseHelp2Wall;

	static const unsigned short MAX_Q_NUM_FOR_MASS_REGION_CLEAR_ZERO = 100;
	static const unsigned short NO_Q_NUM_FOR_MASS_REGION_CLEAR_ZERO = 101;
	sRegionUnitClear vMassRegionClearZero[MAX_Q_NUM_FOR_MASS_REGION_CLEAR_ZERO];
	unsigned short vMaxQMassRegionClearZero;

	Coordinates vCoordinatesSlayerDefence[MAX_HUMAN_PLAYERS];

	bool vMassHelpingMainHuman[MAX_HUMAN_PLAYERS];

	int vAI_BUILDER_MANA;

	int vCountGrive;

	static const unsigned short MAX_VAMPIRES = MAX_PLAYERS;
	sVampire vVampire[MAX_VAMPIRES];
	unsigned short vQVampires;

	bool fInit()
	{
		vFlagHelp1 = FALSE;
		vBaseHelp1 = NULL;
		vFlagHelp2 = FALSE;
		vBaseHelp2 = NULL;
		vFirstGold = FALSE;
		vBuyGold = FALSE;
		vAttackGrave = FALSE;
		fFindIToMapCenter(JASS_SLAYERPLACE,&vCoordinatesSlayerPlace.X,&vCoordinatesSlayerPlace.Y);
		vCoordinatesManaWell.X = 0;
		vCoordinatesManaWell.Y = 256;
		vTimeSignalToHelp = 0;
		vEra1All = FALSE;
		vVampireToManaWell = TRUE;
		vBaseHelp1Wall = NULL;
		vBaseHelp2Wall = NULL;
		for (unsigned short vvi = 0; vvi < MAX_Q_NUM_FOR_MASS_REGION_CLEAR_ZERO; vvi++)
		{
			vMassRegionClearZero[vvi].vIdDataUnit = MAX_COUNT_UNITS;
			vMassRegionClearZero[vvi].vRadius = 0;
			vMassRegionClearZero[vvi].vX = 0;
			vMassRegionClearZero[vvi].vY = 0;
		}
		vMaxQMassRegionClearZero = NO_Q_NUM_FOR_MASS_REGION_CLEAR_ZERO;
		for (unsigned short vvi = 0; vvi < MAX_HUMAN_PLAYERS; vvi++)
		{
			vCoordinatesSlayerDefence[vvi].X = 0;
			vCoordinatesSlayerDefence[vvi].Y = 0;
		}
		for (unsigned short vvi = 0; vvi < MAX_HUMAN_PLAYERS; vvi++)
		{
			vMassHelpingMainHuman[vvi] = FALSE;
		}
		vAI_BUILDER_MANA = -1;
		vCountGrive = 0;
		vQVampires = 0;
		for (unsigned short vvi = 0; vvi < MAX_VAMPIRES; vvi++)
		{
			vVampire[vvi].fInit();
		}
		return TRUE;
	}
};

//struct sPlaceWork;
//struct sStackWorks;

#ifndef S_POS_WORK_ARRAY_H
#define S_POS_WORK_ARRAY_H
class sPosWork;
class sPlaceWork;
class sStackWorks;
class sPosWorkArray
{
public:
	typedef sStackWorks sStackWorks_Type;
	typedef sPosWork sPosWork_Type;
	typedef sPlaceWork sPlaceWork_Type;
private:
	unsigned m_size;			//количество ячеек
	//sPosWork_Type *arr;			//указательная переменная в качестве массива
	sPlaceWork_Type * pPlaceWork;
public:
	void fInit (sPlaceWork_Type * pPlaceWork2);
	sPosWork_Type * fGet( int i );
	sPosWork_Type& operator[](const int index);
 
	explicit sPosWorkArray(const unsigned size = 0);		//прототип конструктора с параметром, для задания количества ячеек arr
	~sPosWorkArray();			//прототип деструктора
	unsigned size() const;		//функция для вытаскивания количества ячеек arr
};
#endif

#ifndef S_POS_WORK_H
#define S_POS_WORK_H
class sPlaceWork;
class sPosWork
{
public:
	typedef sPlaceWork sPlaceWork_Type;
	//friend class sPlaceWork;
	//friend class sStackWorks;
	bool vBusy2;
	int vN;
	//int vType;
	DataUnit *pDataUnit;
	Coordinates vPos;
	integer vPosHarvesting;
	//sPlaceWork *pPlaceWork;
	bool vBusy;
	bool vHarvest;
	real vG;
	bool vGougedOut;
	sPlaceWork_Type * pPlaceWork;

	sPosWork();
	void fInit (sPlaceWork_Type * pPlaceWork2);
	void fClear ();
	~sPosWork ();
	bool fNewPosWork();
	bool fDeletePosWork();
	/*void* operator new(size_t size);
	void operator delete(void* ptr);
	void* operator new[](size_t size);
	void operator delete[](void* ptr);*/
	bool fCopy (sPosWork * vPosWork);
};
//typedef sPosWork sPosWork2;
#endif

#ifndef S_PLACE_WORK_H
#define S_PLACE_WORK_H
class sPosWork;
class sStackWorks;
class sPosWorkArray;
class sPlaceWork
{
public:
	typedef sPosWork sPosWork_Type;
	typedef sStackWorks sStackWorks_Type;
	typedef sPosWorkArray sPosWorkArray_Type;
	//friend class sPosWork;
	//friend class sStackWorks;
	bool vBusy;
	int vType;
	int vTypeWood;
	DataUnit *pDataUnit;
	real vDistanceWork;
	real vRadiusUnit;
	sPosWorkArray_Type pPosWork;
	static const int MAX_Q_POS_WORKS = 13;
	int vMassNPosWork[MAX_Q_POS_WORKS];
	int vLastN;
	int vQ_PosWork;
	int vQ_PosWorkHarvest;
	int vQ_PosWorkSide;

	int vvi;
	int vvj;
	int vvz;
	int vvn;
	int vTemp_Q;
	bool vFree;
	int vNPosWork;
	sPosWork_Type * pPosWorkTest;
	sStackWorks_Type * pStackWorks;
	//sPosWorkArray_Type vPosWorkArray;

	sPlaceWork ();
	void fInit (sStackWorks_Type * pStackWorks2);
	~sPlaceWork ();
	bool fCopy (sPlaceWork * vPlaceWork);
	bool fCreatePosWorks (int vTypeWood);
	int fGetPosHarvesting (DataUnit *pDataUnit);
	bool fDeletePlaceWork ();
	sPosWork * fGetPosWork(int vN);
	bool fDeletePosWork(int vN);
	bool fNewPosWork(int vQ);
	bool fNewPosWork();
	int fNFreePosWork();
};
//typedef sPlaceWork sPlaceWork2;
#endif

#ifndef S_STACK_WORKS_H
#define S_STACK_WORKS_H
class sPosWork;
class sPlaceWork;
class sPosWorkArray;
class sStackWorks
{
public:
	typedef sPosWork sPosWork_Type;
	typedef sPlaceWork sPlaceWork_Type;
	typedef sPosWorkArray sPosWorkArray_Type;
	//friend class sPosWork;
	//friend class sPlaceWork;
	static const int MAX_Q_PLACE_WORK = 6;
	sPlaceWork_Type vMassPlaceWork[MAX_Q_PLACE_WORK];
	int vLastN;
	static const int MAX_Q_POS_WORKS = 48;
	//int vMassNPosWork[MAX_Q_POS_WORKS];
	sPosWork_Type vMassPosWork[MAX_Q_POS_WORKS];
	int vLastN2;
	//sPlaceWork *pFirst;
	//sPlaceWork *pLast;
	int vQ_PlacesWorks;
	unsigned short vCurrentEra;

	bool vFree;
	int vvi;
	int vNPlaceWork;
	sPlaceWork_Type * pPlaceWorkTest;
	int vCount;
	int vvj;
	int vvz;
	group hGroupFarm;
	unit u;
	real vG_Min;
	real vG;
	int vvi2;
	int vvj2;
	integer vOrder;
	int vvo;
	int vvl;
	bool vCheck;
	int vResult;
	DataUnit *pDataUnitTest;
	int vN2PosWork;
	sPosWork_Type * pPosWorkTest;
	sPosWork_Type * pPosWorkTest2;

	sStackWorks ();
	bool fCheckOccupiedPositions();
	int fCountingPosWorks ();
	int fGetPosHarvesting (DataUnit *pDataUnit);
	bool fFullPosHarvest (DataUnit *pDataUnit);
	int fCountingPosWorksHarvest ();
	int fCountingPosWorksHarvestToDataUnit (DataUnit *pDataUnit);
	void fPryOutPositions ();
	bool fCancellationWork (DataUnit *pDataUnit);
	int fCheckDataUnitToPosWork (DataUnit *pDataUnit);
	int fGoNearestPlaceWork (DataUnit *pDataUnit);
	bool fAddPlaceWork (int vType, int vTypeWood, DataUnit *pDataUnit);
	real fRadiusUnit (int vType);
	real fDistanceWork (int vType);
	bool fDeletePlaceWork (DataUnit *pDataUnit);
	bool fCheckUnit(unit WhichUnit);
	sPlaceWork * fGetPlaceWork(unit WhichUnit);
	sPlaceWork * fGetPlaceWork (int vN_In);
	sPlaceWork * fNewPlaceWork();
	int fNFreePlaceWork();
	bool fDeletePosWork (DataUnit *pDataUnit);
	bool fDeletePosWork (int vN_In);
	bool fCheckUnitPosWork(unit WhichUnit);
	sPosWork * fGetPosWork(unit WhichUnit);
	sPosWork * fGetPosWork (int vN_In);
	sPosWork * fNewPosWork();
	int fN2FreePosWork();
	bool fDeleteAllPlaceWork();
};
//typedef sStackWorks sStackWorks2;
#endif