PDA

View Full Version : RatKiller: A Making of



ReadySteadyGo
01-31-2012, 07:00 AM
RatKiller: A Making of

Over the years that I have been a part of this community, I have learned a great deal from the tutorial section. In fact, I owe this community a lot. I recently made the decision to quit my degree that I have been studying for 2 years and reapply for Computer Science. This community gave me the chance to hone my skills, and gave me confidence that I am suitable for such a course.

I am going to be making a tutorial as a proof of concept of my recently released MMToMS, to show it’s usefulness, but hopefully showing you a few hints and tips along the way.

This was originally intended to be a step by step tutorial, but I got carried away with the script. I personally feel it’s the details which make a script, so I’d like to explain my way of thinking in this ‘Making of’.

I’ve purposely decided to leave things that are generic out in order to focus on the more exciting parts.

OK, let’s jump in.

type
MSObject = record
Col, Tol, TPADist, MinCount: Integer;
Hue, Sat: Extended;
Uptext: TStringArray;
MMDot: String;
end;

var
Rat, Bones: MSObject;
BonesDTM: Integer;


I like to define my variables before anything else. It sets the tone for the rest of the code, means less rewriting later, and it also helps to avoid repeating yourself.

As I had decided that I was going to make a Rat Fighting script that picks up and buries bones, a suitable way to define this data was immediately clear. All the script needs is two Main Screen objects, I knew I was going to use a typical TPA Objectfinding method with some added features. So I created a ‘MSObject’ record with common variables between the two objects and defined global variables ‘Rat’ and ‘Bones’ to have this Type.

I also needed a way to find Bones once they were in the inventory in order to bury them. I chose to use a DTM, since there was only one, but in a larger script would probably look into BlackLists.

I will explain ‘MSObject.MMDot’ further on, but take note that it’s defined here as it’s important.

procedure LoadObjects;
begin
with Rat do
begin
Col := 4408390;
Tol := 10;
TPADist := 10;
Hue := 1.39;
Sat := 0.16;
UpText := ['ack Gian'];
MMDot := 'yellow';
MinCount := 50;
end;

with Bones do
begin
Col := 12501714;
Tol := 19;
TPADist := 5;
Hue := 0.23;
Sat := 0.96;
UpText := ['ones'];
MMDot := 'red';
MinCount := 40;
end;

BonesDTM := DTMFromString('mrAAAAHic42BgYGhlYmBoBuJaIG5kgvD7gb gOyp/EyMAwC4hnAPE0IO4B4qlQuhOIp/T2Ak1hwon/A0l+PJiRAIYBAMm8C/Y=');
end;


This procedure just declares the values of our variables. I used AutoColorAid to calculate appropriate CTS Speed Modifiers.

Now is probably a good time to give an overview of the method I used to find my objects. I will go into further detail after each block of code.

‘MMtoMSTile()’ is found in my include (3DProjection.simba) which is attached at the end of this tutorial. It calculates in 3D the Main Screen tile co-ordinates based on the compass angle. You can input a Mini Map co-ordinate and it will out put the co-ordinate of the tile in the Main Screen.

Another useful function, which is included in the include, is ‘GetMMDotsOnMS2’. This returns a TPointArray of all the tile co-ordinates of a specified Mini Map dot type, i.e. NPC = yellow, Ground Item = red.

We will use the information from these dots to significantly increase the accuracy and efficiency of our Object Finding. The real power of this is that you can use tiny minimum count checks, because by using the minimap, you know the object is there. This means that even if an object is covered by a tree, it will generally find it.

function FindMSObjects(var Coords: TPointArray; Obj: MSObject): Boolean;
var
cts, Len, i, c: Integer;
TPA: TPointArray;
ATPA: TPointArrayArray;
begin
cts := GetColorToleranceSpeed;
ColorToleranceSpeed(2);
SetColorSpeed2Modifiers(Obj.Hue, Obj.Sat);

Result := False;

