SRL Archive - Help and Support

Item Picking


Goobs

2011-06-30 07:21:04

I have been working on a roach ranging script, and I've gotten it done for the most part.. My only main hitch is item picking. I have used TileToMS and TileToMSEx to try to get the center point on a tile so I can pickup items, but my main problems are:

1. It doesn't always give me the exact center
2. Single arrows on a tile give it trouble because it has to be on the pixel

To try to remedy the latter, I implemented a color search for the arrow fletching, but this only slowed down my script.

Is there a fast, reliable item picking function someone has made that can help me speed up my script? I'm only getting around 9k exp per hour with it >.<

Any help is appreciated!

PoW

masterBB

2011-06-30 07:26:26

I had this problem to, I use the tiletoMSEX function to get the corners of the tile, then I search for the item color between those corners. It worked really fast for me.

Goobs

2011-06-30 07:38:17

I was thinking on doing that, but I wasn't sure if it would work xD My other problem is that I only want it picking up items in a certain cage.. For instance


cage := [4000, 3000, 4005, 3005]; //example
for x := Cage.x1 to Cage.x2 do
begin
for y := Cage.y1 to Cage.y2 do
begin
TempPt := Point(x, y);
ArrayOfItems := GetItemsAt(TempPt);
tile conversions, etc..
end;
end;

Obviously that's just something I made up, but my point is that there HAS to be a better way >.<

masterBB

2011-06-30 08:02:36

Copied from reflection 2_1:
(*
R_GetGroundItemsEx
~~~~~~~~~~~~~~~~~~

.. code-block:: pascal

function R_GetGroundItemsEx(IDs: TIntegerArray; MaxDist: Integer): TGroundItemArray;

Retrieves all of the ground items within a circle with a radius of MaxDist that
contain one of the IDs specified. Stores them in a TGroundItemArray.

.. note::

by Drags111

*)
function R_GetGroundItemsEx(IDs: TIntegerArray; MaxDist: Integer): TGroundItemArray;
var
Cache, Hash, Plane, Nodes, Size, Index, Tail, Cur, Next,
UID, List, TheID, Stack: Integer;
H, I, BX, BY, endx, endy: Integer;
Tiles: TTileArray;
begin
SetLength(Result, 0);
BX := SmartGetFieldInt(0, hook_static_BaseX);
BY := SmartGetFieldInt(0, hook_static_BaseY);
EndX := BX + 104;
EndY := BY + 104;

Cache := SmartGetFieldObject(0, hook_static_GroundItemCache);
Nodes := SmartGetFieldObject(cache, hook_nodecache_GetNodes);
SmartFreeObject(Cache);
Plane := SmartGetFieldInt(0, hook_static_LoadedPlane);
Size := SmartGetFieldArraySize(Nodes, '', 1);

Tiles := R_SortedCircleTPA(R_GetMyPos, MaxDist);
H := High(Tiles);

for I := 0 to H do
begin
List := 0;
Hash := Tiles[I].X or (Tiles[I].Y shl 14) or (Plane shl 28);
Index := Hash and (Size - 1);

Tail := SmartGetFieldArrayObject(Nodes, '', Index);
Cur := SmartGetFieldObject(Tail, hook_node_Next);

try
while (not (SmartIsEqual(Tail, Cur))) do
begin
UID := SmartGetFieldLongL(Cur, hook_node_GetID);
if (UID = Hash) then
begin
List := SmartGetFieldObject(Cur, hook_nodelistcache_GetNodeList);
Break;
end;

Next := SmartGetFieldObject(Cur, hook_node_Next);
SmartFreeObject(Cur);
Cur := Next;
end;
finally
SmartFreeObject(Cur);
SmartFreeObject(Tail);
end;

if(List = 0)then
Continue;

Tail := SmartGetFieldObject(list, hook_nodelist_Head);
List := 0;
Cur := SmartGetFieldObject(tail, hook_node_Next);
while (not (SmartIsEqual(tail, cur))) do
begin
TheID := SmartGetFieldInt(Cur, hook_item_GetID);
if InIntArray(IDs, TheID)then
begin
SetArrayLength(Result, GetArrayLength(Result) + 1);
with Result[High(Result)] do
begin
ID := TheID;
Stack := SmartGetFieldInt(Cur, hook_item_GetStack);
Tile.X := Tiles[I].X;
Tile.Y := Tiles[I].Y;
end;
end;
Next := SmartGetFieldObject(Cur, hook_node_Next);
SmartFreeObject(Cur);
Cur := Next;
end;

