Перейти к содержанию

Рубка деревьев с возвращением в дом (Lumberjacking recall to Home)

Материал из Wiki Legnes

Скрипт для Legnes Assist. Скрипт для рубки деревьев на Легнес. После того как дерево упало, персонаж полностью рубит лежащее дерево и идёт к следующему. По наполнению рюкзака он возвращается домой по руне.

Автор скрипта: Hotride

// Использовать фильтр логов, 0 - не использовать, 1 - использовать
var UseLogsNameFilter = 0;

// Названия логов для игнорирования дерева (не продолжать рубить)
var IgnoreLogsNames = 'the log';

// Использовать хайд, 0 - не использовать, 1 - использовать
var UseHidding = 0;

// Дистанция для поиска деревьев
var SearchDistance = 15;

// Звук при появлении элементаля
var SoundForGuard = 'C:/a.wav';

// Количество повтора звука
var SoundRepeatCount = 5;

// Серийник сундука, в котором находятся мешки (может быть пустым)
var TopChest = '0x401EFC28';

// Серийник мешка с инструментами, регами и едой
var ToolsBag = '0x40351B31';

// Серийник мешка для логов
var LogsBag = '0x401EFC28';

// Типы еды
var FoodType = '0x09B7|0x09F2|0x097B';

// Серийник оружия, который использовать при появлении гварда
var UseWeaponForGuard = 'guard_weapon';

// Список зон, в которых не производить вырубку леса (территории домов)
// StartX, StartY, EndX, EndY
var IgnoreAreaList =
[
	[ 75, 99, 89, 126 ]
];

// Использовать реколл или бегать относить логи пешком
var UseRecall = 1;

// Серийник руны домой
var RuneHome = '0x40325C4C';

// Координаты точки рядом с сундуками (должна быть в пешей доступности от леса)
// Только если UseRecall = 0
var HomeX = 0;
var HomeY = 0;

// Серийники рун в лес
var RunesToForest =
[
	// Home forest
	'0x40325DF6'
];

// Координаты точки в лесу (должна быть в пешей доступности от дома если UseRecall = 0)
var ForestSpots =
[
	// Home forest
	[
		[ 118, 302 ],
		[ 142, 302 ],
		[ 146, 327 ],
		[ 123, 327 ]
	]
];

// Графика деревьев целых
var Trees =
[
	0x0CDD, 0x0CCD, 0x0CD3, 0x0CDA, 0x0CD8,
	0x0CE6, 0x0CE3, 0x0CD6
];

