PDA

View Full Version : Click Chat Box Item Option



Le Jingle
09-04-2012, 04:02 AM
Here's a little snippet, that aids for those chat box options when you use items on each other / objects.

Here's the example / image of what I mean, and what this snippet will click.
http://i.imgur.com/dCYFX.png

It only supports up to 5 boxes, because after that you need to slide the options to get to more options (done by hovering the mouse over the arrow). Here's an example / image of what I mean by too many boxes:
http://i.imgur.com/asRBI.png

However I found this to be very helpful for things like cooking, potion making, bonefire firemaking (especially when you have 2 types of wood in your invent, such as maples and willows @ Daemonheim Woodcut Resource area, etc.), etc etc.

Also NOTE: This isn't any cool algorithmic function :/ but if you can turn the T2DIntegerArray into one, I'd be so grateful as it would definitely teach me something! :)

Also Also Note: It only works, AFTER you have used your item to make the chat interface appear.

program new;
{$i srl/srl.simba}

{
Ex. of usage =
if FindClickBox(3, 1) then
writeln('found 3 fletch choices, picking shortbow box, aka the 1st box.');
}

function FindClickBox(HowManyBoxes, WhichBox: Integer): Boolean;
var
MiddleXs: T2DIntegerArray;
begin
result := false;
if not inrange(HowManyBoxes, 1, 5) then
srl_warn('LogsChatBox', 'Too little/many boxes to choose!', warn_AllVersions);
MiddleXs := [TIntegerArray([259]),
TIntegerArray([211,307]),
TIntegerArray([161,259,357]),
TIntegerArray([112,210,308,406]),
TIntegerArray([105,182,259,336,413])];
if (CountColorTolerance(1710098, MCX1, MCY1, MCX2, MCY2, 1) > 500) then
begin
Mouse(MiddleXs[HowManyBoxes - 1][WhichBox - 1], 477 - 50, 25, 25, mouse_left);
result := WaitColorCount(9614019, MCX1, MCY1, MCX2, MCY2, 42, 1000, 56000, 5000);
end else
Writeln('Not enough colors found in chat box.');
end;

begin
SetupSRL;
ActivateClient;
if FindClickBox(1, 1) then
writeln('success');
end.


Cheers,
Lj

Edit; noticed that each array increases/decreases (w/ exception that twice it will stay at 259), distance from 259 by approx 49 each time.. but still stumped on a better equation. D:

Silentcore
09-04-2012, 04:25 AM
Nice work, might include in future projects when I get everything brainstormed really well. I'm thinking to make a script which might do a couple of different functions and this might give me a hand sometime.

litoris
09-04-2012, 06:35 AM
I think you could expand on it so that it supports all boxes. Have two input parameters, one will be eth total number of options and the other will be which box to click on. Then you could either have some fancy algorithm or hard-coded TBoxes to click into.

Le Jingle
09-04-2012, 07:03 AM
I think you could expand on it so that it supports all boxes. Have two input parameters, one will be eth total number of options and the other will be which box to click on. Then you could either have some fancy algorithm or hard-coded TBoxes to click into.
It does support all boxes (up to 5 at least).. And I do have two input params, Ttl # of boxes + Which box to click on... And I'm working on an algorithm, but it's a little over my head for the moment.

I did do TBoxArrays, but if I can work/receive help on an algorithm, it'd become a ton shorter, code wise. (Here's my first draft, the OP contains my current second draft):

function FindClickBox(HowManyBoxes, WhichBox: Integer): Boolean;
var
aFoundBox: TBoxArray;
begin
result := false;
if not inrange(HowManyBoxes, 1, 5) then
srl_warn('LogsChatBox', 'Too many boxes to choose!', warn_AllVersions);
SetLength(aFoundBox, HowManyBoxes);

case HowManyBoxes of
1: aFoundBox[0] := IntToBox(226, 449, 292, 506);

