PDA

View Full Version : The Scan and React Method



Obscurity
06-21-2015, 04:46 AM
The Scan and React Method


Introduction

So, I've seen a lot of scripts from different people. These scripts use various different methods. One prominent method I've seen is the standard loop. Let me give you an example:
program woodChopper;

procedure cutTrees;
begin
writeLN('[procedure] cutTrees');
end;

procedure walkToBank;
begin
writeLN('[procedure] walkToBank');
end;

procedure bankLogs;
begin
writeLN('[procedure] bankLogs');
end;

procedure returnToTrees;
begin
writeLN('[procedure] returnToTrees');
end;

begin
repeat
cutTrees;
walkToBank;
bankLogs;
returnToTrees;
until false;
end.
This can work for some situations. However, if anything unexpected happens, it can often break the script. Say, for whatever reason, it fails to bank the logs. It's got to run through 3 other procedures before hopefully fixing the issue.

Scan and React

This is exactly like it sounds. You scan, and then you react accordingly. I can try to explain it, but since most people learn by example:
program fighter;

var
vDropModelID:array of uInt32=[123456,456789,789123];
vMonsterModelID:uInt32=987654321;
vProcedure:procedure();

procedure pAttackMonster;
var
canAttack:countDown;
monsterModels:glModelArray;
begin
repeat
monsterModels:=ogl.getModels(vMonsterModelID).getV isible();
if canAttack.isFinished() and length(monsterModels) then
begin
mouse.rightClickOption(monsterModels.closestTo(ogl .getClientMidPoint())[0],'Attack');
canAttack.setTime(1000);
end;
until combat.hasTarget() or monsterModels.isEmpty();
end;

procedure pLookForMonster;
var
canLook:countDown;
monsterModels:glModelArray;
begin
repeat
monsterModels:=ogl.getModels(vMonsterModelID).getV isible();
if canLook.isFinished() and monsterModels.isEmpty() then
begin
mainScreen.setDegrees(random(360),random(20,50));
canLook.setTime(3000);
end;
until not monsterModels.isEmpty();
end;

procedure pTakeDrop;
var
canTake:countDown;
dropModels:glModelArray;
begin
repeat
dropModels:=ogl.getModels(vDropModelID).getVisible ();
if canTake.isFinished() and length(dropModels.isEmpty()) then
begin
mouse.rightClickOption(dropModels.closestTo(ogl.ge tClientMidPoint())[0],'Take')
canTake.setTime(1000);
end;
until dropModels.isEmpty();
end;

begin
repeat
if length(ogl.getModels(vDropModelID)) then //~ Scan
vProcedure:=@pTakeDrop //~ React
else if length(ogl.getModels(vMonsterModelID)) and (not combat.hasTarget()) then //~ React
vProcedure:=@pAttackMonster //~ React
else if ogl.getModels(vMonsterModelID).isEmpty() then //~ React
vProcedure:=@pLookForMonster //~ React

ogl.callProcedure(@vProcedure);
until false;
end.

That's about it. As I haven't dealt with color, apart from just recently using getColor(), but it's great for OpenGL.

Hope this helps some people!

Citrus
06-21-2015, 05:28 AM
Nice tutorial! I appreciate that it's short and to the point.

I guess I use the 'standard' loop, but I 'scan' on the first line of each procedure so that it exits if the 'scan' doesn't check out.
e.g. my abyss rc mainloop

procedure mainLoop();
begin
bank();
runToMage();
clickThings();
chargePouches();
enterAltar();
craftRunes();
end;

can be started at any point along the way, so it's just a matter of where you want to put those scans.
I'll definitely give this method a shot and see how I like it.

Obscurity
07-09-2015, 08:18 PM
Thanks to Turpinator showing me how to get a procedure name from a pointer, I've edited the original post.