// Графика частей срубленных деревьев
var TreeParts =
[
	0x3A97, 0x3A98, 0x3A99, 0x3AA2, 0x3AA1, 0x3AA0, 0x3A9A, 0x3A9B, 0x3A9C, 0x3A9D, 0x3A9E, 0x3A9F,
	0x3AA9, 0x3AAA, 0x3AB9, 0x3AB8, 0x3AAB, 0x3AAC, 0x3AB7, 0x3AB6, 0x3AAD, 0x3AAC, 0x3AAE, 0x3AAF, 0x3AB3, 0x3AB0, 0x3AB1, 0x3AB4, 0x3AB5, 0x3AB2,
	0x3A80, 0x3A81, 0x3A82, 0x3A83, 0x3A84, 0x3A8F, 0x3A8E, 0x3A8D, 0x3A8C, 0x3A88, 0x3A87, 0x3A86, 0x3A85, 0x3A8B, 0x3A8A, 0x3A89,
	0x3A10, 0x3A11, 0x3A12, 0x3A13, 0x3A1B, 0x3A1A, 0x3A1C, 0x3A1D, 0x3A1E, 0x3A1F, 0x3A20, 0x3A21, 0x3A16, 0x3A14, 0x3A15, 0x3A19, 0x3A18, 0x3A17,
	0x39FC, 0x39FD, 0x39FE, 0x39FF, 0x3A00, 0x3A09, 0x3A08, 0x3A07, 0x3A04, 0x3A03, 0x3A02, 0x3A01, 0x3A05, 0x3A06,
	0x3AC0, 0x3AC1, 0x3AC2, 0x3AC3, 0x3ACE, 0x3ACD, 0x3ACC, 0x3AC8, 0x3AC7, 0x3AC6, 0x3AC5, 0x3ACB, 0x3AC4, 0x3AC9, 0x3ACA,
	0x3A5A, 0x3A5B, 0x3A5C, 0x3A5D, 0x3A5E, 0x3A62, 0x3A61, 0x3A60, 0x3A5F, 0x3A63, 0x3A67, 0x3A66, 0x3A65, 0x3A64,
	0x3A36, 0x3A37, 0x3A38, 0x3A39, 0x3A3A, 0x3A3E, 0x3A3D, 0x3A3C, 0x3A40, 0x3A3F, 0x3A3B, 0x3A40, 0x3A3F,
	0x3A6E, 0x3A6F, 0x3A70, 0x3A71, 0x3A72, 0x3A79, 0x3A78, 0x3A77, 0x3A76, 0x3A75, 0x3A74, 0x3A73,
	0x3A97, 0x3A98, 0x3A99, 0x3A9A, 0x3A9B, 0x3A9E, 0x3A9D, 0x3A9F, 0x3AA2, 0x3AA1, 0x3AA0,
	0x3A47, 0x3A48, 0x3A49, 0x3A4A, 0x3A4B, 0x3A4C, 0x3A53, 0x3A52, 0x3A4F, 0x3A4E, 0x3A4D
];

// Не трогать!!!
var BannedLocations = [];
var FakeId = 0;

function UseHatchet(_private)
{
	if (!Orion.UseType('0x0F43', 'any', self, false))
	{
		if (!Orion.UseType('0x0F43'))
		{
			Orion.Print('0x0021', 'Your tool is gone!');
			return false;
		}
	}

	return true;
}

function WalkHangChecker(distance)
{
	var x = Player.X();
	var y = Player.Y();
	var count = 0;
	var now = Orion.Now() + (distance * 500);

	while (now > Orion.Now())
	{
		if (x == Player.X() && y == Player.Y())
			count++;
		else
			count = 0;

		if (count >= 15)
		{
			Orion.StopWalking();
			count = 0;
		}

		x = Player.X();
		y = Player.Y();

		Orion.Wait(1000);
	}
}

function WalkToWrapper(x, y, distance, run)
{
	Orion.Exec('WalkHangChecker', Orion.GetDistance(x, y));
	Orion.Wait(30)
	// Потому что на пути следования могут быть динамические препятствия
	for (var i = 0; i < 3; i++)
	{
		if (Orion.WalkTo(x, y, 0, distance, 255, run))
		{
			Orion.Terminate('WalkHangChecker');
			Orion.Wait(30)
			return true;
		}
	}

	Orion.Terminate('WalkHangChecker');
	Orion.Wait(30)
	return false;
}

function RecallTo(rune)
{
	var x = Player.X();
	var y = Player.Y();
	var successCount = 0;

	while (x == Player.X() && y == Player.Y() && successCount < 5)
	{
		Orion.WarMode(0);
		Orion.Wait(100);
		Orion.ClearJournal();
		var timeout = Orion.Now() + 10000;
		var mr = Orion.Count('mr');
		Orion.Cast('32', rune);

		while (mr == Orion.Count('mr') && timeout > Orion.Now())
			Orion.Wait(100);

		if (Orion.InJournal('The spell fizzles', 'my|sys') == null)
			successCount++;

		var msgUses = Orion.InJournal('uses left', 'my|sys');
	
		if (msgUses != null)
		{
			for (var i = 0; i < 10; i++)
			{
				if (Orion.Contains(msgUses.Text(), 'has ' + i + ' uses left'))
				{
					MarkRune(rune);
					break;
				}
			}

			break;
		}
	}
}