SmartFreeObject(Cur);
SmartFreeObject(Tail);
SmartFreeObject(List);
end;
SmartFreeObject(Nodes);
end;

This one is much faster, but you will need to adjust it for a square cage, I've made a set up for you. This hasn't been tested so it probally will still contains bugs.

function R_GetGroundItemsEx(IDs: TIntegerArray; SearchBox:Tbox): TGroundItemArray;
var
Cache, Hash, Plane, Nodes, Size, Index, Tail, Cur, Next,
UID, List, TheID, Stack: Integer;
cTileX, cTileY: Integer;
begin
SetLength(Result, 0);

Cache := SmartGetFieldObject(0, hook_static_GroundItemCache);
Nodes := SmartGetFieldObject(cache, hook_nodecache_GetNodes);
SmartFreeObject(Cache);
Plane := SmartGetFieldInt(0, hook_static_LoadedPlane);
Size := SmartGetFieldArraySize(Nodes, '', 1);

for cTileX := SearchBox.X1 to SearchBox.X2 do
for cTileY := SearchBox.Y1 to SearchBox.Y2 do
begin
List := 0;
Hash := cTileX or (cTileY shl 14) or (Plane shl 28);
Index := Hash and (Size - 1);

Tail := SmartGetFieldArrayObject(Nodes, '', Index);
Cur := SmartGetFieldObject(Tail, hook_node_Next);

try
while (not (SmartIsEqual(Tail, Cur))) do
begin
UID := SmartGetFieldLongL(Cur, hook_node_GetID);
if (UID = Hash) then
begin
List := SmartGetFieldObject(Cur, hook_nodelistcache_GetNodeList);
Break;
end;

Next := SmartGetFieldObject(Cur, hook_node_Next);
SmartFreeObject(Cur);
Cur := Next;
end;
finally
SmartFreeObject(Cur);
SmartFreeObject(Tail);
end;

if(List = 0)then
Continue;

Tail := SmartGetFieldObject(list, hook_nodelist_Head);
List := 0;
Cur := SmartGetFieldObject(tail, hook_node_Next);
while (not (SmartIsEqual(tail, cur))) do
begin
TheID := SmartGetFieldInt(Cur, hook_item_GetID);
if InIntArray(IDs, TheID)then
begin
SetArrayLength(Result, GetArrayLength(Result) + 1);
with Result[High(Result)] do
begin
ID := TheID;
Stack := SmartGetFieldInt(Cur, hook_item_GetStack);
Tile.X := cTileX;
Tile.Y := cTileY;
end;
end;
Next := SmartGetFieldObject(Cur, hook_node_Next);
SmartFreeObject(Cur);
Cur := Next;
end;

SmartFreeObject(Cur);
SmartFreeObject(Tail);
SmartFreeObject(List);
end;
SmartFreeObject(Nodes);
end;

Flight

2011-06-30 09:28:16

If you could get the tile the item is on and then use your TPAFinder to search just with the X/Y box of that tile only, would that not be accurate?

Smarter Child

2011-06-30 11:34:51

This is from my fighter, works fast enough imo:
Function PickupGroundItems: boolean;
var
TGIA: TGroundItemArray;
I, X, Y, d: Integer;
GPoint: TPoint;
begin
if R_Invfull then
Exit;
TGIA := GetItemsNear(2);
For I := 0 To High(TGIA)do
For D := 0 To High(Players[currentplayer].Arrays[1])do
begin
if FindGroundItem(TGIA[i])then
if (TGIA[i].ID) = Players[CurrentPlayer].Arrays[1][D] then
begin
GPoint := TileToMs(TGIA[i].Tile, 0);
MMouse(GPoint.x, GPoint.y, 1, 1);
Wait(500 + Random(500));
if not R_IsUpTextMulti(Players[CurrentPlayer].Strings)then
Exit;
begin
Mouse(GPoint.x, GPoint.y, 0, 0, false);
if R_Invfull then
Exit;
if not R_ChooseOption('Take')then
Exit;
begin
Result := True;
Wait(3000);
Break;
Exit;
end;
end;
end;
end;
end;