2:// 2 Boxes in the Chat Box screen.
begin
aFoundBox[0] := IntToBox(170, 449, 253, 506);
aFoundBox[1] := IntToBox(266, 449, 349, 506);
end;

3:// 3 Boxes in the chat box screen.
begin
aFoundBox[0] := IntToBox(119, 449, 204, 506);
aFoundBox[1] := IntToBox(217, 449, 302, 506);
aFoundBox[2] := IntToBox(315, 449, 400, 506);
end;

4:// 4 Boxes in the chat box screen.
begin
aFoundBox[0] := IntToBox(70, 449, 155, 506);
aFoundBox[1] := IntToBox(168, 449, 253, 506);
aFoundBox[2] := IntToBox(266, 449, 351, 506);
aFoundBox[3] := IntToBox(364, 449, 449, 506);
end;

5:// 5 Boxes in the chat box screen.
begin
aFoundBox[0] := IntToBox(75, 449, 136, 506);
aFoundBox[1] := IntToBox(152, 449, 213, 506);
aFoundBox[2] := IntToBox(229, 449, 290, 506);
aFoundBox[3] := IntToBox(306, 449, 367, 506);
aFoundBox[4] := IntToBox(383, 449, 444, 506);
end;
end;

if (CountColorTolerance(1710098, MCX1, MCY1, MCX2, MCY2, 1) > 5000) then
begin
MouseBox(aFoundBox[WhichBox - 1].x1,aFoundBox[WhichBox - 1].y1 - 50,
aFoundBox[WhichBox - 1].x2,aFoundBox[WhichBox - 1].y2 - 50, mouse_left);
result := WaitColorCount(9614019, MCX1, MCY1, MCX2, MCY2, 42, 10000, 56000, 5000);
end else
Writeln('Not enough colors found in chat box.');
end;

begin
SetupSRL;
ActivateClient;
if FindClickBox(4, 1) then
writeln('success');
end.


I even drew myself a pretty picture to help me visualize it and hopefully try to understand it:
(Yes, some of the numbers in the table are off by 1-2 from the actual + or - 49's, but it's all rounding error and/or a mix with when I chose center pixel from the boxes on the RS screen)
http://i.imgur.com/HAJUp.png

But I do need to find a way, in my opinion, to shorten the code down to a nice short-code-wise algorithm. Plus mouse scrolling support in a separate function would make it killer.