function MarkRune(rune)
{
	while (true)
	{
		if (Player.Mana('%') < 40)
		{
			while (Player.Mana('%') < 100)
			{
				Orion.UseSkill('46');
				Orion.Wait(500);
			}
		}

		Orion.WarMode(0);
		Orion.Wait(100);
		Orion.ClearJournal();
		var timeout = Orion.Now() + 10000;
		var mr = Orion.Count('mr');
		Orion.Cast('45', rune);

		while (mr == Orion.Count('mr') && timeout > Orion.Now())
			Orion.Wait(100);

		if (Orion.InJournal('The spell fizzles', 'my|sys') == null)
			break;
	}
}

function Restock(graphic, count)
{
	var val = Orion.Count(graphic);
	
	while (val < count)
	{
		if (!Orion.MoveItemType(graphic, 'any', ToolsBag, count - val))
			break;

		Orion.Wait(400);
		val = Orion.Count(graphic);
	}
}

function CheckOverweight(forced, runeForest)
{
	if (forced || Player.Weight('%') >= 95)
	{
		var oldX = Player.X();
		var oldY = Player.Y();

		if (!forced)
			Orion.Print('0x0021', 'Weight limit reached!!!');

		if (UseRecall)
			RecallTo(RuneHome);
		else
			WalkToWrapper(HomeX, HomeY, 0,  true);

		if (TopChest != '')
			Orion.UseObject(TopChest);

		Orion.UseObject(LogsBag);
		Orion.UseObject(ToolsBag);
		Orion.Wait(200);
		
		UnloadLogs();

		if (Orion.Count(FoodType, '0') > 0 || Orion.MoveItemType(FoodType, '0', ToolsBag, 1))
		{
			Orion.UseType(FoodType, '0');
			Orion.Wait(100);
		}

		Restock('0x0F43', 4); // Axe
		
		if (Orion.Count('0x0F43') < 1)
		{
			Orion.Print('0x0021', 'No hatchets!!!');
			Orion.PauseScript();
		}

		if (UseRecall)
		{
			Restock('mr', 20);
			Restock('bp', 20);
			Restock('bm', 20);

			if (Orion.Count('mr') < 5 || Orion.Count('bp') < 5 || Orion.Count('bm') < 5)
			{
				Orion.Print('0x0021', 'No reagents to recalls!!!');
				Orion.PauseScript();
			}
		}
		
		if (runeForest != '')
		{
			if (UseRecall)
				RecallTo(runeForest);
			else
				WalkToWrapper(oldX, oldY, 0,  true);
		}
	}
}

function PlayGuardAlarm(_private)
{
	for (var i = 0; i < SoundRepeatCount; i++)
	{
		Orion.PlayWav(SoundForGuard);
		Orion.Wait(1000);
	}
}

function CheckIgnoredArea(x, y)
{
	for (var i = 0; i < IgnoreAreaList.length; i++)
	{
		var loc = IgnoreAreaList[i];

		if (x >= loc[0] && y >= loc[1] && x <= loc[2] && y <= loc[3])
			return true;
	}

	return false;
}

