//-- Improve Static AI --//
//By Strangelove
//v0.2
//04.03.2018
//Developed for r8754

// This script tweaks the AI settings of non-autobuild AIs by making them Rebuild destroyed Houses, blocks unfinished wares to the storehouse and maxes out the Ware distribution.
// Just copy this file into the map folder and type "{$I improvestaticai.script}"
// Do not use this script without permission from its author!

{$EVENT evtMissionStart:ImproveStaticAIOnMissionStart}
{$EVENT evtHouseDestroyed:ImproveStaticAIOnHouseDestroyed}
{$EVENT evtTick:ImproveStaticAIOnTick}
{$EVENT evtPlayerDefeated:ImproveStaticAIOnPlayerDefeated}


{$DEFINE REBUILD} //Enable Rebuilding of AI Houses
//{$UNDEF REBUILD}
{$DEFINE SETHUNGER} //Set Hunger Level of AI Players
//{$UNDEF SETHUNGER}
{$DEFINE AIDEF} //Enables to set AI defaults
//{$UNDEF AIDEF}


{$IFDEF REBUILD}
const
	DELAY = 300; //Cant be 0; Destroyed House needs time to be removed from game (in Ticks)
	UPDATE_FREQ = 101; //How frequently aDestroyedHouses array will be checked (in Ticks)

	
Type
	TDestroyedHouse = record
		aHouse, iTime: Integer;
		iX, iY, iType, iOwner: Byte;
	end;

var
	aDestroyedHouses: array of TDestroyedHouse;
	

procedure PlanRebuildHouse(PlayerID, HouseType, X, Y: Byte);
begin
	{$IFDEF DEBUG}
	if not Actions.PlanAddHouse(PlayerID, HouseType, X, Y) then
		Actions.Log('House plan to rebuild destroyed House could not be placed: Actions.PlanAddHouse: ' + inttostr(PlayerID) + ', ' + inttostr(HouseType) + ', ' + inttostr(X) + ', ' + inttostr(Y) + '; GameTime: ' + inttostr(States.GameTime()));
	{$ELSE}
	Actions.PlanAddHouse(PlayerID, HouseType, X, Y);
	{$ENDIF}
end;

procedure DestroyedHouseData(aHouseID: Integer; j: Byte);
begin
	aDestroyedHouses[j].iX := States.HousePositionX(aHouseID);
	aDestroyedHouses[j].iY := States.HousePositionY(aHouseID);
	aDestroyedHouses[j].iOwner := States.HouseOwner(aHouseID);
	aDestroyedHouses[j].iType := States.HouseType(aHouseID);
	aDestroyedHouses[j].iTime := States.GameTime();
	aDestroyedHouses[j].aHouse := aHouseID;
end;


//Needed to scale arrays accordingly
function ImproveStaticAIPlayerCount(): Byte;
var
	p, AIPlayer: Byte;
begin
	for p := 0 to States.LocationCount() -1 do
		if States.PlayerEnabled(p) then
			if States.PlayerIsAI(p) then
				AIPlayer := AIPlayer +1;
	Result := AIPlayer;
end;
{$ENDIF}

{$IFDEF SETHUNGER}
//Sets the HungerLevel of AI Players to a random amount
procedure UnitsRandomHungerSet();
var
	aUnits: array of Integer;
	i, iGroup: Integer;
	p: Byte;
begin
	for p := 0 to States.StatPlayerCount()-1 do
		if States.PlayerIsAI(p) then
		begin
			aUnits := States.PlayerGetAllUnits(p);
			for i := 0 to Length(aUnits)-1 do
				if States.UnitsGroup(aUnits[i]) = -1 then
				begin
					Actions.UnitHungerSet(aUnits[i], States.UnitMaxHunger/2 + States.KaMRandomI(States.UnitMaxHunger/2 +1));
				end else
				begin
					iGroup := States.UnitsGroup(aUnits[i]);
					if States.GroupMember(iGroup, 0) = aUnits[i] then
						Actions.GroupHungerSet(iGroup, States.UnitMaxHunger/2 + States.KaMRandomI(States.UnitMaxHunger/2 +1));
				end;
		end;
end;
{$ENDIF}

{$IFDEF AIDEF}
//Changes AI defaults
procedure SetupAI();
var
	p: Byte;
	h: SmallInt;
	aHouses: array of Integer;