EDIT: The 5th row, I just noticed (it's late), isn't following the +/- 49... So edited that into the diagram.. :s still think the code would be shorter having an algorithm for the first several box options, and then resorting to potential box coords / tpoints for the 5th/6th+ opts.. :confused:

EDIT 2: It's most likely just me in combination with the late night, but I don't recognize any direct pattern relating each an every dot up to the 4th box options either.. I'll probably take another look at them tomorrow and see if I can deduce any plausible pattern/algo.. if not, then I'll just stick with TBoxArray coords, and work on sliding them with the mouse (to go for as many boxes possible, i.e. 5/6+)

Jakkle
09-10-2012, 12:58 PM
You could use a TPA parameter to find the box you want to click and then if its not in the first few boxes move the slider until tpa found ? You could use DTMs but the thing with DTMs is you have to see all the points of it before it's true. With a tpa you could click boxes that are only showing a little bit, if you get what I mean.

Runaway
09-10-2012, 10:21 PM
Hey Jingle,

I've got an algorithm but... it's quite ugly :pinch:


program new;
{$i SRL/SRL.simba}
const
HowMany = 1;
var
TPA: TPointArray;
n, d, o, x, y, i: Integer;
begin
{
1, 3, 5: Diff = 76 (+/-0 offset from 259)
[259]
[183, 259, 335]
[107, 183, 259, 335, 411]
2, 4: Diff = 98 (+/-48 offset from 259)
[211, 307]
[113, 211, 307, 405]
}
SetLength(TPA, HowMany);
for i := 0 to (HowMany - 1) do
begin
d := 76 + ((HowMany - 1) mod 2 * 22); // Difference between each box
o := (HowMany - 1) mod 2 * 48; // Offset from center of chat
n := Floor(HowMany / 2.0) - (HowMany - (i + 1)) - ((HowMany - 1) mod 2 * Round(i / (HowMany * 1.0))); // Current box number
x := 259 + (o * (2 * Round(i / (HowMany * 1.0)) - 1)) + (d * n);
y := MCCY + 20;
TPA[i] := Point(x, y);
end;
Writeln(TPA);
end.


I based it off your values / the screenshots you posted. I think that a TIA might work better for something like this :p That or grabbing a TPA of the box outline colors and separating them. You can get a nice center point of each with a MiddleTPA as well!

E: Guess I'll go ahead and post this for Jingle and everyone else that commented about other ways to do this... I've been working all day on a nifty crafting menu include after I read this thread. It functions similarly to ChooseOption / WaitOption, but for the crafting menu instead:


function CraftingScreen: Boolean;
begin
Result := CountColorTolerance(1131144, MCX1, MCY1, MCX2, MCY2, 3) >= 100;
end;

function ScrollCraftingMenu(Left: Boolean): Boolean;
var
Box: TBox;
P: TPoint;
begin
Result := False;
if not CraftingScreen then
Exit;
case Left of
True: P := Point(12, 394);
False: P := Point(493, 394);
// Top-left corners of each scroll bar
end;
Box := IntToBox(P.x, P.y, P.x + 12, P.y + 69);
Result := WaitColor(P.x, P.y, 791065, 1, 100);
if not Result then
Exit;
MouseTBox(Box, mouse_move);
while SimilarColors(GetColor(P.x, P.y), 791065, 1) do
Wait(50+Random(50));
end;

function GetCraftingOptions(var Options: TStringArray; var Points: TPointArray): Integer;
var
aTPA: T2DPointArray;
TPA: TPointArray;
Bounds: TBox;
P: TPoint;
lTPA, i: Integer;
begin
Result := 0;
if not CraftingScreen then
Exit;
SetLength(Options, 0);
SetLength(Points, 0);
FindColorsTolerance(TPA, 2070783, MCX1, MCY1, MCX2, MCY2, 0);
if (Length(TPA) < 1) then
Exit;
aTPA := SplitTPAEx(TPA, 20, 10);
SortATPAFromMidPoint(aTPA, Point(MCX1, MCCY));
lTPA := Length(aTPA);
SetLength(Options, lTPA);
SetLength(Points, lTPA);
for i := 0 to (lTPA - 1) do
begin
Bounds := GetTPABounds(aTPA[i]);
P := MiddleTPA(aTPA[i]);
Options[i] := GetTextAtExWrap(Bounds.x1, Bounds.y1, Bounds.x2, Bounds.y2, 0, 4, 2, 2070783, 0, statChars);
Points[i] := Point(P.x, P.y - 15);
if (Options[i] <> '') then
Inc(Result);
end;
end;

function CraftingOptionMulti(Text: TStringArray; Scroll: Boolean): Boolean;
var
Options: TStringArray;
Points: TPointArray;
Box: TBox;
M: TPoint;
hOption, hText, t, i, ii: Integer;
Left: Boolean;
begin
Result := False;
if not CraftingScreen then
Exit;
t := 0;
repeat
if InRange(t, 1, 2) and Scroll then
begin
case t of
1: Left := True;
2: Left := False;
end;
if not ScrollCraftingMenu(Left) then
Continue;
end;
GetCraftingOptions(Options, Points);
if (Length(Options) < 1) then
Exit;
hOption := High(Options);
hText := High(Text);
for i := 0 to hText do
begin
for ii := 0 to hOption do
begin
if (Pos(Text[i], Options[ii]) <> 0) then
begin
Result := True;
Box := IntToBox(Points[ii].x - 20, Points[ii].y - 20, Points[ii].x + 20, Points[ii].y + 20);
GetMousePos(M.x, M.y);
if PointInBox(M, Box) then
ClickMouse2(mouse_left)
else
MouseTBox(Box, mouse_left);
Exit;
end;
end;
end;
if not Scroll then
Exit;
Inc(t);
until(t > 2);
end;

function CraftingOption(Text: String; Scroll: Boolean): Boolean;
begin
Result := CraftingOptionMulti([Text], Scroll);
end;

function WaitCraftingOptionMulti(Time: Integer; Text: TStringArray; Scroll: Boolean): Boolean;
var
t: Integer;
begin
Result := False;
MarkTime(t);
while not Result and (TimeFromMark(t) < Time) do
Result := CraftingOptionMulti(Text, Scroll);
end;

function WaitCraftingOption(Time: Integer; Text: String; Scroll: Boolean): Boolean;
begin
Result := WaitCraftingOptionMulti(Time, [Text], Scroll);
end;


Haven't tested it much yet, but it seems spot on so far :)

KeepBotting
09-11-2012, 01:31 AM
Thanks, bookmarked.

Le Jingle
09-11-2012, 03:44 AM
Wow, that's some great stuff Runaway! :)

Your algorithm for the boxes looks great! I understand math, however I'm still working on wrapping my head around operators that do such (floor, mod, div). I lack some reading on those, and I was suspecting an algorithm would come much easier with those too. I'll try to add that research to my list of self taught programming learnings, to do list.

I also like the crafting include you took some time to work on. Definitely looks useful for craft scripts. I hope you don't mind, but I commented in a couple questions in that include below. Just so I make more sense when asking the question (you can correspond to the code right away).


function CraftingScreen: Boolean;
begin
Result := CountColorTolerance(1131144, MCX1, MCY1, MCX2, MCY2, 3) >= 100;
end;

function ScrollCraftingMenu(Left: Boolean): Boolean;
var
Box: TBox;
P: TPoint;
begin
Result := False;
if not CraftingScreen then
Exit;
case Left of
True: P := Point(12, 394);
False: P := Point(493, 394);
end;
Box := IntToBox(P.x, P.y, P.x + 12, P.y + 69);
Result := WaitColor(P.x, P.y, 791065, 1, 100);
if not Result then
Exit;
MouseTBox(Box, mouse_move);
while SimilarColors(GetColor(P.x, P.y), 791065, 1) do // This is for the slider arrows, for when it goes inactive (meaning you've gone as far to the L/R as possible?
Wait(50+Random(50));
end;

function GetCraftingOptions(var Options: TStringArray; var Points: TPointArray): Integer;
var
aTPA: T2DPointArray;
TPA: TPointArray;
Bounds: TBox;
P: TPoint;
lTPA, i: Integer;
begin
Result := 0;
if not CraftingScreen then
Exit;
SetLength(Options, 0);
SetLength(Points, 0);
FindColorsTolerance(TPA, 2070783, MCX1, MCY1, MCX2, MCY2, 0);
if (Length(TPA) < 1) then
Exit;
aTPA := SplitTPAEx(TPA, 20, 10);
SortATPAFromMidPoint(aTPA, Point(MCX1, MCCY));
lTPA := Length(aTPA);
SetLength(Options, lTPA);
SetLength(Points, lTPA);
for i := 0 to (lTPA - 1) do
begin
Bounds := GetTPABounds(aTPA[i]);
P := MiddleTPA(aTPA[i]);
Options[i] := GetTextAtExWrap(Bounds.x1, Bounds.y1, Bounds.x2, Bounds.y2, 0, 4, 2, 2070783, 0, statChars);
Points[i] := Point(P.x, P.y - 15);
if (Options[i] <> '') then
Inc(Result);
end;
end;

function CraftingOptionMulti(Text: TStringArray; Scroll: Boolean): Boolean;
var
Options: TStringArray;
Points: TPointArray;
Box: TBox;
M: TPoint;
hOption, hText, t, i, ii: Integer;
Left: Boolean;
begin
Result := False;
if not CraftingScreen then
Exit;
t := 0;
repeat
if InRange(t, 1, 2) and Scroll then
begin
case t of
1: Left := True;
2: Left := False;
end;
if not ScrollCraftingMenu(Left) then
Continue;
end;
GetCraftingOptions(Options, Points);
if (Length(Options) < 1) then
Exit;
hOption := High(Options);
hText := High(Text);
for i := 0 to hText do
begin // does not it work to remove the begin + corresponding end here?
for ii := 0 to hOption do
begin
if (Pos(Text[i], Options[ii]) <> 0) then
begin
Result := True;
Box := IntToBox(Points[ii].x - 20, Points[ii].y - 20, Points[ii].x + 20, Points[ii].y + 20);
GetMousePos(M.x, M.y);
if PointInBox(M, Box) then
ClickMouse2(mouse_left)
else
MouseTBox(Box, mouse_left);
Exit;
end;
end;
end;
if not Scroll then
Exit;
Inc(t);
until(t > 2);
end;

function CraftingOption(Text: String; Scroll: Boolean): Boolean;
begin
Result := CraftingOptionMulti([Text], Scroll);
end;

function WaitCraftingOptionMulti(Time: Integer; Text: TStringArray; Scroll: Boolean): Boolean;
var
t: Integer;
begin
Result := False;
MarkTime(t);
while not Result and (TimeFromMark(t) < Time) do
Result := CraftingOptionMulti(Text, Scroll);
end;

function WaitCraftingOption(Time: Integer; Text: String; Scroll: Boolean): Boolean;
begin
Result := WaitCraftingOptionMulti(Time, [Text], Scroll);
end;


May I ask too, the preference for setting things like hText, instead of using high(text)? Does it not reset in some instances, or is it better format?

My questions come from an uneducated point of view, rather than any type of criticizing point of view :) Sorry for not testing these yet either, I'll give them a go after I get past this scripting competition stuffs :p