function LumberPart(tile, runeForest)
{
	var text = 'в свой рюкзак|in your pack|Вы некоторое время рубите дерево, но не можете получить|but fail to produce any|Цель находится вне прямой видимости|too far away to chop|Target is not in line of sight|Вы не можете срубить это|cut it down|no logs left here to chop';

	if (!WalkToWrapper(tile.X(), tile.Y(), 2,  (UseHidding == 0 || !Player.Hidden())))
		return false;

	Orion.Ignore(self);
	var tryingCount = 0;

	while (tryingCount < 10)
	{
		if (Orion.FindType('0x0008', 'any', ground, 'mobile|near', 10).length > 0)
		{
			var oldX = Player.X();
			var oldY = Player.Y();

			if (UseWeaponForGuard != '')
				Orion.UseObject(UseWeaponForGuard);

			Orion.Exec('PlayGuardAlarm');

			if (!Player.Hidden())
				Orion.UseSkill('21');

			//if (!Player.Hidden())
			//	CheckOverweight(true, '');

			Orion.PauseScript();
			Orion.WarMode(false);
			WalkToWrapper(oldX, oldY, 0,  (UseHidding == 0 || !Player.Hidden()));
		}

		var mobiles = Orion.FindType('any', 'any', ground, 'mobile|near', 1, 'red|gray|criminal');

		if (mobiles.length > 0)
		{
			var oldX = Player.X();
			var oldY = Player.Y();
			var obj = Orion.FindObject(mobiles[0]);

			if (UseWeaponForGuard != '')
				Orion.UseObject(UseWeaponForGuard);

			Orion.Exec('PlayGuardAlarm');

			while (obj.Exists())
			{
				Orion.Attack(mobiles[0]);
				if (obj.Distance() > 5)
					Orion.WalkTo(obj.X(), obj.Y(), 0, 1, 255, true);
				Orion.Wait(500);
			}

			WalkToWrapper(oldX, oldY, 0,  (UseHidding == 0 || !Player.Hidden()));
		}

		while (UseHidding && !Player.Hidden())
		{
			Orion.WarMode(false);
			Orion.Wait(100);
			Orion.UseSkill('21');
			Orion.WaitJournal('Вы хорошо спрятались|You have hidden yourself well|Кажется, ты не можешь здесь спрятаться|t seem to hide here', Orion.Now(), Orion.Now() + 3000);
		}

		CheckOverweight(false, runeForest);

		var now = Orion.Now();
		Orion.WaitTargetTile(tile.Graphic(), tile.X(), tile.Y(), tile.Z());
		if (!UseHatchet(0))
		{
			CheckOverweight(true, runeForest);

			Orion.WaitTargetTile(tile.Graphic(), tile.X(), tile.Y(), tile.Z());
			UseHatchet(0);
		}

		tryingCount++;
		var msg = Orion.WaitJournal(text, now, now + 5000, 'my|sys');
		
		if (msg != null)
		{
			if (msg.FindTextID() > 3)
			{
				if ((msg.FindTextID() >= 4 && msg.FindTextID() <= 6) && !Orion.WalkTo(tile.X(), tile.Y(), tile.Z(), 0, 255, true))
				{
					BannedLocations.push([ tile.X(), tile.Y(), Orion.Now() + 15 * 60 * 1000 ]);
					return false;
				}
					
				return (msg.FindTextID() == 3);
			}
			else if (UseLogsNameFilter && msg.FindTextID() <= 1)
			{
				if (Orion.Contains(msg.Text(), IgnoreLogsNames))
				{
					BannedLocations.push([ tile.X(), tile.Y(), Orion.Now() + 15 * 60 * 1000 ]);
					return false;
				}
			}
		}

		Orion.Wait(10);
	}

	return (tryingCount < 10);
}

function LumberParts(_private, runeForest)
{
	var tiles = Orion.GetTilesInRect('any', Player.X() - SearchDistance, Player.Y() - SearchDistance, Player.X() + SearchDistance, Player.Y() + SearchDistance);
	var result = false;

	for (var i = 0; i < tiles.length; i++)
	{
		if (CheckIgnoredArea(tiles[i].X(), tiles[i].Y()))
			continue;

		var graphic = parseInt(tiles[i].Graphic(), 16);

		if (TreeParts.indexOf(graphic) != -1)
		{
			if (UseLogsNameFilter)
			{
				var now = Orion.Now();
				var inBan = false;

				for (var j = BannedLocations.length - 1; j >= 0; j--)
				{
					var loc = BannedLocations[j];

					if (now > loc[2])
						BannedLocations.splice(j, 1);
					else if (loc[0] == tiles[i].X() && loc[1] == tiles[i].Y())
					{
						inBan = true;
						break;
					}
				}
				
				if (inBan)
					continue;
			}

			if (LumberPart(tiles[i], runeForest))
				result = true;
		}
	}

	return result;
}