Just modify for your needs.

Goobs

2011-07-01 01:30:15

From: masterBB
Copied from reflection 2_1:
(*
R_GetGroundItemsEx
~~~~~~~~~~~~~~~~~~

.. code-block:: pascal

function R_GetGroundItemsEx(IDs: TIntegerArray; MaxDist: Integer): TGroundItemArray;

Retrieves all of the ground items within a circle with a radius of MaxDist that
contain one of the IDs specified. Stores them in a TGroundItemArray.

.. note::

by Drags111

*)
function R_GetGroundItemsEx(IDs: TIntegerArray; MaxDist: Integer): TGroundItemArray;
var
Cache, Hash, Plane, Nodes, Size, Index, Tail, Cur, Next,
UID, List, TheID, Stack: Integer;
H, I, BX, BY, endx, endy: Integer;
Tiles: TTileArray;
begin
SetLength(Result, 0);
BX := SmartGetFieldInt(0, hook_static_BaseX);
BY := SmartGetFieldInt(0, hook_static_BaseY);
EndX := BX + 104;
EndY := BY + 104;

Cache := SmartGetFieldObject(0, hook_static_GroundItemCache);
Nodes := SmartGetFieldObject(cache, hook_nodecache_GetNodes);
SmartFreeObject(Cache);
Plane := SmartGetFieldInt(0, hook_static_LoadedPlane);
Size := SmartGetFieldArraySize(Nodes, '', 1);

Tiles := R_SortedCircleTPA(R_GetMyPos, MaxDist);
H := High(Tiles);

for I := 0 to H do
begin
List := 0;
Hash := Tiles[I].X or (Tiles[I].Y shl 14) or (Plane shl 28);
Index := Hash and (Size - 1);

Tail := SmartGetFieldArrayObject(Nodes, '', Index);
Cur := SmartGetFieldObject(Tail, hook_node_Next);

try
while (not (SmartIsEqual(Tail, Cur))) do
begin
UID := SmartGetFieldLongL(Cur, hook_node_GetID);
if (UID = Hash) then
begin
List := SmartGetFieldObject(Cur, hook_nodelistcache_GetNodeList);
Break;
end;

Next := SmartGetFieldObject(Cur, hook_node_Next);
SmartFreeObject(Cur);
Cur := Next;
end;
finally
SmartFreeObject(Cur);
SmartFreeObject(Tail);
end;

if(List = 0)then
Continue;

Tail := SmartGetFieldObject(list, hook_nodelist_Head);
List := 0;
Cur := SmartGetFieldObject(tail, hook_node_Next);
while (not (SmartIsEqual(tail, cur))) do
begin
TheID := SmartGetFieldInt(Cur, hook_item_GetID);
if InIntArray(IDs, TheID)then
begin
SetArrayLength(Result, GetArrayLength(Result) + 1);
with Result[High(Result)] do
begin
ID := TheID;
Stack := SmartGetFieldInt(Cur, hook_item_GetStack);
Tile.X := Tiles[I].X;
Tile.Y := Tiles[I].Y;
end;
end;
Next := SmartGetFieldObject(Cur, hook_node_Next);
SmartFreeObject(Cur);
Cur := Next;
end;

SmartFreeObject(Cur);
SmartFreeObject(Tail);
SmartFreeObject(List);
end;
SmartFreeObject(Nodes);
end;

This one is much faster, but you will need to adjust it for a square cage, I've made a set up for you. This hasn't been tested so it probally will still contains bugs.

function R_GetGroundItemsEx(IDs: TIntegerArray; SearchBox:Tbox): TGroundItemArray;
var
Cache, Hash, Plane, Nodes, Size, Index, Tail, Cur, Next,
UID, List, TheID, Stack: Integer;
cTileX, cTileY: Integer;
begin
SetLength(Result, 0);

Cache := SmartGetFieldObject(0, hook_static_GroundItemCache);
Nodes := SmartGetFieldObject(cache, hook_nodecache_GetNodes);
SmartFreeObject(Cache);
Plane := SmartGetFieldInt(0, hook_static_LoadedPlane);
Size := SmartGetFieldArraySize(Nodes, '', 1);