c:= 0;
if FindColorsTolerance(TPA, Obj.Col, MSX1, MSY1, MSX2, MSY2, Obj.Tol) then
begin
Result := True;
ATPA := SplitTPA(TPA, Obj.TPADist);
Len := Length(ATPA);
SetLength(Coords, Len);
for i := 0 to Len-1 do
begin
if Length(ATPA[i]) > Obj.MinCount then
begin
//SMART_DrawBoxEx(False, GetTPABounds(ATPA[i]), clAqua);
Coords[c] := MiddleTPA(ATPA[i]);
Inc(c);
end;
end;
end;
SetLength(Coords, c)
ColorToleranceSpeed(cts);
SetColorSpeed2Modifiers(0.2, 0.2);
end;


The above is pretty traditional TPA Object finding, it it returning a TPointArray with all the occurrences of an object. It uses the information provided by ACA earlier to do this.

function FindMSObjectsByDot(var Coords: TPointArray; Obj: MSObject): Boolean;
var
BoxArr: TBoxArray;
Len, Len2, i, j, c: Integer;
TPA, TPA2: TPointArray;
begin
TPA := GetMMDotsOnMS2(Obj.MMDot, False);
Len := Length(TPA);
SetLength(BoxArr, Len);

for i := 0 to Len-1 do
BoxArr[i] := MakeBox(TPA[i].x-70, TPA[i].y-70, TPA[i].x+70, TPA[i].y+70);

if FindMSObjects(TPA2, Obj) then
begin

Len2 := Length(TPA2);
SetLength(Coords, Len2);

c := 0;
for i := 0 to Len2-1 do
for j := 0 to Len-1 do
if PointInBox(TPA2[i], BoxArr[j]) then
begin
Coords[c] := TPA2[i];
Inc(c);

Break;
end;
SetLength(Coords, c);
Result := (c > 0);
end;

end;


This is where it differs slightly, it is checking if the colour aproximated Object Points coincide with the 3D projected from Mini Map Co-ords. It does this by creating a box around each projected point and checking if any of the colour points are inside it.

http://i.imgur.com/8Bhn8.png

function InBadBox(p: TPoint): Boolean;
var
i, Len: Integer;
badboxarray: TBoxArray;
begin
Result := False;
BadBoxArray := FindAllHPBars(MSCX, MSCY, MSX1, MSY1, MSX2, MSY2);

Len := Length(badboxarray);
for i := 0 to Len-1 do
if PointInBox(p, MakeBox(BadBoxArray[i].X1, BadBoxArray[i].Y1, BadBoxArray[i].X2, BadBoxArray[i].Y2+60)) then
begin
Result := True;
Break;
end;
end;

function InRatFight: Boolean;
var
aps: Integer;
begin
aps := AveragePixelShift(MakeBox(MSCX-10, MSCY-25, MSCX+15, MSCY+15), 50, 2000);
Result := (aps > 100);
end;

function KillRat: Boolean;
var
TPA: TPointArray;
i, Len, x, y, a, b: Integer;
begin
Result := False;
if FindMSObjectsByDot(TPA, Rat) then
begin
Len := Length(TPA);
SortTPAFrom(TPA, Point(MMCX, MMCY));
for i := 0 to Len-1 do
begin
if inBadBox(TPA[i]) then
Continue;
MMouse(TPA[i].x, TPA[i].y, 3, 3);
if WaitUpTextMulti(Rat.UpText, 300) then
begin
GetMousePos(x, y);
Mouse(x, y, 0, 0, True);
if FindColorTolerance(a, b, 65278 {YellowWalkingCross}, x, y, x+1, y+1, 5) then
begin
WriteLn('MISSED');
Exit;
end;
if GetColor(x, y) = 65278 then
FFlag(2);
Wait(500);
repeat
Antiban;
until (not InRatFight) or (not srl_InFight)
Result := True;
Break;
end;
end;
end;

end;


There are a few details here that aren’t generally talked about in the tutorials I have seen.

‘KillRat’ is a procedure in which we need to use our previously made object finding routine, move the mouse to the object and test for the desired uptext. If this test is positive then we click to attack the rat. We then can perform various antiban routines whilst in the fight.

