Simba Code:
program Universal_Miner_V034;
{$DEFINE SMART}
{$I SRL/OSR.simba}
{$I SRL/utils/slackdebug.simba}
{$I RSWalker/Walker.simba}
{$H-}{$R+}{$X+}
{$DEFINE SMARTDEBUG}
{==============================================================================]
| Universal Miner ™
|
| Steps to use:
| 1. For longer runs you need to declare login details bellow
| 2. Start the script at your mining site, and run setup.
[==============================================================================}
type
EDropStyle = (dsRegular, dsIntense, dsAdaptive);
const
LOGIN_NAME = '';
LOGIN_PASS = '';
RS_WORLD = -1; // preferred world
IS_MEMBER = False; //
SHIFT_DROP = True; // use shift to drop
INTENSE_DROP = dsRegular; // dsIntense, and dsAdaptive = mine some drop some (Often higher XP)
CONFIG_PATH = IncludePath+'Universal_Miner/';
CONFIG_FILE = 'config.cfg';
CONFIG_MAP = 'map.png';
INTENSITY_LEVEL = 88;
CHANCE_OF_MISS = 1;
type
TClickHistory = record
Data: TRectArray;
end;
TStatistics = record
Trips: Int32;
StartInfo: TSkillInfo;
CurrLvl: Int32;
Count: Int32;
PrcToNextLvl: Int32;
Gains,Rem,CurrXP:Double;
XPPerOre: Int32;
DismissedRandoms: Int32;
Isset_XPPerOre: Boolean;
end;
TMiner = record
PlayerBox: TBox;
ConfigPath: String;
StartTime: Int64;
QuickDeposit: Boolean;
BotStats: TStatistics;
StatsDebugTick: Int64;
RockSpots, BankSpots: TPointArray;
RockColors, BankColors: array of TCTS2Color;
BankPath: TPointArray;
ClickOrder: TClickHistory;
ProggyArea: TBox;
FailCount: Int32;
Antiban: TAntiban;
end;
var
Bot: TMiner;
RSW: TRSWalker;
NativeClient: Int32;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// WIN API stuff
const WINAPI_CC = {$IFDEF CPU386}' stdcall'{$ELSE}' win64'{$ENDIF};
const ffi_winapi = {$IFDEF CPU386}ffi_stdcall{$ELSE}ffi_win64{$ENDIF};
type
_EnumWindowsProc = function(wnd:DWORD; Param:Pointer): LongBool;
TEnumWindowsProc = native(_EnumWindowsProc, ffi_winapi);
function GetAsyncKeyState(vKey: Int32): Int16; external 'GetAsyncKeyState@user32.dll' + WINAPI_CC;
function GetForegroundWindow(): PtrUInt; external 'GetForegroundWindow@user32.dll' + WINAPI_CC;
function GetWindowThreadProcessId(wnd: PtrUInt; out dwProcessId: DWORD): DWORD; external 'GetWindowThreadProcessId@user32.dll' + WINAPI_CC;
function EnumChildWindows(hWndParent: DWORD; func: TEnumWindowsProc; Param: Pointer): LongBool; external 'EnumChildWindows@user32.dll' + WINAPI_CC;
function GetClientRect(wnd: DWORD; out Rect: TBox): Boolean; external 'GetClientRect@user32.dll' + WINAPI_CC;
function GetKeyDown(): Char;
var
key: Word;
keys: array of Word;
begin
keys := [VK_A..VK_Z];
keys += [VK_0..VK_9];
keys += [VK_OEM_PERIOD, VK_OEM_MINUS];
for Key in keys do
if GetAsyncKeyState(key) and $8000 <> 0 then
begin
while GetAsyncKeyState(key) and $8000 <> 0 do Wait(10);
if key = VK_OEM_PERIOD then key := Ord('.');
if key = VK_OEM_MINUS then key := Ord('-');
Exit(Char(key));
end;
end;
function IsKeyDown2(vKey: Word): Boolean;
begin
Result := GetAsyncKeyState(vKey) and $8000 <> 0;
end;
function HasFocus(PID: PtrUInt): Boolean;
var tmp: DWORD;
begin
GetWindowThreadProcessId(GetForegroundWindow(), tmp);
Result := tmp = PID;
end;
function GetRSAppletWnd(PID: DWORD): DWORD;
function GetNativeClient(Handle: DWORD; Param: Pointer): LongBool; static;
var B: TBox;
begin
GetClientRect(handle, B);
if (B.Width = 765+1) and (B.Height = 503+1) then
DWORD(Param^) := handle;
Result := True;
end;
var
p: TSysProc;
client: DWORD;
begin
for p in GetProcesses() do
if p.Pid = PID then
Break;
EnumChildWindows(p.Handle, @GetNativeClient, @Result);
if Result = 0 then Result := NativeClient;
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// UTILITY FUNCTIONS
function StrToTPA(s:String): TPointArray;
var
i: Int32;
Arr: TExtArray;
begin
Arr := s.ExtractNumbers();
SetLength(Result, Length(Arr) div 2);
for i:=0 to High(Result) do
begin
Result[i].x := Trunc(Arr[i*2]);
Result[i].y := Trunc(Arr[i*2+1]);
end;
end;
function StrToCTS2(s:String): array of TCTS2Color;
var
i: Int32;
Arr: TExtArray;
begin
Arr := s.ExtractNumbers();
SetLength(Result, Length(Arr) div 4);
for i:=0 to High(Result) do
begin
Result[i].Color := Trunc(Arr[i*4]);
Result[i].Tolerance := Trunc(Arr[i*4+1]);
Result[i].HueMod := Arr[i*4+2];
Result[i].SatMod := Arr[i*4+3];
end;
end;
procedure TMouse.Move(P: TPoint); override;
var
dist: Double;
q: TPoint;
maxSpeed := Random(20,22);
minSpeed := Random(4,6);
begin
q := Self.GetPosition;
dist := Hypot(q.x-p.x, q.y-p.y);
self.Speed := Trunc(minSpeed + (maxSpeed-minSpeed) * Power(dist / 1000, 1/2));
inherited;
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// MISC BOT FUNCTIONS
function WorldToMSTile(Me, ObjLoc: TPoint; Height:Double=0; Offx,Offy:Double=0): TRectangle;
var
Angle: Double;
begin
ObjLoc := Point(MM2MS.MMCX, MM2MS.MMCY) + (ObjLoc - Me);
Angle := Minimap.GetCompassAngle(False);
ObjLoc := ObjLoc.Rotate(Angle, Point(MM2MS.MMCX, MM2MS.MMCY));
Result := Minimap.VecToMSRect(Vec3(ObjLoc.x - offx, ObjLoc.y - offy, Height), Angle);
end;
procedure TClickHistory.Push(x: TRectangle);
begin
Insert(x, Self.Data, 0);
end;
function TClickHistory.Pop(): TRectangle;
begin
if Length(Self.Data) < Length(Bot.RockSpots) then
Exit(Self.Data[High(Self.Data)]);
Result := Self.Data[High(Self.Data)];
SetLength(Self.Data, High(Self.Data));
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// OVERRIDES AND METHODS FOR FATIGUE
procedure WaitFatigue(t: Double; Exp: Double=0.2);
begin
System.Wait(Trunc(2*t * (1-Power(System.Max(0.0001, Bot.Antiban.EnergyLevel/100),Exp))));
end;
procedure Wait(min, max:Double; weight:EWaitDir=wdMean); override;
var t:Double;
begin
t := PerformanceTimer();
inherited(min, max, weight);
WaitFatigue(PerformanceTimer()-t,0.2);
end;
procedure WaitEx(mean, dev:Double); override;
var t:Double;
begin
t := PerformanceTimer();
inherited(mean, dev);
WaitFatigue(PerformanceTimer()-t, 0.2);
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// MINER
function TMiner.GetTimeRunning(): Int64;
begin
if Self.StartTime = 0 then Exit(0);
Result := GetTickCount() - Self.StartTime;
end;
procedure TMiner.DeclarePlayers();
begin
with Players.New()^ do
begin
LoginName := LOGIN_NAME;
Password := LOGIN_PASS;
IsActive := True;
IsMember := IS_MEMBER;
World := RS_WORLD;
end;
Players.SetCurrent(0);
end;
procedure TMiner.SetupAntiban();
begin
Antiban.Init(SKILL_MINING);
Antiban.AddTask([@Antiban.LoseFocus, ONE_MINUTE*7, 0.15]);
Antiban.AddTask([@Antiban.HoverPlayers, ONE_MINUTE*9, 0.15]);
Antiban.AddTask([@Antiban.CheckSkill, ONE_MINUTE*13, 0.15]);
Antiban.AddTask([@Antiban.CheckStats, ONE_MINUTE*18, 0.15]);
Antiban.AddTask([@Antiban.OpenRandomTab, ONE_MINUTE*20, 0.15]);
Antiban.AddTask([@Antiban.RandomCompass, ONE_MINUTE*40, 0.15]);
Antiban.AddTask([@Antiban.DoMiscStuff, ONE_MINUTE*45, 0.15]);
Antiban.AddTask([@Antiban.VeryShortBreak,ONE_MINUTE*50, 0.15]);
Antiban.AddBreak([1.0 * ONE_HOUR, 05 * ONE_MINUTE, 0.33, 0.25]);
Antiban.AddBreak([3.5 * ONE_HOUR, 40 * ONE_MINUTE, 0.85, 0.15]);
Antiban.AddBreak([17 * ONE_HOUR, 07 * ONE_HOUR, 0.95, 0.10]);
end;
function TMiner.HasBanking(): Boolean;
begin
Result := (Self.BankColors <> []) and (Self.BankPath <> []) and (Self.BankSpots <> []);
end;
procedure TMiner.DoAntiban();
begin
if Self.Antiban.DoAntiban() then
Players.GetCurrent()^.Login(); // if we got logged out
end;
procedure TMiner.PostAction(CheckAntiban: Boolean = True);
begin
WaitEx(500,70);
if CheckAntiban then Self.DoAntiban;
end;
procedure TMiner.ProcessWhileWaiting();
var
n,atNextLvl,atCurrLvl:Int32;
begin
BotStats.Gains := BotStats.Count * BotStats.XPPerOre;
BotStats.CurrXP := BotStats.StartInfo.XP + BotStats.Gains;
BotStats.CurrLvl := srl.GetLevelAtXP(Ceil(BotStats.CurrXP));
atNextLvl := srl.GetXPAtLevel(BotStats.CurrLvl+1);
atCurrLvl := srl.GetXPAtLevel(BotStats.CurrLvl);
BotStats.Rem := atNextLvl - BotStats.CurrXP;
BotStats.PrcToNextLvl := 100 - Round((BotStats.Rem / (atNextLvl - atCurrLvl)) * 100);
if GetTickCount() - StatsDebugTick > 2000 then
begin
ClearDebug();
WriteLn('+---| STATS |----------------------------------------');
WriteLn('|- Trips / Drops : ', BotStats.Trips);
WriteLn('|- Ores Mined : ', BotStats.Count);
WriteLn('|- Experience Gained : ', BotStats.Gains);
WriteLn('|- Experience Per Hour : ', Round(BotStats.Gains / (GetTimeRunning()/1000/60/60)) );
WriteLn('|- Dismissed Randoms : ', BotStats.DismissedRandoms);
WriteLn('|- Time Since Break : ', SRL.MsToTime(Self.Antiban.TimeSinceBreak, Time_Short));
WriteLn('|- Energy Level : ', Self.Antiban.EnergyLevel);
WriteLn('|- Script Runtime : ', SRL.MsToTime(GetTimeRunning, Time_Short));
WriteLn('+----------------------------------------------------');
{$IFDEF SMARTDEBUG}
ProggyArea := Smart.Image.DrawSkillReport([288,2], clProgBrown, Trunc(BotStats.CurrXP), Trunc(BotStats.Gains), BotStats.Count, 'Mining');
{$ENDIF}
StatsDebugTick := GetTickCount();
end;
Self.DoAntiban;
end;
function TMiner.Contains(R: TRectangle; Colors: array of TCTS2Color): Boolean;
var
TPA: TPointArray;
i, count: Int32;
begin
for i:=0 to High(Colors) do
begin
count += srl.FindColors(TPA, Colors[i], R.Bounds);
if count > 150 then //XXXXXXXXXXXX
Exit(True);
end;
end;
function TMiner.Find(Locations: TPointArray): TRectArray;
var
i: Int32;
me: TPoint;
rect: TRectangle;
begin
me := RSW.GetMyPos();
for i:=0 to High(Locations) do
begin
rect := WorldToMSTile(me, Locations[i], 0,0,0).Expand(-2);
if MainScreen.GetBounds.Contains(rect.Bounds) then
Result += rect;
end;
if (Length(Result) = 0) then
begin
if (Self.FailCount in [2,6]) then
Minimap.RandomCompass(0,359)
else if (Self.FailCount = 7) then
begin
WriteLn('Trying to recover from failure');
Logout.ClickLogout();
Wait(1000,30000,wdLeft);
Players.GetCurrent^.Login();
MainScreen.SetAngle(True);
WaitEx(500,150);
end else if (Self.FailCount > 10) then
TerminateScript('Not close enough to objects: ('+ ToStr(me.x) +','+ToStr(me.y)+') -> '+ ToStr(locations));
Inc(Self.FailCount);
WaitEx(600,150);
end else
Self.FailCount := 0;
end;
function TMiner.DoWork(): Boolean;
var
i: Int32;
T: TCountDown;
TRA: TRectArray;
next: TRectangle;
tmpCurrXP, invCount: Int32;
function MaybeMiss(): Boolean;
var
R: TRectangle;
begin
Result := True;
if Random()*100 <= CHANCE_OF_MISS then
begin
R := Minimap.PointToMsRect(Point(MM2MS.MMCX+Random(-6,6), MM2MS.MMCY+Random(-6,6)));
Mouse.Move(R, True);
WaitEx(65,10);
if MainScreen.IsUpText(['Walk here', 'Mine', 'Rocks']) then
Exit();
Result := False;
end;
end;
function ClickRock(rect: TRectangle): Int8;
begin
mouse.Move(rect, Random(10) = 0);
WaitEx(65,10);
if not Mainscreen.IsUpText(['Mine', 'Rocks']) then
Exit(1);
if (not MaybeMiss()) then
Exit(0);
if (not ((Random() <= 0.05) and ChooseOption.Select('Mine Rocks'))) and
(not Mouse.Click(ctRed)) then
begin
Wait(400,7000,wdLeft);
Self.DoAntiban;
WaitFatigue(Random(1500,3000), 0.6);
Exit(0);
end;
ClickOrder.Push(TRA[i]);
for 6 to Round(srl.TruncatedGauss(0,12)) do
begin
Mouse.Click(mouse_Left);
WaitEx(65,10);
end;
WaitEx(300,60);
Result := 2;
end;
begin
invCount := Inventory.Count;
TRA := Find(self.RockSpots);
if (Self.BotStats.StartInfo = []) and (Self.BotStats.XPPerOre = 0) then
begin
Self.BotStats.StartInfo := Stats.GetSkillInfo(SKILL_MINING);
Self.BotStats.XPPerOre := BotStats.StartInfo.XP;
end;
for i:=0 to High(TRA) do
begin
if not Contains(TRA[i], Self.RockColors) then
Continue;
WaitFatigue(Random(700,1200), 0.1);
case ClickRock(TRA[i]) of
0: Exit;
1: Continue;
2: Minimap.WaitPlayerMoving(False);
end;
next := ClickOrder.Pop();
if (Self.Antiban.EnergyLevel > 40) or (Random() < 0.05) then
begin
if(Random() > 0.05) then
Mouse.Move(next, Random() < 0.1)
else if(Random() < 0.05) then
begin
Mouse.Move(srl.DefaultClientBounds, True, rndRandom);
WaitFatigue(5000, 0.6);
end;
end;
TRA := Find(self.RockSpots); // update the TRA in case we moved
T.Init(srl.NormalRange(20000,25000)); //XXXXXXXXXXXX
while (not T.IsFinished) and Contains(TRA[i], Self.RockColors) do
begin
if(Chatbox.GotLevelUp()) then
if(Random(9) = 0) then
Chatbox.HandleLevelUp()
else
Break;
if 'inventory is too full' in Chatbox.GetNotification() then
Break;
Self.ProcessWhileWaiting();
Wait(30);
end;
if (Inventory.Count > invCount) then
begin
Inc(Self.BotStats.Count);
if (not Self.BotStats.Isset_XPPerOre) then //XXXXXXXXXXXX
begin
Self.BotStats.XPPerOre := Stats.GetSkillInfo(SKILL_MINING).XP - Self.BotStats.XPPerOre;
Self.BotStats.Isset_XPPerOre := Self.BotStats.XPPerOre > 0;
end;
end;
Exit(True);
end;
end;
procedure TMiner.DoBanking();
function OpenBank(): Boolean;
var Rect: TRectangle;
begin
for 0 to 3 do
begin
for Rect in Find(self.BankSpots) do
if Contains(Rect, Self.BankColors) and BankScreen.OpenAt(srl.RandomPoint(Rect.Mean, Trunc(Rect.Radius))) then
Exit(True);
Wait(800,1300);
end;
end;
function BankInventory(): Boolean;
var
slots: TIntArray;
t: TCountDown;
begin
if Self.QuickDeposit then
Exit(BankScreen.DepositAll);
slots := Inventory.GetUsedSlots();
slots.Remove(0); //reserved
while Length(slots) > 0 do
begin
Inventory.MouseSlot(slots[0]);
ChooseOption.Select('Deposit-All');
t.Init(2000);
while Inventory.IsSlotUsed(slots[0]) and (not t.IsFinished) do WaitEx(90,10);
slots := Inventory.GetUsedSlots();
slots.Remove(0);
end;
Wait(1, 1200, wdLeft);
Result := not Inventory.IsFull();
if Inventory.Count = 0 then
Self.QuickDeposit := True;
end;
function Walk(path: TPointArray): Boolean;
begin
for 0 to 2 do
if RSW.WalkPath(Path) then
Exit(True)
else
Wait(800, 3200, wdRight);
end;
begin
if(not Walk(self.BankPath)) then
TerminateScript('Failed to walk path [1]');
Self.DoAntiban;
if(not OpenBank()) then
TerminateScript('Failed to open bank');
PostAction(False);
if(not BankInventory()) then
TerminateScript('Failed to deposit items');
PostAction;
if(not Walk(self.BankPath.Reversed)) then
TerminateScript('Failed to walk path [2]');
Self.DoAntiban;
end;
procedure TMiner.IntenseDrop(Test: function: Boolean of Object);
var
p: TPoint;
Slots: TIntArray;
n: Int32 = 3;
begin
if Test() then Exit;
if Random(5) = 0 then
n := Random(2,4);
p := Mouse.GetPosition();
Slots := Inventory.GetUsedSlots();
if (Length(Slots) >= 3)then
begin
if(not Self.QuickDeposit) then Slots.Remove(0);
SetLength(Slots, Min(Length(Slots), n));
Inventory.DropItems(Inventory.ErrorPattern(Slots,2));
Mouse.Move(p,20);
end;
end;
procedure TMiner.DropInventory();
begin
if Self.QuickDeposit then
Inventory.DropItems(Inventory.ErrorPattern(DROP_PATTERN_SNAKE))
else
Inventory.DropItemsExcept([0], Inventory.ErrorPattern(DROP_PATTERN_SNAKE));
end;
procedure TMiner.Run();
var
loc: TPoint;
procedure TryDropWhileMining();
begin
if (not HasBanking) and (INTENSE_DROP in [dsIntense,dsAdaptive]) then
begin
if (INTENSE_DROP = dsIntense) then
Self.IntenseDrop(@Self.DoWork)
else if (INTENSE_DROP = dsAdaptive) and (Self.Antiban.EnergyLevel > INTENSITY_LEVEL) then
Self.IntenseDrop(@Self.DoWork);
end;
end;
begin
Self.StartTime := GetTickCount();
Self.SetupAntiban();
MainScreen.SetAngle(True);
if Inventory.Count = 0 then
Self.QuickDeposit := True;
if Self.HasBanking() then
begin
loc := RSW.GetMyPos();
if (Distance(loc, self.BankPath[high(self.BankPath)]) < Distance(loc, self.BankPath[0])) and
(not RSW.WalkPath(self.BankPath.Reversed)) then
TerminateScript('Failed to walk from bank on startup');
end;
repeat
if (Random(5000) <> 0) and Inventory.IsFull() then
begin
if HasBanking then Self.DoBanking()
else Self.DropInventory();
Inc(BotStats.Trips);
end;
if Self.DoWork() then
begin
TryDropWhileMining();
Self.DoAntiban;
end else
Players.GetCurrent()^.Login();
Wait(1);
until False;
end;
procedure TMiner.Init();
var
W, H: Integer;
begin
GetClientDimensions(W, H);
self.PlayerBox := Minimap.VecToMsRect(Vec3(MM2MS.MMCX,MM2MS.MMCY,2)).Expand(7).Bounds;
self.DeclarePlayers();
Mouse.Speed := 10;
Players.GetCurrent()^.Login();
Inventory.ShiftDrop := SHIFT_DROP;
end;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Crazy config generation
procedure TMiner.Setup();
var
r: String;
DefaultBox: TBox = [75,40, 425,140];
client2: TClient;
type
TButtonBox = record
TextTPA: TPointArray;
Bounds: TBox;
end;
function SlowMSToMM(MS: TPoint): TPoint;
var
x,y: Int32;
best,test: TPoint;
begin
for x:=MM2MS.MMCX-52 to MM2MS.MMCX+52 do
for y:=MM2MS.MMCY-52 to MM2MS.MMCY+52 do
begin
test := Minimap.PointToMs([x,y],0);
if Distance(test, MS) < Distance(best, MS) then
begin
best := test;
Result := Point(x,y);
end;
end;
end;
procedure WaitReleaseKey();
begin
while client2.GetIOManager.IsMouseButtonDown(0) do Wait(10);
end;
function GetClick(out p: TPoint): Boolean;
begin
if not HasFocus(smart.PID) then Exit();
if client2.GetIOManager.IsMouseButtonDown(0) then
begin
client2.GetIOManager.GetMousePos(p.x,p.y);
Result := p.InBox(GetClientBounds);
WaitReleaseKey();
end;
end;
function GetButton(txt: String): TButtonBox;
begin
Result.TextTPA := TPAFromText(txt, StatChars07);
Result.Bounds := GetTPABounds(Result.TextTPA).ExpandFunc(8);
end;
function DrawButton(p: TPoint; var Button: TButtonBox): TButtonBox;
begin
Button.TextTPA.Offset(p);
Button.Bounds.Offset(p);
smart.Image.DrawBox(Button.Bounds, True, 2502198);
smart.Image.DrawBox(Button.Bounds.ExpandFunc(-1), True, 4607315);
smart.Image.DrawTPA(Button.TextTPA, $FFFFFF);
end;
function MessageBox(Text: String; Area:TBox=[]): string;
var
xstart: Int32;
TPA: TPointArray;
box: TBox;
begin
if (Area.x1 = Area.x2) then Area := chatbox.GetBounds;
smart.Image.DrawBox(Area.ExpandFunc(-0), False, $1F2F33);
smart.Image.DrawBox(Area.ExpandFunc(-1), False, $3F4A5A);
smart.Image.DrawBox(Area.ExpandFunc(-2), False, $1F2F33);
smart.Image.DrawBox(Area.ExpandFunc(-3), True, $171D20);
TPA := TPAFromText(Text, SmallChars07);
box := GetTPABounds(TPA);
xstart := (box.Width + Area.Width) div 2 - box.Width;
OffsetTPA(TPA, Point(Area.x1+xstart, Area.y1+20));
smart.Image.DrawTPA(TPA, $FFFFFF);
end;
function Query(Text: String; Alts:TStringArray; Area:TBox=[]): string;
var
i,xstart,CurrWidth: Int32;
p: TPoint;
Buttons: array of TButtonBox;
xOffset: TIntArray;
begin
if (Area.x1 = Area.x2) then Area := chatbox.GetBounds;
// query
MessageBox(Text, Area);
// buttons
for i:=0 to High(Alts) do
begin
Buttons += GetButton(Alts[i]);
xOffset += CurrWidth;
CurrWidth += Buttons[i].Bounds.X2+20;
end;
CurrWidth -= 20;
xstart := (CurrWidth + Area.Width) div 2 - CurrWidth;
for i:=0 to High(Buttons) do
DrawButton(Point(Area.x1+xstart+xOffset[i], Area.y1+50), Buttons[i]);
// handling
while True do
begin
if GetClick(p) then
for i:=0 to High(Buttons) do
if PointInBox(p, Buttons[i].Bounds) then
begin
smart.Image.DrawBox(Area, True, 0);
Exit(Alts[i]);
end;
Wait(1);
end;
end;
function QueryStr(Text: String; Area:TBox=[]): string;
var
i: Int32;
pt, p: TPoint;
chr: Char;
B: TBox;
TPA: TPointArray;
Button: TButtonBox;
begin
if (Area.x1 = Area.x2) then
Area := chatbox.GetBounds;
// query
smart.Image.DrawBox(Area.ExpandFunc(-0), False, $1F2F33);
smart.Image.DrawBox(Area.ExpandFunc(-1), False, $3F4A5A);
smart.Image.DrawBox(Area.ExpandFunc(-2), False, $1F2F33);
smart.Image.DrawBox(Area.ExpandFunc(-3), True, $171D20);
TPA := TPAFromText(Text, SmallChars07);
OffsetTPA(TPA, Point(Area.x1+40, Area.y1+20));
smart.Image.DrawTPA(TPA, $FFFFFF);
B := GetTPABounds(TPA);
// button
Button := GetButton('OK');
DrawButton(Point(Area.x1+48, Area.y1+50), Button);
// handling
pt.x := B.x2+5;
pt.y := Area.y1+20;
repeat
while not HasFocus(smart.PID) do Wait(10);
if GetClick(p) then
if PointInBox(p, Button.Bounds) then
begin
smart.Image.DrawBox(Area, True, 0);
Exit(Result);
end;
chr := GetKeyDown();
if chr <> #0 then
begin
Result += Lowercase(chr);
Keyboard.PressKey(VK_BACK);
smart.Image.DrawText(Result,'SmallChars07', pt, False, $FFCCAA);
end;
if IsKeyDown2(VK_BACK) and (Result <> '') then
begin
TPA := TPAFromText(Result, 'SmallChars07');
TPA.Offset(pt);
smart.Image.DrawBox(GetTPABounds(TPA), True, $171D20);
while IsKeyDown2(VK_BACK) do Wait(50);
SetLength(Result, Length(Result)-1);
smart.Image.DrawText(Result, 'SmallChars07', pt, False, $FFCCAA);
end;
until False;
end;
function SetupLocations(): TPointArray;
var
p, me, worldPt: TPoint;
rect: TRectangle;
begin
me := RSW.GetMyPos();
while True do
begin
if GetClick(p) then
begin
worldPt := (SlowMSToMM(p) - Point(MM2MS.MMCX, MM2MS.MMCY)) + me;
rect := WorldToMSTile(me, worldPt);
if Mainscreen.GetBounds.Contains(rect.Bounds) then
begin
smart.Image.DrawTPA(rect.ToTPA.Connect, $FFFF);
case Query('Are you happy?', ['Add more', 'Retry', 'Yes']) of
'Retry': smart.Image.DrawTPA(rect.ToTPA.Connect, 0);
'Add more': Result += worldPt;
'Yes': begin Result += worldPt; Break; end;
end;
end;
end;
Wait(1);
end;
smart.Image.Clear();
end;
function SetupColors(Locations: TPointArray): array of TCTS2Color;
var
i: Int32;
p,me: TPoint;
IsValid: Boolean;
R: array of TRectangle;
Color: TCTS2Color;
TPA: TPointArray;
function MarkColors(Colors: array of TCTS2Color): TPointArray;
var
i,j: Int32;
TPA: TPointArray;
begin
for i:=0 to High(Colors) do
for j:=0 to High(R) do
if srl.FindColors(TPA, Colors[i], R[j].Bounds.ExpandFunc(-1)) then
begin
TPA := R[j].Filter(TPA);
smart.Image.DrawTPA(TPA, $FF);
Result += TPA;
end;
end;
begin
me := RSW.GetMyPos();
SetLength(R, Length(Locations));
for i:=0 to High(Locations) do
begin
R[i] := WorldToMSTile(Me, Locations[i]);
smart.Image.DrawTPA(R[i].ToTPA.Connect, $00FF00);
end;
while True do
begin
if GetClick(p) then
begin
Color := CTS2(GetColor(p), 13);
for i:=0 to High(R) do
if R[i].Contains(p) then
begin
IsValid := True;
break;
end;
if(not IsValid) then
continue;
TPA := MarkColors(Result + Color);
case Query('Are you happy?', ['Add more', 'Retry', 'Reset', 'Yes']) of
'Retry': smart.Image.DrawTPA(TPA, 0);
'Add more': Result += Color;
'Yes': begin Result += Color; Break; end;
'Reset': begin smart.Image.DrawTPA(TPA, 0); Result := []; end;
end;
end;
Wait(1);
end;
smart.Image.Clear();
end;
function RecordPath(): TPointArray;
var
worldPt,p: TPoint;
t: UInt64;
begin
t := GetTickCount()+8000;
while True do
begin
if GetClick(p) then
begin
t := GetTickCount()+2500;
worldPt := RSW.GetMyPos();
Mouse.Click(p, mouse_Left);
Result += worldPt;
end;
if (GetTickCount() > t) and (not Minimap.isPlayerMoving()) then
case Query('Are we there yet?', ['No', 'Yes']) of
'Yes': Exit(Result+RSW.GetMyPos());
'No' : t := GetTickCount()+2500;
end;
Wait(1);
end;
end;
procedure GenerateMap(MapPath:String; Pad:Int32=160);
var
pt,sz: TPoint;
map,slice: TMufasaBitmap;
TPA: TPointArray;
B: TBox;
begin
TPA := Self.BankPath + Self.RockSpots + Self.BankSpots;
sz := Point(High(RSW.WorldMap[0]),High(RSW.WorldMap));
B := TPA.Bounds.ExpandFunc(Pad);
B.LimitTo(Box(0,0,sz.x,sz.y));
map.Init(client.GetMBitmaps);
map.SetSize(B.Width, B.Height);
for pt in TPA do
begin
slice.Init(client.GetMBitmaps);
slice.DrawMatrix(RSW.WorldMap.Crop(Box(
Max(0,pt.x-Pad),
Max(0,pt.y-Pad),
Min(sz.x,pt.x+Pad),
Min(sz.y,pt.y+Pad)
)));
slice.DrawTransparent(pt.x-B.x1-Pad,pt.y-B.y1-Pad, map);
slice.Free();
end;
map.SaveToFile(MapPath);
map.Free();
Self.BankPath.Offset ([-B.x1,-B.y1]);
Self.RockSpots.Offset([-B.x1,-B.y1]);
Self.BankSpots.Offset([-B.x1,-B.y1]);
end;
function LoadConfig(): Boolean;
begin
if not FileExists(ConfigPath+CONFIG_FILE) then
Exit(False);
BankPath := StrToTPA (ReadINI('settings', 'BankPath', ConfigPath+CONFIG_FILE));
RockSpots := StrToTPA (ReadINI('settings', 'RockSpots', ConfigPath+CONFIG_FILE));
RockColors := StrToCTS2(ReadINI('settings', 'RockColors', ConfigPath+CONFIG_FILE));
BankSpots := StrToTPA (ReadINI('settings', 'BankSpots', ConfigPath+CONFIG_FILE));
BankColors := StrToCTS2(ReadINI('settings', 'BankColors', ConfigPath+CONFIG_FILE));
Result := True;
end;
procedure SaveConfig();
var
f: PtrInt;
begin
CreateDirectory(CONFIG_PATH);
CreateDirectory(ConfigPath);
GenerateMap(ConfigPath+CONFIG_MAP);
CloseFile(CreateFile(ConfigPath+CONFIG_FILE));
f := RewriteFile(Self.ConfigPath+CONFIG_FILE, True);
WriteFileString(f, '[settings]' + #13#10);
WriteFileString(f, 'BankPath = '+ToStr(BankPath) + #13#10);
WriteFileString(f, 'RockSpots = '+ToStr(RockSpots) + #13#10);
WriteFileString(f, 'RockColors = '+ToStr(RockColors)+ #13#10);
WriteFileString(f, 'BankSpots = '+ToStr(BankSpots) + #13#10);
WriteFileString(f, 'BankColors = '+ToStr(BankColors)+ #13#10);
CloseFile(f);
end;
label
START, QUERY_CONFIG;
begin
client2.Init(PluginPath);
client2.GetIOManager.SetTarget2(GetRSAppletWnd(SMART.PID));
START:
r := Query('Do you wish to run setup?', ['Yes','No'], DefaultBox);
if r = 'No' then
begin QUERY_CONFIG:
Self.ConfigPath := CONFIG_PATH + QueryStr('Name of config: ', DefaultBox) + '/';
if not LoadConfig() then
case Query('Failed to load config, try again?', ['Yes','No'], DefaultBox) of
'Yes': goto QUERY_CONFIG;
'No' : goto START;
end;
client2.Free();
Exit();
end;
r := MessageBox('Preparing, please stand by...', DefaultBox);
minimap.SetCompassAngle(0);
RSW.Init('world.png');
Query('Click the rocks you wish to mine...', ['OK'], DefaultBox);
RockSpots := SetupLocations();
Query('Click some colors for us to use...', ['OK'], DefaultBox);
RockColors := SetupColors(RockSpots);
if('Banking' = Query('Select style:', ['Banking','Powermining'], DefaultBox)) then
begin
Query('Please walk to your bank', ['OK'], DefaultBox);
BankPath := RecordPath();
Query('Click valid bankers, or booths...', ['OK'], DefaultBox);
BankSpots := SetupLocations();
Query('Click some colors for us to use...', ['OK'], DefaultBox);
BankColors := SetupColors(BankSpots);
end;
Self.ConfigPath := CONFIG_PATH + QueryStr('Save config as: ', DefaultBox) + '/';
SaveConfig();
RSW.Free();
client2.Free();
end;
begin
NativeClient := GetNativeWindow();
smart.EnableDrawing := True;
srl.Setup([]);
srl.Options := [soDebugAntiban];
AddOnTerminate(@smart.Free);
Bot.Init();
Bot.Setup();
RSW.Init(Bot.ConfigPath+CONFIG_MAP);
AddOnTerminate(@RSW.Free);
//RSW.MemScanEnabled := False;
Bot.Run();
end.