SRL Archive - OSR Help

Need Some Help With A Loop


VastlySuperior

2012-07-08 05:40:42

Hey All

I need some advice. I`m trying to create a loop that looks at two conditions
The First is do I have any soft clay.
The second is after I started crafting How Many Pots is in my inventory

The first loop executes but it fails at the second. Can Anyone look at this and tell me why it will not work and what I can use or do instead to get this loop to function

I have disabled the right Click Option to make it easier to handle the code and follow what is not done. If the first option works correctly the Right click option will be updated with the code.

// Do Pottery Crafting Of Choice
procedure MakePottery(Choice:Integer);
var
x, y, T, PlusOne, PotteryCounter, ClayCounter, LoopCounter: Integer;
Wheel: Boolean;
label
Start;
Begin
Start:
if(not(LoggedIn))then
exit;
ClayCounter := 0;
PotteryCounter := 0;

// Open Inventory to count the amount of clay
ClayCounter := CountInvItems('color', 669001, [4, 50]);
WriteLn('SoftClay In Inventory ' + IntToStr(ClayCounter));

// Setup Pottery For Finding Item To Use
// If Pottery Then Find Wheel
// If Pottery Is made Find Oven
WriteLn('In Pottery Shop');
// Wheel := False;
SetAngle(SRL_ANGLE_HIGH); // Set Camera Angle
MakeCompass('W');
x:=MSCX; // This is the Center Of the Main Screen Where Your Character is standing at the moment
y:=MSCY; // The Search for your object will start from this location outwards in a spiral
WriteLn('Looking For Pottery Wheel');
MakeCompass('W');
If FindObjTPA(x, y, 9079697, 6, 1, 15, 60, 50, ['Pott']) then
Begin
While IsMoving do
Wait(100);
Case random(2) of
0: Begin
WriteLn('Left Clicked Potters Wheel');
GetMousePos(x,y); // Get Mouse Current Position
mouse(x, y, 5, 5, True); // Left Click On Potters Wheel
Wait(2000 + random(400));
End;
1: Begin
WriteLn('Right Clicked Potters Wheel');
GetMousePos(x,y); // Get Mouse Current Position
mouse(x, y, 5, 5, False); // Right Click To Bring Up Options
WaitOption('Form', 500); // Wait A Certain X Amount Of Seconds Before Clicking Option
Wait(2000 + random(400));
End;
End;
End;
// Chooce Option For Which Pottery To Make
// First Get Player Crafting Experience, If not enougth expereince for
// chosen option exit procedure goto Global FailSafe and execute
Case Choice of
// First Case Make a Pot
0: Begin
Case random(1) of
0: Begin // Left Click On Pot To Make
WriteLn('Left Clicked Pot');
ClayCounter := CountInvItems('color', 669001, [4, 50]);
if (CountInvItems('color', 669001, [4, 50]) > 0) then
Begin
mouse(164, 428, 5, 5, True); // Left Click On Potters Wheel
Wait(1000 + random(400));
MarkTime(T);
PotteryCounter := CountInvItems('color', 803419, [3, 50]);
WriteLn('Amount Of pots In Inventorry ' + IntToStr(CountInvItems('color', 803419, [3, 50])));
While (CountInvItems('color', 803419, [3, 50]) < 28) or (TimeFromMark(T) < 15000) do
Wait(1000+Random(500));
WriteLn('Test 1 pottery');
if(TimeFromMark(T) > 15000) then
WriteLn('Test 2 pottery');
if (CountInvItems('color', 803419, [3, 50]) > 1) then
// goto Start;
WriteLn('Goto Banking');
FindNormalRandoms;
Players[CurrentPlayer].Loc:='Potting';
{if (ClayCounter > 0) then
Exit
else}
WriteLn('No More Clay To Craft');
BankFromPottery;
DepositItems;
Exit;
End;
// Start Count for Clay Turned into Pots
End;
1: Begin // Rigt Clicked On Pot
WriteLn('Right Clicked Pot');
mouse(162, 417, 5, 5, False); // Right Click To Bring Up Options
WaitOption('All', 500); // Wait A Certain X Amount Of Seconds Before Clicking Option
Wait(1000 + random(400));
if (ClayCounter > 0) then // If This Condition Is True Do Loop Otherwise Do Next Step
Wait(500 + random(400)) // Check Status Again
else
WriteLn('No More Clay To Craft');
BankFromPottery;
Exit;
End;
End;
End;

// Make Urns
1: Begin

End;

// Make a Pie Dish
2: Begin

End;

// Make a Bowl
3: Begin

End;
End;
ClayCounter := CountInvItems('color', 669001, [4, 50]);
if (ClayCounter > 0) then
Goto Start;
End;


The code executes, it starts making the pots but the loop fail

Thanks All for your input

Daniel

2012-07-08 07:23:22

Uhh, I wouldn't ever attempt to loop with labels, and I'd advise you against from doing so either. Loops without labels were invented for a reason, to avoid jumping through a lot of code.

Please see this tutorial and/or this tutorial for learning loops.

VastlySuperior

2012-07-08 07:32:42

The label is there to test the last condition, to see if there is any clay left in the inventory as then all the pots were not made, so it must go back to the start of the procedure, instead of executing the next procedure.

If there is anything else I can use to go back to the first line of the code in the procedure I`ll be happy to use that instead. The label is basically a failsafe to test this procedure.