function LumberTree(tile, runeForest)
{
	if (!WalkToWrapper(tile.X(), tile.Y(), 2,  (UseHidding == 0 || !Player.Hidden())))
		return false;

	Orion.WaitTargetTile(tile.Graphic(), tile.X(), tile.Y(), tile.Z());
	UseHatchet(0);
	Orion.Wait(4500);

	var result = false;

	while (LumberParts(0, runeForest))
	{
		result = true;
		Orion.Wait(100);
	}

	return result;
}

function LumberTrees()
{
	var maxForestsCount = (UseRecall ? RunesToForest.length : 1);

	var now = Orion.Now() + 5 * 60 * 1000;

	for (var forest = 0; forest < maxForestsCount; forest++)
	{
		var spots = ForestSpots[forest];

		if (UseRecall)
			RecallTo(RunesToForest[forest]);

		for (var spot = 0; spot < spots.length; spot++)
		{
			WalkToWrapper(spots[spot][0], spots[spot][1], 0,  true);

			var x = Player.X();
			var y = Player.Y();

			LumberParts(0, RunesToForest[forest]);

			while (true)
			{
				Orion.WalkTo(x, y, 0, 1, 255, true);
				var tiles = Orion.GetTilesInRect('any', x - SearchDistance, y - SearchDistance, x + SearchDistance, y + SearchDistance);
				var hasTree = false;

				for (var i = 0; i < tiles.length; i++)
				{
					if (CheckIgnoredArea(tiles[i].X(), tiles[i].Y()))
						continue;

					var graphic = parseInt(tiles[i].Graphic(), 16);
		
					if (Trees.indexOf(graphic) != -1)
					{
						if (LumberTree(tiles[i], RunesToForest[forest]))
							hasTree = true;
					}
				}

				if (!hasTree)
					break;
			}
		}

		if (Player.Weight('%') >= 45)
			CheckOverweight(true, '');
	}

	var delta = now - Orion.Now();

	if (delta > 0)
	{
		var secs = delta / 1000;
		var mins = Math.floor(secs / 60);
		Orion.Print('Wait to respawn: ' + mins + ' min ' + Math.floor(secs - (mins * 60)) + ' sec');
		Orion.Wait(delta);
	}

	Orion.Wait(100);
	Orion.Exec('LumberTrees');
	Orion.Wait(500);
}

function UnloadLogs()
{
	while (Orion.MoveItemType('0x1BDD|0x0F90|0x0F79|gp', 'any', backpack, 0, LogsBag))
		Orion.Wait(400);
}

function CheckHP()
{
	while (true)
	{
		if (Player.Hits('%') < 90)
			Orion.PlayWav('С:/1.wav');

		Orion.Wait(1000);
	}
}

function TestHarvestingZones(rune)
{
	if (rune < 0 || rune >= ForestSpots.length)
	{
		Orion.Print('0x0021', 'Invalid rune index: ' + rune);
		return;
	}

	Orion.ClearFakeMapObjects();
	FakeId = 1;
	var spots = ForestSpots[rune];

	for (var spot = 0; spot < spots.length; spot++)
	{
		TestHarvestingZone(spots[spot][0], spots[spot][1], SearchDistance);
	}
}

function TestHarvestingZone(centerX, centerY, distance)
{
	for (var x = -distance; x <= distance; x++)
	{
		for (var y = -distance; y <= distance; y++)
		{
			Orion.AddFakeMapObject(FakeId++, '0x051A', '0x0044', centerX + x, centerY + y, Player.Z());
		}
	}
}