begin
	for p := 0 to States.StatPlayerCount() -1 do
		if States.PlayerIsAI(p) then
		begin
			//Adjust Ware Distribution
			//Iron
			Actions.PlayerWareDistribution(p, 6, 2, 5); //Weapon Smithy
			Actions.PlayerWareDistribution(p, 6, 10, 5); //Armor smithy
			//Coal
			Actions.PlayerWareDistribution(p, 5, 1, 5);	//Iron smity
			Actions.PlayerWareDistribution(p, 5, 15, 5); //Metallurgist
			Actions.PlayerWareDistribution(p, 5, 2, 5);	//Weapon Smithy
			Actions.PlayerWareDistribution(p, 5, 10, 5); //Armor Smithy
			//Timber
			Actions.PlayerWareDistribution(p, 2, 20, 5); //Armory workshop
			Actions.PlayerWareDistribution(p, 2, 19, 5); //Weapon Workshop
			//Corn
			Actions.PlayerWareDistribution(p, 9, 22, 5); //Mill
			Actions.PlayerWareDistribution(p, 9, 16, 5); //Swine farm
			Actions.PlayerWareDistribution(p, 9, 12, 5); //Stables
			//Block Wares in Storehouses (unfinished products)
			aHouses := States.PlayerGetAllHouses(p);
			for h := 0 to Length(aHouses) -1 do
				if States.HouseType(aHouses[h]) = 11 then
				begin
					Actions.HouseWareBlock(aHouses[h], 0, true); //Treetrunk
					//Actions.HouseWareBlock(aHouses[h], 1, true); //Stone
					//Actions.HouseWareBlock(aHouses[h], 2, true); //Timber
					Actions.HouseWareBlock(aHouses[h], 3, true); //Iron Ore
					Actions.HouseWareBlock(aHouses[h], 4, true); //Gold Ore
					Actions.HouseWareBlock(aHouses[h], 5, true); //Coal
					Actions.HouseWareBlock(aHouses[h], 6, true); //Iron
					//Actions.HouseWareBlock(aHouses[h], 7, true); //Gold
					//Actions.HouseWareBlock(aHouses[h], 8, true); //Wine
					Actions.HouseWareBlock(aHouses[h], 9, true); //Corn
					//Actions.HouseWareBlock(aHouses[h], 10, true); //Loaves
					Actions.HouseWareBlock(aHouses[h], 11, true); //Flour
					Actions.HouseWareBlock(aHouses[h], 12, true); //Leather
					//Actions.HouseWareBlock(aHouses[h], 13, true); //Sausages
					Actions.HouseWareBlock(aHouses[h], 14, true); //Pig
					Actions.HouseWareBlock(aHouses[h], 15, true); //Skin
					//16-26 = Military Equipment
					//Actions.HouseWareBlock(aHouses[h], 15, true); //Fish
				end;
		end;
end;
{$ENDIF}


procedure ImproveStaticAIOnMissionStart();
{$IFDEF REBUILD}
var
	j: Byte;
	{$ENDIF}
begin
	//Apply...
	{$IFDEF AIDEF}
	SetupAI();
	{$ENDIF}
	{$IFDEF SETHUNGER}
	UnitsRandomHungerSet();
	{$ENDIF}
	{$IFDEF REBUILD}
	//Scale Array dynamicly
	SetLength(aDestroyedHouses, 5 +(ImproveStaticAIPlayerCount() *2));
	//Assign values to arrays
	for j := 0 to Length(aDestroyedHouses) -1 do
		aDestroyedHouses[j].aHouse := -1;
	{$ENDIF}
end;

{$IFDEF REBUILD}
procedure ImproveStaticAIOnHouseDestroyed(aHouseID, aDestroyerIndex: Integer);
var
	j: Byte;
begin
	if States.PlayerIsAI(States.HouseOwner(aHouseID)) and (aDestroyerIndex <> -1) then
		for j := 0 to Length(aDestroyedHouses) -1 do
			if (aDestroyedHouses[j].aHouse = -1) then //Save House Data to next empty position in array
			begin
				DestroyedHouseData(aHouseID, j);
				exit;
			end;
end;

//Make AI rebuild destroyed Houses
procedure ImproveStaticAIOnTick();
var 
	j: Byte;
begin
	if States.GameTime() mod UPDATE_FREQ = 0 then
		for j := 0 to Length(aDestroyedHouses) -1 do
			if (aDestroyedHouses[j].aHouse <> -1) then
				if ((aDestroyedHouses[j].iTime +DELAY) <= States.GameTime()) then
				begin
					aDestroyedHouses[j].aHouse := -1;
					PlanRebuildHouse(aDestroyedHouses[j].iOwner, aDestroyedHouses[j].iType, aDestroyedHouses[j].iX, aDestroyedHouses[j].iY);
					//break;
				end;
end;

//Remove stored buildings of defeated AIPlayer from Array to free up space
procedure ImproveStaticAIOnPlayerDefeated(aIndex: Integer);
var
	j: Byte;
begin
	if States.PlayerIsAI(aIndex) then
		for j := 0 to Length(aDestroyedHouses) -1 do
			if aDestroyedHouses[j].iOwner = aIndex then
				aDestroyedHouses[j].aHouse := -1;
end;

{$ELSE}
procedure ImproveStaticAIOnHouseDestroyed(aHouseID, aDestroyerIndex: Integer);
begin
	exit;
end;

procedure ImproveStaticAIOnTick();
begin
	exit;
end;

procedure ImproveStaticAIOnPlayerDefeated(aIndex: Integer);
begin
	exit;
end;
{$ENDIF}