I realised that the Object Finder would sometimes find a rat that was already in combat, so I created the function InBadBox, which checks if the point is in a ‘Bad box’ which are generated from any HP bars that are on the screen.

I noticed that sometimes, due to the rats moving around pretty rapidly, it would miss. This isn’t much as of a problem, personally when I’m playing legit I sometimes miss too. What is a problem, is that it continues to wait until the player has stopped moving and enters the InFight loop. This look really unatural so I thought about how I could tell immediately whether it had missed the rat or not and avoid this unnecessary delay.

What I ended up doing was a simple check on the mouse co-ordinates for the cross that your cursor makes when clicking somewhere. If you click the object it is red, if you don’t it is yellow. Simple but effective. If the color is yellow, it Exits the procedure and the main loop immediately causes it to look for the next rat.

http://i.imgur.com/6kNL8.png

Another cool thing I used which I haven’t taken advantage of before is SRL’s animation procedures. It was incredibly easy to set up. I just made it do a few WriteLn’s telling me what the average pixel shift was while it was in a fight, and while it was not, giving me the information I needed to do a reliable check. I also used SRL’s ‘srl_InFight’ as a back up, which checks for the players health bar. This would handle anytime I was under a tree.


procedure PickUpBones;
var
TPA: TPointArray;
i, Len, x, y, c: Integer;
begin
for c := 0 to Random(5) + 1 do
if FindMSObjectsByDot(TPA, Bones) then
begin
Len := Length(TPA);
SortTPAFrom(TPA, Point(MMCX, MMCY));
for i := 0 to Len-1 do
begin
MMouse(TPA[i].x, TPA[i].y, 3, 3);
if WaitUpTextMulti(['Take'], 100) then
begin
GetMousePos(x, y);
Mouse(x, y, 0, 0, False);
if WaitOptionMulti(Bones.UpText, 300) then
begin
FFlag(2);
Wait(500);
if i = Len-1 then
Exit;
Break;
end;
end;
end;
end;

end;


This works very similarly to KillRat, taking advantage of the minimap dots.


function WeightedChoice(Weights: TIntegerArray): Integer;
var
i, Len, t, r: Integer;
Totals: TIntegerArray;
begin
Len := Length(Weights);
SetLength(Totals, Len);

t := 0

for i := 0 to Len-1 do
begin
IncEx(t, Weights[i]);
Totals[i] := t;
end;

r := Random(t);
for i := 0 to Len-1 do
if r < Totals[i] then
begin
Result := i;
Break;
end;
end;

procedure MainLoop;
begin
repeat
if KillRat then
begin
SMART_ClearCanvas;
if InvFull then
ClickAllItems('dtm', BonesDTM, '', 400+ random(200), []);
if WeightedChoice([3, 7]) = 0 then
PickUpBones;

end;
SMART_ClearCanvas;
until(not LoggedIn)
end;


Very standard main loop here. One thing I like is the use of ‘WeightedChoice’. It gives you complete control over the probability that something will happen. It’s use would probably be shown better in an anti ban routine. In this script I wanted to mimic myself, I don’t pick up bones after every kill. I tend to pick up quite randomly, but I still prefer the actual killing :)

begin
MouseSpeed := 15;
Smart_Server := 1;
Smart_Members := False;
Smart_Signed := True;
Smart_SuperDetail := False;
SetupSRL;
SMART_ClearCanvas;
LoadObjects;
MainLoop;
end.


Last thing, MouseSpeed is something that you should think about. It completely depends on the task at hand and you should try to thing about what it would be if you were playing legit. For this script I chose a fast MouseSpeed because my targets are mobile.

I have attached the complete script and include to this post. Try it if you like, it is very fast and fun to watch. I may add Multiplayer and AntiBan at some point to release. I haven't decided yet.

And that is it, I hope you enjoyed reading this and you found something that might be useful. Please check out my MMtoMSTile functions as well!

The End.

Kyle Undefined
01-31-2012, 03:48 PM
Very nice tutorial man! Love the MMtoMS tile!

ReadySteadyGo
01-31-2012, 05:34 PM
Thank you Kyle! I was getting worried that my explanations might be badly written :)