Any reason why the second loop should fail loop should fail?

While (CountInvItems('color', 803419, [3, 50]) < 28) or (TimeFromMark(T) < 15000)  do

That is the part where it fails.

@Daniel, Sorry I missed the tutorials you have shown me to read before I made this post. I would still like to know what is wrong with this logic Above where I receive the error. Can you use CountInvItems in such a manner? I have quickly gone through the first tutorial and I have decided to go with the for do loop as I think that will work better. I have also read about calling the same procedure within the same procedure, but doing it in such a manner will create difficulties I think.

riwu

2012-07-08 07:39:34

From: VastlySuperior
The label is there to test the last condition, to see if there is any clay left in the inventory as then all the pots were not made, so it must go back to the start of the procedure, instead of executing the next procedure.

If there is anything else I can use to go back to the first line of the code in the procedure I`ll be happy to use that instead. The label is basically a failsafe to test this procedure.

Any reason why the second loop should fail loop should fail?

While (CountInvItems('color', 803419, [3, 50]) < 28) or (TimeFromMark(T) < 15000)  do

That is the part where it fails.

CountInvItems? where did u find this procedure? Didn't it return a compiling error?
Also (TimeFromMark(T) < 15000) is true the moment u enter the loop, means it wont wait at all, u should do the opposite condition (TimeFromMark(T)>15000)

VastlySuperior

2012-07-08 09:13:49

Thanks riwu for the heads up about the TimeFromMark. Did not see the smaller as sign.

Countinvitems is part of srl, do a search for inventory or find items that is inventory related. The code gives no compiling error otherwise it would never have run in the first place.

The code now runs, but I found that the colors for pots and clay is more or less the same, so it detects the pots as created when it is not and starts the next procedure.

I think I will need to use DTM`s instead of colors to make a count of specific items in the inventory.

CephaXz

2012-07-08 09:22:04

From: riwu
CountInvItems? where did u find this procedure? Didn't it return a compiling error?
Also (TimeFromMark(T) < 15000) is true the moment u enter the loop, means it wont wait at all, u should do the opposite condition (TimeFromMark(T)>15000)


Riwu, actually I see nothing wrong with using <. He's doing a wait if inventory is less than 28 and when its not 15 seconds yet. And it will only wait if its true :p

From: VastlySuperior
I think I will need to use DTM`s instead of colors to make a count of specific items in the inventory.


DTM will do. Maybe you can use

while FindDTM(item, x, y, MIX1, MIY1, MIX2, MIY2) do wait(500);

or

repeat
wait(500);
until not FindDTM(item, x, y, MIX1, MIY1, MIX2, MIY2);

EDIT: Btw, I thought that function was CountItems? Never knew there was a function called CountInvItems.

riwu

2012-07-08 10:07:41

From: CephaXz
Riwu, actually I see nothing wrong with using <. He's doing a wait if inventory is less than 28 and when its not 15 seconds yet. And it will only wait if its true :p



DTM will do. Maybe you can use

while FindDTM(item, x, y, MIX1, MIY1, MIX2, MIY2) do wait(500);

or

repeat
wait(500);
until not FindDTM(item, x, y, MIX1, MIY1, MIX2, MIY2);

EDIT: Btw, I thought that function was CountItems? Never knew there was a function called CountInvItems.

Ops srry thought the wrong way, you are right about the <.

Vast u probably have an extremely outdated version of SRL (or u edited the include?), i cant find CountInvItems at all. Do SRL>Settings>override update, then SRL>Update.

Also u can try WaitColorGone to detect that the last slot has changed color?

Daniel

2012-07-08 11:04:54

Hi VastlySuperior.

From: VastlySuperior
The label is there to test the last condition, to see if there is any clay left in the inventory as then all the pots were not made, so it must go back to the start of the procedure, instead of executing the next procedure.

My apologies. I saw the keyword label there and immediately assumed that is what you were attempting to loop with, and if so, would of been the most likely candidate for your problem(s).

From: VastlySuperior

If there is anything else I can use to go back to the first line of the code in the procedure I`ll be happy to use that instead. The label is basically a failsafe to test this procedure.

Indeed there is. You could simply use a repeat..Until when calling the procedure, like so:

procedure Test;
begin
// Do Things
end;

begin
repeat
Test;
Until(False);
end.
or, you could simply use the repeat..Until statement inside of the procedure. Or, you could use method recursion (see the "Calling a procedure inside the same procedure" section here).

However, the best way would be the first way I demonstrated.

From: VastlySuperior

Any reason why the second loop should fail loop should fail?

While (CountInvItems('color', 803419, [3, 50]) < 28) or (TimeFromMark(T) < 15000)  do

That is the part where it fails.