for cTileX := SearchBox.X1 to SearchBox.X2 do
for cTileY := SearchBox.Y1 to SearchBox.Y2 do
begin
List := 0;
Hash := cTileX or (cTileY shl 14) or (Plane shl 28);
Index := Hash and (Size - 1);

Tail := SmartGetFieldArrayObject(Nodes, '', Index);
Cur := SmartGetFieldObject(Tail, hook_node_Next);

try
while (not (SmartIsEqual(Tail, Cur))) do
begin
UID := SmartGetFieldLongL(Cur, hook_node_GetID);
if (UID = Hash) then
begin
List := SmartGetFieldObject(Cur, hook_nodelistcache_GetNodeList);
Break;
end;

Next := SmartGetFieldObject(Cur, hook_node_Next);
SmartFreeObject(Cur);
Cur := Next;
end;
finally
SmartFreeObject(Cur);
SmartFreeObject(Tail);
end;

if(List = 0)then
Continue;

Tail := SmartGetFieldObject(list, hook_nodelist_Head);
List := 0;
Cur := SmartGetFieldObject(tail, hook_node_Next);
while (not (SmartIsEqual(tail, cur))) do
begin
TheID := SmartGetFieldInt(Cur, hook_item_GetID);
if InIntArray(IDs, TheID)then
begin
SetArrayLength(Result, GetArrayLength(Result) + 1);
with Result[High(Result)] do
begin
ID := TheID;
Stack := SmartGetFieldInt(Cur, hook_item_GetStack);
Tile.X := cTileX;
Tile.Y := cTileY;
end;
end;
Next := SmartGetFieldObject(Cur, hook_node_Next);
SmartFreeObject(Cur);
Cur := Next;
end;

SmartFreeObject(Cur);
SmartFreeObject(Tail);
SmartFreeObject(List);
end;
SmartFreeObject(Nodes);
end;


Thanks for the info! I will definitely try it out in the morning - we just got power back after 2 hours of DARKNESS.. >.<

From: Flight
If you could get the tile the item is on and then use your TPAFinder to search just with the X/Y box of that tile only, would that not be accurate?


I was thinking of doing that, but I want it to be universal, not necessarily restricted to ID's or certain colors. I was going to try to do GapsTPA on the tile tboxes, comparing it to an autocolor of some sort of the tile, finding the item in the space where there the ground color isn't found. I'm also looking for a faster exp location to do this >.< 8k a hour isn't cuttin it for me, even though it gets some pretty epic drops..

From: Smarter Child
This is from my fighter, works fast enough imo:
Function PickupGroundItems: boolean;
var
TGIA: TGroundItemArray;
I, X, Y, d: Integer;
GPoint: TPoint;
begin
if R_Invfull then
Exit;
TGIA := GetItemsNear(2);
For I := 0 To High(TGIA)do
For D := 0 To High(Players[currentplayer].Arrays[1])do
begin
if FindGroundItem(TGIA[i])then
if (TGIA[i].ID) = Players[CurrentPlayer].Arrays[1][D] then
begin
GPoint := TileToMs(TGIA[i].Tile, 0);
MMouse(GPoint.x, GPoint.y, 1, 1);
Wait(500 + Random(500));
if not R_IsUpTextMulti(Players[CurrentPlayer].Strings)then
Exit;
begin
Mouse(GPoint.x, GPoint.y, 0, 0, false);
if R_Invfull then
Exit;
if not R_ChooseOption('Take')then
Exit;
begin
Result := True;
Wait(3000);
Break;
Exit;
end;
end;
end;
end;
end;

Just modify for your needs.


That's similar to what I wrote, but I didn't have the InvFull check per se ^_^" How fast does your picking go?

Smarter Child

2011-07-01 02:18:25

In terms of finding the ground items that would be the same as normal. But, it is quite fast once the objects are loaded into the array ;)

Goobs

2011-07-01 15:11:51

Would that accurately pick up single arrows which are probably 1-2 pixels wide? That's my main problem xD

EDIT:

I wanted to do some sort of.. spiral search? Or something, from the main point of the tile. It would stop when it hits Uptext.. How did SpiralMouse work? Is there a way for me to have it move a pixel or a two and check for uptext every movement to guarantee accurate pickup?

Smarter Child

2011-07-01 17:18:44

My function picks up steel arrows smoothly.