Kyle Undefined
01-31-2012, 05:49 PM
Ha, it's simple really :p Don't have a use for it now, but maybe one day I'll use it ;)

NickMystre
02-01-2012, 05:26 AM
Thank you for your time and effort. I really enjoyed working through your tutorial, and matching your explanations to the code.

I think you have a great idea here with "The Making Of" series. I am pretty sure that others will pick up on this as well. Well done!

ReadySteadyGo
02-01-2012, 06:56 PM
Thank you NickMystre and you're very welcome! I hope other people do similar tutorials as well. It's good fun reading peoples methods and ideas.

poopy2177
02-01-2012, 07:58 PM
Wow I really like this tutorial you explain things very well and I like your style to it seems a smidge different than the other tutorials ha

Camaro'
02-04-2012, 04:34 AM
Awesome tutorial man!

ReadySteadyGo
02-10-2012, 02:28 PM
Glad people are enjoying it :)

eska
03-24-2012, 10:10 AM
This is awesome, I need to try this in one of my next script.

Zota
03-24-2012, 04:40 PM
You mind if I use the MMtoMS and related functions in my script(Credits stated)? Really nice idea. The post was very well structured and just as informative. Nice one :)

Luke

Olly
03-25-2012, 01:36 PM
MMtoMS looks sweet :o Great tutorial.

ReadySteadyGo
03-26-2012, 03:47 PM
You mind if I use the MMtoMS and related functions in my script(Credits stated)? Really nice idea. The post was very well structured and just as informative. Nice one :)

Luke

Yes absolutely, please go ahead, I would like to see this used by people.

Glad people are enjoying this tutorial. :)

Zota
03-29-2012, 02:21 PM
hey man.

I had problems with my script. Mainly with it kept trying to attack other peoples monster and for example - It'd kill a monster, and try find drop. But a lot of the time it'd find bones/gold/whatever that wasn't from your monster. So rather than waiting for the drop where the monster died, it'd look at a previous drop pile.

Not sure how to fix that.. I really need to look into how to use Tpoints/array properly.


Luke

alexes
03-29-2012, 04:50 PM
:o This is a very useful tutorial. At the moment I'm learning scripting and this tutorial is really profitable for me as I can see the code and what it does and also get ideas for scripts.

Thank you so much it's really helpful :D

ReadySteadyGo
03-30-2012, 02:21 AM
hey man.

I had problems with my script. Mainly with it kept trying to attack other peoples monster and for example - It'd kill a monster, and try find drop. But a lot of the time it'd find bones/gold/whatever that wasn't from your monster. So rather than waiting for the drop where the monster died, it'd look at a previous drop pile.

Not sure how to fix that.. I really need to look into how to use Tpoints/array properly.


Luke

Hi Luke, I'm not really sure if you're asking a question. Can you ask me what you'd like to know exactly? This tutorial actually deals with the problem of attacking other peoples monsters.



:o This is a very useful tutorial. At the moment I'm learning scripting and this tutorial is really profitable for me as I can see the code and what it does and also get ideas for scripts.

Thank you so much it's really helpful :D

You're very welcome alexes. :)

[D]ude
06-25-2012, 11:28 PM
This is an awesome function to work with. I made a ghoul killer with it. Do you mind if I release it?

ReadySteadyGo
07-12-2012, 10:27 AM
This is an awesome function to work with. I made a ghoul killer with it. Do you mind if I release it?

Of course not, please do! :)

jman1208
07-13-2012, 02:27 AM
Wow this is a great tutorial! Well done, I learned a few things that i may use in the future thanks! I never knew about the yellow and red walking crosses those will definitely become useful!

Ps: Good Luck with your studies

Clarity
03-03-2014, 01:53 PM
Apologies for gravedig but has anybody converted the 3DProjection to SRL-6? I tried to convert it but I don't understand the math well enough to know what I'm doing.

Olly
03-04-2014, 05:14 PM
http://i.imgur.com/iYksftc.png

Hmm

Clarity
03-04-2014, 05:45 PM
http://i.imgur.com/iYksftc.png

Hmm
Man, you're such a tease.