The reason a loop would fail, or in this case, why a while-loop would fail would be due to either of those returning True. You have two possible culprits:
  • TimeFromMark
  • [indent]Your most likely culprit would be, as others have mentioned, your use of TimeFromMark. You should always try to use a greater than (">") sign when wanting to test if X amount of milliseconds had passed. Besides, the way you have it at the moment, it has the possibility (albeit a minuscule chance) to enter an infinite loop. [/indent]
  • CountInvItems
  • [indent]The only other possible culprit would be your use of CountInvItems, you will need to provide us with this function first in order for us to help you debug it, as it does not currently exist within SRL (or if it is, then please direct us to the include name/location).[/indent]

Good luck and regards,
Daniel. :)

VastlySuperior

2012-07-08 15:45:13

Sorry Guys that I only respond now, I was away the rest of the afternoon and it is quite late here now,so I will be off to bed in a few moments. Here is the code I make reference off. It is under SRL Core in the inventory section.

(*
CountItems
~~~~~~~~~~

.. code-block:: pascal

function CountItems(ItemType: string; Identifier: Integer; tol: TIntegerArray): Integer;

Counts Items in the inventory:

- ItemType: 'dtm', 'bitmap', 'bitmap mask', 'color'
- Item: name/value of your dtm/bmp/color/bmpmask.
- Tol:

* 'dtm' - [] (dtm's can't have tolerance).
* 'bmp' - [BMPTol].
* 'color' - [COLOUR Tol, Colour Count].
* 'bmpmask' - [BMPTol, ContourTol].

.. note::

by WT-Fakawi / Sumilion

Example:

.. code-block:: pascal

numbOfItems := CountItems('dtm', TheDTM, []);

*)
function CountItems(ItemType: string; Identifier: Integer; tol: TIntegerArray): Integer;
begin
GameTab(tab_Inv);
Result := CountItemsIn('inv', ItemType, Identifier, Tol)
end;

Maybe I`m using it in the wrong way, although I don`t think I misunderstand what it is supposed to do. I just don`t know any pascal and neither SRL. I do have a background in VB6, but I think it is a bit more advanced than pascal. But every language has it`s own methods to use to do what You want from it. So it is only a matter of learning the ropes so to speak.

Thanks for your input so far it is of great value to me.

riwu

2012-07-08 17:37:13

From: VastlySuperior
Sorry Guys that I only respond now, I was away the rest of the afternoon and it is quite late here now,so I will be off to bed in a few moments. Here is the code I make reference off. It is under SRL Core in the inventory section.

(*
CountItems
~~~~~~~~~~

.. code-block:: pascal

function CountItems(ItemType: string; Identifier: Integer; tol: TIntegerArray): Integer;

Counts Items in the inventory:

- ItemType: 'dtm', 'bitmap', 'bitmap mask', 'color'
- Item: name/value of your dtm/bmp/color/bmpmask.
- Tol:

* 'dtm' - [] (dtm's can't have tolerance).
* 'bmp' - [BMPTol].
* 'color' - [COLOUR Tol, Colour Count].
* 'bmpmask' - [BMPTol, ContourTol].

.. note::

by WT-Fakawi / Sumilion

Example:

.. code-block:: pascal

numbOfItems := CountItems('dtm', TheDTM, []);

*)
function CountItems(ItemType: string; Identifier: Integer; tol: TIntegerArray): Integer;
begin
GameTab(tab_Inv);
Result := CountItemsIn('inv', ItemType, Identifier, Tol)
end;

Maybe I`m using it in the wrong way, although I don`t think I misunderstand what it is supposed to do. I just don`t know any pascal and neither SRL. I do have a background in VB6, but I think it is a bit more advanced than pascal. But every language has it`s own methods to use to do what You want from it. So it is only a matter of learning the ropes so to speak.

Thanks for your input so far it is of great value to me.

U dont have to copy and paste the function into ur script and edit it. You can simply add {$I SRL/SRL.Simba} at the top, then use it directly in ur script.

What u want to do is to make it wait until all 28 items have been converted, or that 15sec has passed right? If that is the case then ur original TimeFromMark is correct, but CountItems probably didn't work as the start and finished product may have similar color. U can try CountColortolerance just on the last inv slot too, they probably have quite significant difference for a particular color (in terms of the no. of pixel for that color), and u can use InRange to detect if it falls within the range.

VastlySuperior

2012-07-09 01:28:54

I didn`t copy that into my code, I just call it. As you say I already Included it in the beginning.

I just copied it here as there was a request from Daniel to see what function I call. I think personally the quickest and less complicated way would just be to create a dtm for both Items or rather all the items I want to use in the script and declare them as global Variables and just use them wherever I need them. Less code and also less trouble.

Is there any place where I can get pre-made dtm`s or their values for these objects or do I have to create them myself?

Daniel

2012-07-09 09:55:50

Hi VastlySuperior,

The function you have copied is not the same as the one you are calling, unless you have simply renamed it? Please confirm.

I was going to suggest this before, but forgot whilst typing that previous post of mine, but delve into tutorials on coding standards for Pascal programming. As I believe you may possibly be missing a block statement somewhere, if not, irregardless, learning them will still be a major help in debugging in the future.

Regards,
Daniel.