Runaway
09-11-2012, 05:18 PM
Wow, that's some great stuff Runaway! :)

Your algorithm for the boxes looks great! I understand math, however I'm still working on wrapping my head around operators that do such (floor, mod, div). I lack some reading on those, and I was suspecting an algorithm would come much easier with those too. I'll try to add that research to my list of self taught programming learnings, to do list.

I also like the crafting include you took some time to work on. Definitely looks useful for craft scripts. I hope you don't mind, but I commented in a couple questions in that include below. Just so I make more sense when asking the question (you can correspond to the code right away).

-Snip-

May I ask too, the preference for setting things like hText, instead of using high(text)? Does it not reset in some instances, or is it better format?

My questions come from an uneducated point of view, rather than any type of criticizing point of view :) Sorry for not testing these yet either, I'll give them a go after I get past this scripting competition stuffs :p

Thanks :) I've been fooling around with OCR lately and it's got some great uses! I actually provided some mod and floor examples to someone the other day, you can check it out here (http://villavu.com/forum/showpost.php?p=1096730&postcount=12) if you want.

Time for a little Q&A sesh!

Q: does not it work to remove the begin + corresponding end here?
A: Yes. Both ways work the same, I like to use a begin/end to encompass anything taking up more than one line to stay organized :)

Q: This is for the slider arrows, for when it goes inactive (meaning you've gone as far to the L/R as possible)?
A: Yes. When it goes inactive the color changes to something like 1448025.

Q: May I ask too, the preference for setting things like hText, instead of using high(text)? Does it not reset in some instances, or is it better format?
A: It depends. Since it's faster to set a High(whatever) as a var and call the var twice compared to calling High(whatever) twice, I do the former when I'm using the same High() or Length() more than once. The example you picked out from my code was actually something I messed up :p I have fixed it though; it should have been placed before the first repeat. That way, I only call High(Text) once but use that value 3 times!

I updated the crafting code a bit so I figured I'd post it again as well. You can see what I was talking about @moving the hText:


function CraftingScreen: Boolean;
begin
Result := CountColorTolerance(1131144, MCX1, MCY1, MCX2, MCY2, 3) >= 100;
end;

function ScrollCraftingMenu(Left: Boolean): Boolean;
var
Box: TBox;
P: TPoint;
t: Integer;
begin
Result := False;
if not CraftingScreen then
Exit;
case Left of
True: P := Point(12, 394);
False: P := Point(493, 394);
end;
Box := IntToBox(P.x, P.y, P.x + 12, P.y + 69);
Result := WaitColor(P.x, P.y, 791065, 1, 100);
if not Result then
Exit;
MouseTBox(Box, mouse_move);
MarkTime(t);
while SimilarColors(GetColor(P.x, P.y), 791065, 1) and (TimeFromMark(t) < 2500) do
Wait(100+Random(50));
end;

function GetCraftingOptions(var Options: TStringArray; var Points: TPointArray): Integer;
var
aTPA: T2DPointArray;
TPA: TPointArray;
Bounds: TBox;
P: TPoint;
lTPA, i: Integer;
begin
Result := 0;
if not CraftingScreen then
Exit;
SetLength(Options, 0);
SetLength(Points, 0);
FindColorsTolerance(TPA, 2070783, MCX1, MCY1, MCX2, MCY2, 0);
if (Length(TPA) < 1) then
Exit;
aTPA := SplitTPAEx(TPA, 20, 10);
SortATPAFromMidPoint(aTPA, Point(MCX1, MCCY));
lTPA := Length(aTPA);
SetLength(Options, lTPA);
SetLength(Points, lTPA);
for i := 0 to (lTPA - 1) do
begin
Bounds := GetTPABounds(aTPA[i]);
P := MiddleTPA(aTPA[i]);
Options[i] := GetTextAtExWrap(Bounds.x1, Bounds.y1, Bounds.x2, Bounds.y2, 0, 4, 2, 2070783, 0, statChars);
Points[i] := Point(P.x, P.y - 15);
if (Options[i] <> '') then
Inc(Result);
end;
end;

function CraftingOptionMulti(Text: TStringArray; Scroll: Boolean): Boolean;
var
Options: TStringArray;
Points: TPointArray;
Box: TBox;
M: TPoint;
hOption, hText, t, i, ii: Integer;
Left: Boolean;
begin
Result := False;
if not CraftingScreen then
Exit;
hText := High(Text);
t := 0;
repeat
if InRange(t, 1, 2) and Scroll then
begin
case t of
1: Left := True;
2: Left := False;
end;
if not ScrollCraftingMenu(Left) then
Continue;
end;
GetCraftingOptions(Options, Points);
if (Length(Options) < 1) then
Exit;
hOption := High(Options);
for i := 0 to hText do
begin
for ii := 0 to hOption do
begin
if (Pos(Text[i], Options[ii]) <> 0) then
begin
Result := True;
Box := IntToBox(Points[ii].x - 15, Points[ii].y - 15, Points[ii].x + 15, Points[ii].y + 15);
GetMousePos(M.x, M.y);
if PointInBox(M, Box) then
ClickMouse2(mouse_left)
else
MouseTBox(Box, mouse_left);
Exit;
end;
end;
end;
if not Scroll then
Exit;
Inc(t);
until(t > 2);
end;

function CraftingOption(Text: String; Scroll: Boolean): Boolean;
begin
Result := CraftingOptionMulti([Text], Scroll);
end;

function WaitCraftingOptionMulti(Time: Integer; Text: TStringArray; Scroll: Boolean): Boolean;
var
t: Integer;
begin
Result := False;
MarkTime(t);
while not Result and (TimeFromMark(t) < Time) do
Result := CraftingOptionMulti(Text, Scroll);
end;

function WaitCraftingOption(Time: Integer; Text: String; Scroll: Boolean): Boolean;
begin
Result := WaitCraftingOptionMulti(Time, [Text], Scroll);
end;