Rather then include a....
writeLN('[procedure] someProcedure')
...in each procedure, you can check if the pointer is nil (and thus doesn't contain a procedure), and if it's not then use...
if @vProcedure<>nil then
begin
writeLN(ogl.getUpTime(),' > someScriptName > ',replaceRegExpr('procedure\(\)\s\("([\w]+)"::0x[A-F0-9]+\)',toStr(@vProcedure),'$1',true));
vProcedure();
end;

12:34:56 > ogLib > pTakeDrop

KeepBotting
07-09-2015, 08:38 PM
This is interesting. My scripts are all traditional loop-based scripts, but individual routines are structured in such a way that if anything goes wrong, looping through the rest of the routines won't be an issue.

Taking your example: say my banking routine fails and my logs aren't banked. Of course, the main loop will proceed to call the following routines (and, in eventuality the preceding ones as well) but they will simply exit once they check the inventory and realize that it is full.

Once the loop goes full circle (which I'd imagine only takes a few milliseconds because all of the routines simply exit), we can try banking again.

How does this compare to the way you've done it in the OP / second post?

E: Just saw Citrus' post. We do the same thing. How does this type of traditional loop compare to what you've done (which to me looks like a variation on a finite-state machine)?

The Mayor
07-09-2015, 09:11 PM
I think the 'standard' loop achieves the same thing if you do it properly, and is much easier for people to understand. I know most/all of the scripts for java bots I've seen use a similar FSM style loop, and I've seen a few scripts here over the years, but I guess it's just up to the scripter what they use.

E: Here is Bumblebeee's tutorial https://villavu.com/forum/showthread.php?t=58300

Kyle
07-09-2015, 09:25 PM
I think the 'standard' loop achieves the same thing if you do it properly, and is much easier for people to understand. I know most/all of the scripts for java bots I've seen use a similar FSM style loop, and I've seen a few scripts here over the years, but I guess it's just up to the scripter what they use.

Agreed, plus IMO this (https://villavu.com/forum/showthread.php?t=58300)is a easier to understand FSM style loop..

The Mayor
07-09-2015, 09:26 PM
Agreed, plus IMO this (https://villavu.com/forum/showthread.php?t=58300)is a easier to understand FSM style loop..

I just edited my post the exact same time as you quoted me :p

KeepBotting
07-09-2015, 09:49 PM
I think the 'standard' loop achieves the same thing if you do it properly, and is much easier for people to understand. I know most/all of the scripts for java bots I've seen use a similar FSM style loop, and I've seen a few scripts here over the years, but I guess it's just up to the scripter what they use.

E: Here is Bumblebeee's tutorial https://villavu.com/forum/showthread.php?t=58300
I agree. Finite-state machines are no doubt a higher-level programming technique, but (at least for the purposes of RS macroing) I don't see a huge advantage over traditional loops.

The Mayor
07-10-2015, 09:57 AM
I also think that if you are going to go down the whole 'states' route, then the state needs to be set within a method that changes the state, and not calculated within one procedure. For example, if you clicked a monster, then you would set the global state to 'attacking', within the attacking procedure. The way this is structured is essentially a 'standard main loop' except instead of calling the procedure directly, you assign it to a pointer, and then call the procedure through that pointer. E.g:


begin
repeat
if length(ogl.getModels(vDropModelID)) then //~ Scan
vProcedure:=@pTakeDrop //~ React
else if length(ogl.getModels(vMonsterModelID)) and (not combat.hasTarget()) then //~ React
vProcedure:=@pAttackMonster //~ React
else if ogl.getModels(vMonsterModelID).isEmpty() then //~ React
vProcedure:=@pLookForMonster //~ React
else
vProcedure:=@pDoNothing; //~ React
if @vProcedure<>nil then
begin
writeLN(ogl.getUpTime(),' > someScriptName > ',replaceRegExpr('procedure\(\)\s\("([\w]+)"::0x[A-F0-9]+\)',toStr(@vProcedure),'$1',true));
vProcedure();
end;
until false;
end.


If you got rid of all the pointers (and the empty procedure) then you could just do this:


begin
repeat
if length(ogl.getModels(vDropModelID)) then
pTakeDrop()
else if length(ogl.getModels(vMonsterModelID)) and (not combat.hasTarget()) then
pAttackMonster()
else if ogl.getModels(vMonsterModelID).isEmpty() then
pLookForMonster();
until false;
end.

Thomas
08-14-2015, 12:38 PM
I liked how hoodz used a 'scan and react method' in his NMZ script found here:
https://villavu.com/forum/showthread.php?t=113041
I just think multiple 'if then else' doesn't look clean, I don't like reading scripts like that either.
But like The Mayor said, it just unneeded code for most part.

Hoodz
08-14-2015, 05:14 PM
I liked how hoodz used a 'scan and react method' in his NMZ script found here:
https://villavu.com/forum/showthread.php?t=113041
I just think multiple 'if then else' doesn't look clean, I don't like reading scripts like that either.
But like The Mayor said, it just unneeded code for most part.

maybe a better example is HoodzFighter, thats more complicated.