World Hopping Fixed Point ACA
Hops worlds, Collects colors, Returns best CTS1 color/tolerance
Thank you to @Flight and @nielsie95 without whom this would not have been possible.
The intended use and why I put this together is to more easily do/use ACA on specific points for the creation of item DTMs.
I've found that to make good item DTMs with the DTM Editor you need to make use of ACA for the colored points the same way you would on mainscreen objects. That usually means hopping through worlds to account for the color shifts, but with DTMs I find it hard to always pick the same point.
I aimed to keep it simple:
- There's only 2 variables to modify, a list of points and a list of worlds
- It assumes you're already logged in
- It only calculates CTS1 values
The script iterates through the listed worlds and switches to them using AeroLib. On each world it collects the colors at the listed points. After collection, it calculates and outputs the best color and tolerance for each point using the CTS1 algorithm from nielsie95's ACA v3 code release.
Progress Report:
{X = 565, Y = 227} -> Color: 65536, Tolerance: 0
{X = 568, Y = 239} -> Color: 65536, Tolerance: 0
{X = 577, Y = 223} -> Color: 3433362, Tolerance: 4
Successfully executed.
Using this, building item DTMs has become easier. I can work with multiple points or items without worrying about having used the same point of comparison from one world to another. It gathers the colors and switches worlds much faster then I could doing it manually. It also negates the need for inputting colors into ACA since it does the needed CTS1 calculations directly in the script and only outputs the best color result.
Simba Code:
program Annaeus_WorldHoppingFixedPointACA;
{$DEFINE SMART}
{$i AeroLib/AeroLib.Simba}
{ Thanks to Flight and nielsie95
Used features, data and algorithms from the following:
[WIP] ACA v3 from nielsie95
https://villavu.com/forum/showthread.php?t=70704
AeroLib Include from Flight
https://villavu.com/forum/showthread.php?t=108953
* Assumes you're already logged in
* Best results on items that are in your inventory, that's what this
was intended for
}
const
WorldsToVisit : TIntegerArray =
[301, 308, 316, 326, 335, 381, 382, 383, 384, 385, 393, 394];
PointsToInspect : TPointArray =
[{Pnt 1}[{X}565,{Y}227], {Pnt 2}[{X}568,{Y}239], {Pnt 3}[{X}577,{Y}223]];
{Short Version [[565, 227], [568, 239], [577, 223]];}
type
TColorAndRGB = union
Color : TColor;
RGB : packed record R, G, B: Byte; end;
end;
TColorAndRGBArray = array of TColorAndRGB;
var
I, J, BestColor, BestTolerance: Integer;
CollectedColors : array of TColorAndRGBArray;
{ procedure BestColor_CTS1(Colors : TColorAndRGBArray);
Implementation of nielsie95's CTS1 algorithm }
procedure BestColor_CTS1(Colors : TColorAndRGBArray);
var
R, G, B, K : Integer;
MinC, MaxC : TColorAndRGB;
begin
if not (High(Colors) > 0) then Exit; {Check there's at least one}
MinC := Colors[0];
MaxC := Colors[0];
if not (High(Colors) > 1) then Exit; {No need to go further if only one}
for K := 1 to High(Colors) do
begin
if (Colors[K].RGB.R < MinC.RGB.R) then MinC.RGB.R := Colors[K].RGB.R;
if (Colors[K].RGB.R > MaxC.RGB.R) then MaxC.RGB.R := Colors[K].RGB.R;
if (Colors[K].RGB.G < MinC.RGB.G) then MinC.RGB.G := Colors[K].RGB.G;
if (Colors[K].RGB.G > MaxC.RGB.G) then MaxC.RGB.G := Colors[K].RGB.G;
if (Colors[K].RGB.B < MinC.RGB.B) then MinC.RGB.B := Colors[K].RGB.B;
if (Colors[K].RGB.B > MaxC.RGB.B) then MaxC.RGB.B := Colors[K].RGB.B;
end;
R := Ceil((MaxC.RGB.R - MinC.RGB.R) / 2.0);
G := Ceil((MaxC.RGB.G - MinC.RGB.G) / 2.0);
B := Ceil((MaxC.RGB.B - MinC.RGB.B) / 2.0);
BestColor := RGBToColor(MinC.RGB.R + R, MinC.RGB.G + G, MinC.RGB.B + B);
BestTolerance := Ceil(Sqrt(R*R + G*G + B*B));
end;
begin
initAL;
{Build arrays}
SetLength(CollectedColors, Length(PointsToInspect));
for I := 0 to High(CollectedColors) do
SetLength(CollectedColors[I], Length(WorldsToVisit));
{Hop worlds and collect colors}
for I := 0 to High(WorldsToVisit) do
begin
WS_switchWorlds(WorldsToVisit[I]);
gameTab(TAB_INV);
for J := 0 to High(PointsToInspect) do
begin
CollectedColors[J][I].Color :=
GetColor(PointsToInspect[J].X, PointsToInspect[J].Y);
end;
Wait(Random(700, 1200)); {Hops pretty fast otherwise}
end;
ClearDebug;
{Output results}
for I := 0 to High(PointsToInspect) do
begin
BestColor_CTS1(CollectedColors[I]);
WriteLn(ToStr(PointsToInspect[I]) + ' -> Color: ' + IntToStr(BestColor)
+ ', Tolerance: ' + IntToStr(BestTolerance));
end;
end.
This could be considered a snippet due to it's length, but I thought it would be a better fit in this section. I also didn't find anything similar in this section and I'm thinking someone else might be able to benefit from it.
I welcome any comments, suggestions and criticism. I'm mainly still sorting out contributing without releasing the scripts I've been working on and this seemed like a good start.
I should note that there are slight quirks associated with the world switching, but for the most part it hops on enough of them to provide useful results. There's two things I noticed:
- For the single digit worlds it sometimes ends up picking the wrong world, for example 38 instead of 8.
- If the world it's trying to switch to is the last one appearing at the bottom, it ends up failing saying it can't find the world. (I suspect this is related to the text recognition and the amount of space available)
@tls makes a valid suggestion below concerning restarting SMART, but it's not something I've experienced as of yet. For this initial release I tried to keep it simple and functional. I wanted to share something sooner rather then later as I'm observing a tendency to over complicate things in my own scripts and they never fully get completed. It's partly why I omitted login routines and a preset world list. If this becomes necessary on my end I'll definitely consider and look into it. It would also avoid the occasional case where a switch takes too long/disconnects and you end up on the login screen.