Keeps the repo root clean - only README.md visible on landing page. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
400 lines
9.9 KiB
C#
400 lines
9.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
|
|
const int MAIN_ROOM = 80262160;
|
|
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;
|
|
|
|
var gameRooms = new[] { 80262165, 80262159, 80262161, 80262162, 80262164, 80262166, 80262167, 80262163 };
|
|
var completed = new HashSet<int>();
|
|
|
|
int GetColorNumber(string name)
|
|
{
|
|
var match = Regex.Match(name, @"\d+$");
|
|
return match.Success ? int.Parse(match.Value) : -1;
|
|
}
|
|
|
|
bool InArea(int x, int y, int minX, int maxX, int minY, int maxY) => x >= minX && x <= maxX && y >= minY && y <= maxY;
|
|
bool InField(int x, int y) => InArea(x, y, FIELD_MIN_X, FIELD_MAX_X, FIELD_MIN_Y, FIELD_MAX_Y);
|
|
bool InWaitingLine(int x, int y) => x == 14 && y >= 16 && y <= 33;
|
|
bool AtChair(int x, int y) => x == 14 && y == 15;
|
|
|
|
int GetRoomId()
|
|
{
|
|
try { return (int)Room.Id; } catch { return 0; }
|
|
}
|
|
|
|
(int x, int y) GetSelfPos()
|
|
{
|
|
try { return (Self.Location.X, Self.Location.Y); } catch { return (-1, -1); }
|
|
}
|
|
|
|
void WalkToAndWait(int tx, int ty)
|
|
{
|
|
for (int retry = 0; retry < 10; retry++)
|
|
{
|
|
Send(Out["MoveAvatar"], tx, ty);
|
|
for (int i = 0; i < 30; i++)
|
|
{
|
|
Delay(100);
|
|
var pos = GetSelfPos();
|
|
if (pos.x == tx && pos.y == ty)
|
|
{
|
|
Delay(200);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WalkToAreaAndWait(int minX, int maxX, int minY, int maxY)
|
|
{
|
|
for (int retry = 0; retry < 10; retry++)
|
|
{
|
|
var pos = GetSelfPos();
|
|
if (pos.x >= 0 && InArea(pos.x, pos.y, minX, maxX, minY, maxY))
|
|
{
|
|
Delay(200);
|
|
return;
|
|
}
|
|
Send(Out["MoveAvatar"], minX, minY);
|
|
for (int i = 0; i < 30; i++)
|
|
{
|
|
Delay(100);
|
|
pos = GetSelfPos();
|
|
if (pos.x >= 0 && InArea(pos.x, pos.y, minX, maxX, minY, maxY))
|
|
{
|
|
Delay(200);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ClickUntilTeleport(int id, int targetX, int targetY)
|
|
{
|
|
for (int retry = 0; retry < 20; retry++)
|
|
{
|
|
Send(Out["ClickFurni"], id, 0);
|
|
for (int i = 0; i < 20; i++)
|
|
{
|
|
Delay(100);
|
|
var pos = GetSelfPos();
|
|
if (pos.x == targetX && pos.y == targetY)
|
|
{
|
|
Delay(200);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UseUntilRoom(int id, int roomId)
|
|
{
|
|
for (int retry = 0; retry < 20; retry++)
|
|
{
|
|
Send(Out["UseFurniture"], id, 0);
|
|
for (int i = 0; i < 30; i++)
|
|
{
|
|
Delay(100);
|
|
if (GetRoomId() == roomId)
|
|
{
|
|
Delay(2000);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WaitForMainRoom()
|
|
{
|
|
for (int i = 0; i < 200; i++)
|
|
{
|
|
Delay(100);
|
|
if (GetRoomId() == MAIN_ROOM)
|
|
{
|
|
Delay(2000);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void WaitUntilInField()
|
|
{
|
|
Log("Waiting for field...");
|
|
|
|
while (true)
|
|
{
|
|
var pos = GetSelfPos();
|
|
if (pos.x < 0) { Delay(100); continue; }
|
|
|
|
if (InField(pos.x, pos.y))
|
|
{
|
|
Log($"In field at ({pos.x},{pos.y})");
|
|
Delay(300);
|
|
return;
|
|
}
|
|
|
|
if (AtChair(pos.x, pos.y))
|
|
{
|
|
Delay(100);
|
|
continue;
|
|
}
|
|
|
|
if (InWaitingLine(pos.x, pos.y))
|
|
{
|
|
Send(Out["MoveAvatar"], 14, 15);
|
|
Delay(200);
|
|
continue;
|
|
}
|
|
|
|
Send(Out["MoveAvatar"], 14, 20);
|
|
Delay(300);
|
|
}
|
|
}
|
|
|
|
void DoPixelArt()
|
|
{
|
|
WaitUntilInField();
|
|
|
|
var selectors = new Dictionary<int, int>();
|
|
try
|
|
{
|
|
foreach (var item in FloorItems)
|
|
{
|
|
if (item == null) continue;
|
|
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;
|
|
}
|
|
}
|
|
} catch { }
|
|
|
|
var sourcePixels = new Dictionary<(int x, int y), int>();
|
|
try
|
|
{
|
|
foreach (var item in FloorItems)
|
|
{
|
|
if (item == null) continue;
|
|
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;
|
|
}
|
|
} catch { }
|
|
|
|
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)>();
|
|
try
|
|
{
|
|
foreach (var item in FloorItems)
|
|
{
|
|
if (item == null) continue;
|
|
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);
|
|
}
|
|
} catch { }
|
|
|
|
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) break;
|
|
|
|
var sorted = toChange.OrderBy(x => x.srcColor).ToList();
|
|
int lastColor = -1;
|
|
|
|
foreach (var item in sorted)
|
|
{
|
|
if (item.srcColor != lastColor)
|
|
{
|
|
Send(Out["ClickFurni"], selectors[item.srcColor], 0);
|
|
Delay(50);
|
|
lastColor = item.srcColor;
|
|
}
|
|
|
|
Send(Out["ClickFurni"], item.fieldId, 0);
|
|
Delay(50);
|
|
changed++;
|
|
}
|
|
|
|
Delay(500);
|
|
}
|
|
|
|
try
|
|
{
|
|
var badge = FloorItems.FirstOrDefault(f => f != null && f.GetName() == "Badge Display Case");
|
|
if (badge != null)
|
|
Send(Out["ClickFurni"], (int)badge.Id, 0);
|
|
} catch { }
|
|
|
|
Log($"Done: {changed}");
|
|
completed.Add(GetRoomId());
|
|
}
|
|
|
|
void GoToRoom1()
|
|
{
|
|
if (completed.Contains(80262165)) return;
|
|
Log("Room 1");
|
|
WalkToAreaAndWait(5, 6, 25, 27);
|
|
ClickUntilTeleport(902905683, 11, 27);
|
|
ClickUntilTeleport(902906203, 11, 24);
|
|
UseUntilRoom(902906203, 80262165);
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
void GoToRoom2()
|
|
{
|
|
if (completed.Contains(80262159)) return;
|
|
Log("Room 2");
|
|
WalkToAreaAndWait(16, 20, 34, 35);
|
|
ClickUntilTeleport(902906461, 20, 34);
|
|
ClickUntilTeleport(902906426, 20, 32);
|
|
UseUntilRoom(902906426, 80262159);
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
void GoToRoom3()
|
|
{
|
|
if (completed.Contains(80262161)) return;
|
|
Log("Room 3");
|
|
WalkToAreaAndWait(25, 25, 17, 21);
|
|
Send(Out["ClickFurni"], 902906152, 0);
|
|
Delay(500);
|
|
ClickUntilTeleport(902907470, 25, 19);
|
|
UseUntilRoom(902907470, 80262161);
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
void GoToRoom4()
|
|
{
|
|
if (completed.Contains(80262162)) return;
|
|
Log("Room 4");
|
|
WalkToAreaAndWait(30, 31, 15, 16);
|
|
Send(Out["ClickFurni"], 902907718, 0);
|
|
Delay(500);
|
|
ClickUntilTeleport(902907623, 31, 15);
|
|
UseUntilRoom(902907623, 80262162);
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
void GoToRoom5()
|
|
{
|
|
if (completed.Contains(80262164)) return;
|
|
Log("Room 5");
|
|
WalkToAreaAndWait(30, 31, 15, 16);
|
|
Send(Out["ClickFurni"], 902907718, 0);
|
|
Delay(500);
|
|
WalkToAndWait(36, 16);
|
|
ClickUntilTeleport(902905838, 36, 16);
|
|
UseUntilRoom(902905838, 80262164);
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
void GoToRoom6()
|
|
{
|
|
if (completed.Contains(80262166)) return;
|
|
Log("Room 6");
|
|
WalkToAreaAndWait(30, 31, 15, 16);
|
|
Send(Out["ClickFurni"], 902907718, 0);
|
|
Delay(500);
|
|
WalkToAndWait(44, 14);
|
|
ClickUntilTeleport(902907457, 44, 14);
|
|
UseUntilRoom(902907457, 80262166);
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
void GoToRoom7()
|
|
{
|
|
if (completed.Contains(80262167)) return;
|
|
Log("Room 7");
|
|
WalkToAreaAndWait(30, 31, 15, 16);
|
|
Send(Out["ClickFurni"], 902907718, 0);
|
|
Delay(500);
|
|
WalkToAndWait(50, 12);
|
|
ClickUntilTeleport(902906400, 50, 12);
|
|
UseUntilRoom(902906400, 80262167);
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
void GoToRoom8()
|
|
{
|
|
if (completed.Contains(80262163)) return;
|
|
Log("Room 8");
|
|
WalkToAreaAndWait(50, 51, 21, 21);
|
|
Send(Out["ClickFurni"], 902906802, 0);
|
|
Delay(500);
|
|
ClickUntilTeleport(902906273, 50, 21);
|
|
UseUntilRoom(902906273, 80262163);
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
Log("Starting");
|
|
|
|
int currentRoom = GetRoomId();
|
|
|
|
if (gameRooms.Contains(currentRoom))
|
|
{
|
|
Log($"In game room {currentRoom}");
|
|
DoPixelArt();
|
|
WaitForMainRoom();
|
|
}
|
|
|
|
GoToRoom1();
|
|
GoToRoom2();
|
|
GoToRoom3();
|
|
GoToRoom4();
|
|
GoToRoom5();
|
|
GoToRoom6();
|
|
GoToRoom7();
|
|
GoToRoom8();
|
|
|
|
Log($"All done: {completed.Count}/8");
|
|
WalkToAreaAndWait(41, 41, 32, 33);
|