Keeps the repo root clean - only README.md visible on landing page. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
156 lines
4.1 KiB
C#
156 lines
4.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
|
|
const int SOURCE_MIN_X = 18;
|
|
const int SOURCE_MAX_X = 29;
|
|
const int SOURCE_MIN_Y = 25;
|
|
const int SOURCE_MAX_Y = 36;
|
|
|
|
const int FIELD_MIN_X = 18;
|
|
const int FIELD_MAX_X = 29;
|
|
const int FIELD_MIN_Y = 9;
|
|
const int FIELD_MAX_Y = 20;
|
|
|
|
int GetColorNumber(string name)
|
|
{
|
|
var match = Regex.Match(name, @"\d+$");
|
|
return match.Success ? int.Parse(match.Value) : -1;
|
|
}
|
|
|
|
bool InField(int x, int y) => x >= FIELD_MIN_X && x <= FIELD_MAX_X && y >= FIELD_MIN_Y && y <= FIELD_MAX_Y;
|
|
|
|
Log("=== WAITING FOR FIELD POSITION ===");
|
|
|
|
while (true)
|
|
{
|
|
int selfX = Self.Location.X;
|
|
int selfY = Self.Location.Y;
|
|
|
|
if (selfX == 14 && selfY >= 16 && selfY <= 35)
|
|
{
|
|
Log("Moving to (14, 15)...");
|
|
await SendAsync(Out["MoveAvatar"], 14, 15);
|
|
await Task.Delay(500);
|
|
continue;
|
|
}
|
|
|
|
if (InField(selfX, selfY))
|
|
{
|
|
Log($"In field at ({selfX}, {selfY}), starting!");
|
|
break;
|
|
}
|
|
|
|
await Task.Delay(100);
|
|
}
|
|
|
|
Log("=== AUTO DETECTING COLORS ===");
|
|
|
|
var selectors = new Dictionary<int, int>();
|
|
foreach (var item in FloorItems)
|
|
{
|
|
string name = item.GetName();
|
|
if (name.Contains("Cylinder Block") || name.Contains("Hemisphere Block"))
|
|
{
|
|
int colorNum = GetColorNumber(name);
|
|
if (colorNum > 0 && !selectors.ContainsKey(colorNum))
|
|
{
|
|
selectors[colorNum] = (int)item.Id;
|
|
Log($"Selector: {name} -> Color {colorNum}");
|
|
}
|
|
}
|
|
}
|
|
Log($"Total selectors: {selectors.Count}");
|
|
|
|
var sourcePixels = new Dictionary<(int x, int y), int>();
|
|
foreach (var item in FloorItems)
|
|
{
|
|
int x = item.Location.X;
|
|
int y = item.Location.Y;
|
|
double z = item.Location.Z;
|
|
if (x < SOURCE_MIN_X || x > SOURCE_MAX_X || y < SOURCE_MIN_Y || y > SOURCE_MAX_Y) continue;
|
|
if (z < 0.7 || z > 1.0) continue;
|
|
int colorNum = GetColorNumber(item.GetName());
|
|
if (colorNum > 0)
|
|
sourcePixels[(x, y)] = colorNum;
|
|
}
|
|
Log($"Source pixels: {sourcePixels.Count}");
|
|
|
|
int offsetY = SOURCE_MIN_Y - FIELD_MIN_Y;
|
|
int changed = 0;
|
|
|
|
for (int attempt = 1; attempt <= 3; attempt++)
|
|
{
|
|
var fieldTiles = new Dictionary<(int x, int y), (int id, int colorNum)>();
|
|
foreach (var item in FloorItems)
|
|
{
|
|
int x = item.Location.X;
|
|
int y = item.Location.Y;
|
|
double z = item.Location.Z;
|
|
if (x < FIELD_MIN_X || x > FIELD_MAX_X || y < FIELD_MIN_Y || y > FIELD_MAX_Y) continue;
|
|
|
|
int colorNum = GetColorNumber(item.GetName());
|
|
|
|
if (z > 0.5)
|
|
fieldTiles[(x, y)] = ((int)item.Id, colorNum);
|
|
else if (!fieldTiles.ContainsKey((x, y)))
|
|
fieldTiles[(x, y)] = ((int)item.Id, -1);
|
|
}
|
|
|
|
var toChange = new List<(int fieldId, int srcColor)>();
|
|
foreach (var src in sourcePixels)
|
|
{
|
|
int fieldX = src.Key.x;
|
|
int fieldY = src.Key.y - offsetY;
|
|
int srcColor = src.Value;
|
|
|
|
if (!fieldTiles.TryGetValue((fieldX, fieldY), out var field)) continue;
|
|
if (field.colorNum == srcColor) continue;
|
|
if (!selectors.ContainsKey(srcColor)) continue;
|
|
|
|
toChange.Add((field.id, srcColor));
|
|
}
|
|
|
|
if (toChange.Count == 0)
|
|
{
|
|
Log($"Attempt {attempt}: All correct!");
|
|
break;
|
|
}
|
|
|
|
Log($"Attempt {attempt}: {toChange.Count} to change");
|
|
|
|
var sorted = toChange.OrderBy(x => x.srcColor).ToList();
|
|
int lastColor = -1;
|
|
|
|
foreach (var item in sorted)
|
|
{
|
|
if (item.srcColor != lastColor)
|
|
{
|
|
await SendAsync(Out["ClickFurni"], selectors[item.srcColor], 0);
|
|
await Task.Delay(50);
|
|
lastColor = item.srcColor;
|
|
}
|
|
|
|
await SendAsync(Out["ClickFurni"], item.fieldId, 0);
|
|
await Task.Delay(50);
|
|
changed++;
|
|
}
|
|
|
|
await Task.Delay(500);
|
|
}
|
|
|
|
Log("=== SUBMITTING ===");
|
|
var badge = FloorItems.FirstOrDefault(f => f.GetName() == "Badge Display Case");
|
|
if (badge != null)
|
|
{
|
|
await SendAsync(Out["ClickFurni"], (int)badge.Id, 0);
|
|
Log($"Clicked Badge Display Case (ID: {badge.Id})");
|
|
}
|
|
else
|
|
{
|
|
Log("Badge Display Case not found!");
|
|
}
|
|
|
|
Log($"Done! Total changed: {changed}");
|