Changed some code to be in SDust Core and now the AI can break stones!
This commit is contained in:
parent
eae0eb82bf
commit
365808a504
|
@ -62,6 +62,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RuneFactoryCropsMod", "Rune
|
|||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StarAI", "..\StarAI\StarAI\StarAI.csproj", "{93632675-991D-425B-96F9-9C2B6BFC4EFE}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0756D36A-95C8-480D-8EA6-4584C03010C6} = {0756D36A-95C8-480D-8EA6-4584C03010C6}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
|
|
@ -774,5 +774,34 @@ namespace StardustCore
|
|||
}
|
||||
|
||||
|
||||
public static StardewValley.Object checkRadiusForObject(int radius, string name)
|
||||
{
|
||||
for (int x = -radius; x <= radius; x++)
|
||||
{
|
||||
for (int y = -radius; y <= radius; y++)
|
||||
{
|
||||
bool f = Game1.player.currentLocation.isObjectAt((Game1.player.getTileX() + x) * Game1.tileSize, (Game1.player.getTileY() + y) * Game1.tileSize);
|
||||
if (f == false) continue;
|
||||
StardewValley.Object obj = Game1.player.currentLocation.getObjectAt((Game1.player.getTileX() + x) * Game1.tileSize, (Game1.player.getTileY() + y) * Game1.tileSize);
|
||||
if (obj == null) continue;
|
||||
if (obj.name == name)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool doesLocationContainObject(GameLocation location, string name)
|
||||
{
|
||||
foreach (var v in location.objects)
|
||||
{
|
||||
if (name == v.Value.name) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ namespace StarAI
|
|||
ModCore.CoreHelper.ConsoleCommands.Add("getseeds", "Get Seeds From chests.", new Action<string, string[]>(Commands.getSeedsFromChests));
|
||||
|
||||
ModCore.CoreHelper.ConsoleCommands.Add("choptwigs", "Chop twigs.", new Action<string, string[]>(Commands.chopAllTwigs));
|
||||
ModCore.CoreHelper.ConsoleCommands.Add("chopsticks", "Chop twigs.", new Action<string, string[]>(Commands.chopAllTwigs));
|
||||
ModCore.CoreHelper.ConsoleCommands.Add("breakstones", "Break small stones with pickaxe.", new Action<string, string[]>(Commands.breakAllStones));
|
||||
// ModCore.CoreHelper.ConsoleCommands.Add("chopsticks", "Chop twigs.", new Action<string, string[]>(Commands.chopAllTwigs));
|
||||
pathfind("Initialize Delay 0", new string[] {
|
||||
"setDelay",
|
||||
"0"
|
||||
|
@ -43,9 +46,32 @@ namespace StarAI
|
|||
|
||||
public static void chopAllTwigs(string s, string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
{
|
||||
if (args[0] == "All" || args[0] == "all")
|
||||
{
|
||||
DebrisLogic.getAllSticksToChop(Game1.player.currentLocation);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DebrisLogic.getAllSticksToChopRadius(Game1.player.currentLocation);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void breakAllStones(string s, string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
{
|
||||
if (args[0] == "All" || args[0] == "all")
|
||||
{
|
||||
DebrisLogic.getAllStonesToBreak(Game1.player.currentLocation);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DebrisLogic.getAllStonestoBreakRadius(Game1.player.currentLocation);
|
||||
}
|
||||
|
||||
public static void runTasks(string s, string[] args)
|
||||
{
|
||||
ExecutionCore.TaskList.runTaskList();
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
class DebrisLogic
|
||||
{
|
||||
public static List<TileNode> sticksToChop = new List<TileNode>();
|
||||
|
||||
public static List<TileNode> stonesToBreak = new List<TileNode>();
|
||||
|
||||
public static void getAllSticksToChop(GameLocation location)
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// DO NOT USE THIS UNLESS YOU WANT LAG UP THE WAZOO
|
||||
/// DO NOT USE THIS UNLESS YOU WANT LAG UP THE WAZOO. WILL ATTEMPT TO PATH TO ALL STICKS AT THE LOCATION AND CHOP THEM!
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
public static void getAllSticksToChop(object obj)
|
||||
|
@ -42,10 +42,6 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
TileNode t = new TileNode(1, Vector2.Zero, Path.Combine("Tiles", "GenericUncoloredTile.xnb"), Path.Combine("Tiles", "TileData.xnb"), StardustCore.IlluminateFramework.Colors.invertColor(StardustCore.IlluminateFramework.ColorsList.Brown));
|
||||
//t.placementAction(Game1.currentLocation, (int)v.Key.X * Game1.tileSize, (int)v.Key.Y * Game1.tileSize);
|
||||
t.fakePlacementAction(Game1.currentLocation, (int)v.Key.X, (int)v.Key.Y);
|
||||
//t.tileLocation = new Vector2((int)v.Key.X, (int)v.Key.Y);
|
||||
//t.position = new Vector2(v.Key.X * Game1.tileSize, v.Key.Y * Game1.tileSize);
|
||||
//t.thisLocation = location;
|
||||
//StardustCore.Utilities.masterAdditionList.Add(new StardustCore.DataNodes.PlacementNode(t, Game1.currentLocation, (int)v.Key.X * Game1.tileSize, (int)v.Key.Y * Game1.tileSize));
|
||||
Utilities.tileExceptionList.Add(new TileExceptionMetaData(t, "ChopStick"));
|
||||
sticksToChop.Add(t);
|
||||
twingCount++;
|
||||
|
@ -83,6 +79,7 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
Utilities.clearExceptionListWithName("Child");
|
||||
// waterSingleCrop(v);
|
||||
}
|
||||
sticksToChop.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,33 +91,6 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
}
|
||||
|
||||
|
||||
public static StardewValley.Object checkRadiusForObject(int radius,string name)
|
||||
{
|
||||
for(int x = -radius; x <= radius; x++)
|
||||
{
|
||||
for (int y = -radius; y <= radius; y++)
|
||||
{
|
||||
bool f= Game1.player.currentLocation.isObjectAt((Game1.player.getTileX() + x) * Game1.tileSize, (Game1.player.getTileY() + y) * Game1.tileSize);
|
||||
if (f == false) continue;
|
||||
StardewValley.Object obj = Game1.player.currentLocation.getObjectAt((Game1.player.getTileX() + x)*Game1.tileSize, (Game1.player.getTileY() + y)*Game1.tileSize);
|
||||
if (obj == null) continue;
|
||||
if (obj.name==name)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool doesLocationContainObject(GameLocation location, string name)
|
||||
{
|
||||
foreach(var v in location.objects)
|
||||
{
|
||||
if (name == v.Value.name) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void getAllSticksToChopRadius(object obj)
|
||||
{
|
||||
|
@ -128,12 +98,12 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
int twingCount = 0;
|
||||
object[] objArr = (object[])obj;
|
||||
GameLocation location = (GameLocation)objArr[0];
|
||||
if (doesLocationContainObject(location, "Twig")) {
|
||||
StardewValley.Object twig = checkRadiusForObject(radius, "Twig");
|
||||
if (StardustCore.Utilities.doesLocationContainObject(location, "Twig")) {
|
||||
StardewValley.Object twig =StardustCore.Utilities.checkRadiusForObject(radius, "Twig");
|
||||
while (twig == null)
|
||||
{
|
||||
radius++;
|
||||
twig = checkRadiusForObject(radius, "Twig");
|
||||
twig =StardustCore.Utilities.checkRadiusForObject(radius, "Twig");
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,10 +115,6 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
TileNode t = new TileNode(1, Vector2.Zero, Path.Combine("Tiles", "GenericUncoloredTile.xnb"), Path.Combine("Tiles", "TileData.xnb"), StardustCore.IlluminateFramework.Colors.invertColor(StardustCore.IlluminateFramework.ColorsList.Brown));
|
||||
//t.placementAction(Game1.currentLocation, (int)v.Key.X * Game1.tileSize, (int)v.Key.Y * Game1.tileSize);
|
||||
t.fakePlacementAction(Game1.currentLocation, (int)twig.tileLocation.X, (int)twig.tileLocation.Y);
|
||||
//t.tileLocation = new Vector2((int)v.Key.X, (int)v.Key.Y);
|
||||
//t.position = new Vector2(v.Key.X * Game1.tileSize, v.Key.Y * Game1.tileSize);
|
||||
//t.thisLocation = location;
|
||||
//StardustCore.Utilities.masterAdditionList.Add(new StardustCore.DataNodes.PlacementNode(t, Game1.currentLocation, (int)v.Key.X * Game1.tileSize, (int)v.Key.Y * Game1.tileSize));
|
||||
Utilities.tileExceptionList.Add(new TileExceptionMetaData(t, "ChopStick"));
|
||||
sticksToChop.Add(t);
|
||||
twingCount++;
|
||||
|
@ -178,23 +144,14 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
|
||||
if (task.taskMetaData.cost == Int32.MaxValue)
|
||||
{
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
// System.Threading.Thread.Sleep(1000);
|
||||
Utilities.clearExceptionListWithNames(true);
|
||||
continue;
|
||||
}
|
||||
if (task.taskMetaData.cost.ToString() == "2.147484E+09")
|
||||
{
|
||||
ModCore.CoreMonitor.Log("OHH THAT's BAD");
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
}
|
||||
|
||||
ModCore.CoreMonitor.Log("TASK COST:" + task.taskMetaData.cost.ToString());
|
||||
|
||||
ExecutionCore.TaskList.taskList.Add(task);
|
||||
Utilities.clearExceptionListWithName("Child");
|
||||
ModCore.CoreMonitor.Log("TASK LIST COUNT:" + ExecutionCore.TaskList.taskList.Count.ToString());
|
||||
//Utilities.clearExceptionListWithName(true, "Child");
|
||||
// waterSingleCrop(v);
|
||||
}
|
||||
sticksToChop.Clear();
|
||||
}
|
||||
|
@ -305,5 +262,245 @@ namespace StarAI.PathFindingCore.DebrisLogic
|
|||
}
|
||||
|
||||
|
||||
|
||||
public static void getAllStonesToBreak(GameLocation location)
|
||||
{
|
||||
object[] arr = new object[1];
|
||||
arr[0] = location;
|
||||
getAllStonesToBreak(arr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DO NOT USE THIS UNLESS YOU WANT LAG UP THE WAZOO. WILL ATTEMPT TO PATH TO ALL STICKS AT THE LOCATION AND CHOP THEM!
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
public static void getAllStonesToBreak(object obj)
|
||||
{
|
||||
int twingCount = 0;
|
||||
object[] objArr = (object[])obj;
|
||||
GameLocation location = (GameLocation)objArr[0];
|
||||
string targetName = "Stone";
|
||||
foreach (var v in location.objects)
|
||||
{
|
||||
ModCore.CoreMonitor.Log(v.Value.name);
|
||||
|
||||
if (v.Value.name == targetName)
|
||||
{
|
||||
ModCore.CoreMonitor.Log(v.Value.name, LogLevel.Warn);
|
||||
TileNode t = new TileNode(1, Vector2.Zero, Path.Combine("Tiles", "GenericUncoloredTile.xnb"), Path.Combine("Tiles", "TileData.xnb"), StardustCore.IlluminateFramework.Colors.invertColor(StardustCore.IlluminateFramework.ColorsList.Brown));
|
||||
//t.placementAction(Game1.currentLocation, (int)v.Key.X * Game1.tileSize, (int)v.Key.Y * Game1.tileSize);
|
||||
t.fakePlacementAction(Game1.currentLocation, (int)v.Key.X, (int)v.Key.Y);
|
||||
Utilities.tileExceptionList.Add(new TileExceptionMetaData(t, "Break Stone"));
|
||||
stonesToBreak.Add(t);
|
||||
twingCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ok = 0;
|
||||
foreach (var v in stonesToBreak)
|
||||
{
|
||||
|
||||
object[] objList = new object[2];
|
||||
objList[0] = v;
|
||||
// ExecutionCore.TaskList.taskList.Add(new Task(new Action<object>(waterSingleCrop), obj));
|
||||
StardewValley.Tools.Pickaxe w = new StardewValley.Tools.Pickaxe();
|
||||
ModCore.CoreMonitor.Log("Processing :"+ targetName+" : "+ ok.ToString() + " / " + twingCount.ToString());
|
||||
ok++;
|
||||
ExecutionCore.CustomTask task = new ExecutionCore.CustomTask(chopSingleStick, objList, new ExecutionCore.TaskMetaData("Break Single Rock", new StaminaPrerequisite(true, 3), new ToolPrerequisite(true, w.GetType(), 1)));
|
||||
if (task.taskMetaData.cost == Int32.MaxValue)
|
||||
{
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
Utilities.clearExceptionListWithNames(true);
|
||||
continue;
|
||||
}
|
||||
ExecutionCore.TaskList.taskList.Add(task);
|
||||
// Utilities.clearExceptionListWithName(true, "Child");
|
||||
Utilities.clearExceptionListWithName("Child");
|
||||
// waterSingleCrop(v);
|
||||
}
|
||||
stonesToBreak.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static void getAllStonestoBreakRadius(GameLocation location)
|
||||
{
|
||||
object[] arr = new object[1];
|
||||
arr[0] = location;
|
||||
getAllStonesToBreakRadius(arr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void getAllStonesToBreakRadius(object obj)
|
||||
{
|
||||
int radius = 1;
|
||||
int twingCount = 0;
|
||||
object[] objArr = (object[])obj;
|
||||
GameLocation location = (GameLocation)objArr[0];
|
||||
string targetName = "Stone";
|
||||
if (StardustCore.Utilities.doesLocationContainObject(location, targetName))
|
||||
{
|
||||
StardewValley.Object twig = StardustCore.Utilities.checkRadiusForObject(radius, targetName);
|
||||
while (twig == null)
|
||||
{
|
||||
radius++;
|
||||
twig = StardustCore.Utilities.checkRadiusForObject(radius, targetName);
|
||||
}
|
||||
|
||||
|
||||
ModCore.CoreMonitor.Log(twig.name);
|
||||
|
||||
if (twig.name == targetName)
|
||||
{
|
||||
ModCore.CoreMonitor.Log(twig.name, LogLevel.Warn);
|
||||
TileNode t = new TileNode(1, Vector2.Zero, Path.Combine("Tiles", "GenericUncoloredTile.xnb"), Path.Combine("Tiles", "TileData.xnb"), StardustCore.IlluminateFramework.Colors.invertColor(StardustCore.IlluminateFramework.ColorsList.Brown));
|
||||
//t.placementAction(Game1.currentLocation, (int)v.Key.X * Game1.tileSize, (int)v.Key.Y * Game1.tileSize);
|
||||
t.fakePlacementAction(Game1.currentLocation, (int)twig.tileLocation.X, (int)twig.tileLocation.Y);
|
||||
Utilities.tileExceptionList.Add(new TileExceptionMetaData(t, "BreakStone"));
|
||||
stonesToBreak.Add(t);
|
||||
twingCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ModCore.CoreMonitor.Log(targetName+" is not found at location.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ok = 0;
|
||||
foreach (var v in stonesToBreak)
|
||||
{
|
||||
|
||||
object[] objList = new object[2];
|
||||
objList[0] = v;
|
||||
// ExecutionCore.TaskList.taskList.Add(new Task(new Action<object>(waterSingleCrop), obj));
|
||||
StardewValley.Tools.Pickaxe w = new StardewValley.Tools.Pickaxe();
|
||||
ModCore.CoreMonitor.Log("Processing stone:" + ok.ToString() + " / " + twingCount.ToString());
|
||||
ok++;
|
||||
ExecutionCore.CustomTask task = new ExecutionCore.CustomTask(breakSingleStone, objList, new ExecutionCore.TaskMetaData("Break Single Stone", new StaminaPrerequisite(true, 3), new ToolPrerequisite(true, w.GetType(), 1)));
|
||||
objList[1] = task.taskMetaData.path;
|
||||
task.objectParameterDataArray = objList;
|
||||
|
||||
|
||||
if (task.taskMetaData.cost == Int32.MaxValue)
|
||||
{
|
||||
// System.Threading.Thread.Sleep(1000);
|
||||
Utilities.clearExceptionListWithNames(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
ExecutionCore.TaskList.taskList.Add(task);
|
||||
Utilities.clearExceptionListWithName("Child");
|
||||
}
|
||||
stonesToBreak.Clear();
|
||||
}
|
||||
|
||||
|
||||
public static void breakSingleStone(TileNode v, List<TileNode> path)
|
||||
{
|
||||
object[] obj = new object[2];
|
||||
obj[0] = v;
|
||||
obj[1] = path;
|
||||
breakSingleStone(obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void breakSingleStone(object obj)
|
||||
{
|
||||
|
||||
object[] objArray = (object[])obj;
|
||||
|
||||
TileNode v = (TileNode)objArray[0];
|
||||
//List<TileNode> correctPath = Utilities.pathStuff(v);//(List<TileNode>)objArray[1];
|
||||
List<TileNode> correctPath = (List<TileNode>)objArray[1];
|
||||
foreach (var goodTile in correctPath)
|
||||
{
|
||||
StardustCore.ModCore.SerializationManager.trackedObjectList.Add(goodTile);
|
||||
//StardustCore.Utilities.masterAdditionList.Add(new StardustCore.DataNodes.PlacementNode(goodTile, Game1.currentLocation, (int)goodTile.tileLocation.X * Game1.tileSize, (int)goodTile.tileLocation.Y * Game1.tileSize));
|
||||
goodTile.placementAction(goodTile.thisLocation, (int)goodTile.tileLocation.X * Game1.tileSize, (int)goodTile.tileLocation.Y * Game1.tileSize);
|
||||
|
||||
}
|
||||
PathFindingLogic.calculateMovement(correctPath);
|
||||
|
||||
|
||||
|
||||
if (v.tileLocation.X < Game1.player.getTileX())
|
||||
{
|
||||
Game1.player.faceDirection(3);
|
||||
}
|
||||
else if (v.tileLocation.X > Game1.player.getTileX())
|
||||
{
|
||||
Game1.player.faceDirection(1);
|
||||
}
|
||||
else if (v.tileLocation.Y < Game1.player.getTileY())
|
||||
{
|
||||
Game1.player.faceDirection(0);
|
||||
}
|
||||
else if (v.tileLocation.Y > Game1.player.getTileY())
|
||||
{
|
||||
Game1.player.faceDirection(2);
|
||||
}
|
||||
foreach (var item in Game1.player.items)
|
||||
{
|
||||
if (item is StardewValley.Tools.Pickaxe)
|
||||
{
|
||||
Game1.player.CurrentToolIndex = Game1.player.getIndexOfInventoryItem(item);
|
||||
}
|
||||
}
|
||||
bool move = false;
|
||||
StardewValley.Object twig = v.thisLocation.objects[v.tileLocation];
|
||||
while ((twig.name == "Stone"))
|
||||
{
|
||||
if (!v.thisLocation.isObjectAt((int)v.tileLocation.X * Game1.tileSize, (int)v.tileLocation.Y * Game1.tileSize)) break;
|
||||
if (WindowsInput.InputSimulator.IsKeyDown(WindowsInput.VirtualKeyCode.VK_C) == false) WindowsInput.InputSimulator.SimulateKeyDown(WindowsInput.VirtualKeyCode.VK_C);
|
||||
|
||||
Vector2 center = new Vector2();
|
||||
if (Game1.player.facingDirection == 2)
|
||||
{
|
||||
center = Utilities.parseCenterFromTile((int)v.tileLocation.X + 1, (int)v.tileLocation.Y);
|
||||
continue;
|
||||
}
|
||||
if (Game1.player.facingDirection == 1)
|
||||
{
|
||||
center = Utilities.parseCenterFromTile((int)v.tileLocation.X - 1, (int)v.tileLocation.Y);
|
||||
continue;
|
||||
}
|
||||
if (Game1.player.facingDirection == 0)
|
||||
{
|
||||
center = Utilities.parseCenterFromTile((int)v.tileLocation.X, (int)v.tileLocation.Y + 1);
|
||||
continue;
|
||||
|
||||
}
|
||||
if (Game1.player.facingDirection == 3)
|
||||
{
|
||||
center = Utilities.parseCenterFromTile((int)v.tileLocation.X, (int)v.tileLocation.Y - 1);
|
||||
continue;
|
||||
}
|
||||
Game1.player.position = center;
|
||||
|
||||
|
||||
//Game1.setMousePosition((int)v.tileLocation.X*Game1.tileSize/2,(int)v.tileLocation.Y*Game1.tileSize/2);
|
||||
ModCore.CoreMonitor.Log("DOESNT Pickaxe LIKE YOU THINK IT SHOULD");
|
||||
ModCore.CoreMonitor.Log("player pos: " + Game1.player.position.ToString(), LogLevel.Warn);
|
||||
ModCore.CoreMonitor.Log("TilePos: " + v.position.ToString(), LogLevel.Error);
|
||||
}
|
||||
Utilities.cleanExceptionList(v);
|
||||
StardustCore.ModCore.SerializationManager.trackedObjectList.Remove(v);
|
||||
foreach (var goodTile in correctPath)
|
||||
{
|
||||
StardustCore.ModCore.SerializationManager.trackedObjectList.Remove(goodTile);
|
||||
goodTile.performRemoveAction(goodTile.tileLocation, goodTile.thisLocation);
|
||||
//goodTile.placementAction(goodTile.thisLocation, (int)goodTile.tileLocation.X * Game1.tileSize, (int)goodTile.tileLocation.Y * Game1.tileSize);
|
||||
}
|
||||
WindowsInput.InputSimulator.SimulateKeyUp(WindowsInput.VirtualKeyCode.VK_C);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue