SRL Archive - Senior Scripts and Snippets

Brimhaven Agility Arena [Beta]


lordsaturn

2010-09-20 00:18:52

Last updated: 7:21 AM EST Dec 6 2010
program BrimhavenAgility;
{$define smart}
{$i srl/srl.scar}
{$i reflection/reflection.simba}
{$i srl/srl/misc/debug.scar}

procedure SetupPlayers;
begin
NumberOfPlayers(1);
Players[0].Name := '';
Players[0].Pass := '';
Players[0].Active := True;
//Integers[0] = NumTicketsGained;
//Integers[1] = AgiExpGained;
end;

const
Debug = True;
CrapDebug = False; //debug annoying crap
SMART_WORLD = 39;//RECOMMENDED TO SET THIS UP
Save_Stats = True;
Use_Primitive_G_Score = True; //mainly used for testing and gathering unbiased statistics
INI_Path = ScriptPath+'AgilityArenaStats.ini';
TIME_INBETWEEN_PROGGIES = 2; //minutes

/////////////////////////////////////////////////////////////////////////////
//TYPE,CONSTANT,VARIABLE DECLARATION

type //rope, darts, log
obstacle = (Balancing_Ledge, Log_Balance, Rope_Swing, Hand_Holds, Planks,
Pillars, Floor_Spikes, Balancing_Rope, Pressure_Pad, Monkey_Bars, Low_Wall,
Poison_Darts, Spinning_Blade, Blade, None);
obsFunc = function(Tile: TTile): Boolean;
TObstacle = record
Name: obstacle;
level: integer;
exp: integer;
Tile: TTile;
doObstacle: obsFunc;
end;
TNode = record
N, E, S, W: TObstacle;
end;
TColorInfo = record
BestColor: Integer;
ColorArray: TIntegerArray;
HueMod, SatMod: Extended;
BestTolerance: Integer;
MinR, MaxR, MinG, MaxG, MinB, MaxB: Integer;
MinX, MaxX, MinY, MaxY, MinZ, MaxZ: Extended;
MinH, MaxH, MinS, MaxS, MinL, MaxL: Extended;
end;
TStats = record
numPassed, numAttempted: Integer;
totalTime: Integer;
Danger: Integer; //primitive
end;

var
map: array of array of array of TObstacle;
obstacles: array of TObstacle;
autocolors: array of TColorInfo;
bins: array of TStats;
Target_Node: TPoint;
Current_Node: TPoint;

const
DIR_NORTH = 0;
DIR_EAST = 1;
DIR_SOUTH = 2;
DIR_WEST = 3;

const
OBJ_CLIMBING_ROPE_ID = 3610;
ANIM_CLIMBING_ROPE = 828;

OBJ_SWING_ID = 3566;
ANIM_SWING_PASS = 751;
ANIM_SWING_FAIL = 1105;

OBJ_PLANK_FAIL_ID = 3576;
OBJ_PLANK_PASS_ID = 3573; //98% of the time
ANIM_PLANK_FAIL = 768;

OBJ_LOW_WALL_ID = 3565;
ANIM_LOW_WALL_PASS = 1252;

OBJ_BALANCING_ROPE_ID_1 = 3551;//clickable
OBJ_BALANCING_ROPE_ID_2 = 3552;//nonclickable

OBJ_BLADE_STAND_HERE_ID_1 = 35872;
OBJ_BLADE_STAND_HERE_ID_2 = 35873; //type 3
OBJ_BLADE_SAW_UP = 3567; //type 0
OBJ_BLADE_SAW_DOWN_ID_1 = 3568; //type 3
OBJ_BLADE_SAW_DOWN_ID_2 = 3569; //type 3
ANIM_BLADE_FAIL = 2928;

ANIM_LOG_BALANCE_FAIL = 768; //maybe?

ANIM_BALANCING_LEDGE_FAIL = 764;// 753/758 = on/off

OBJ_FLOOR_SPIKES_ID = 3582;
ANIM_FLOOR_SPIKES_PASS = 1115;
ANIM_FLOOR_SPIKES_FAIL = 1114;

OBJ_PILLARS_CLICK_ID = 3578;
ANIM_PILLARS_FAIL = 764;
ANIM_PILLARS_CONTINUE = 741;

OBJ_MONKEY_BARS_CLICK_ID = 3564;
ANIM_MONKEY_BARS_ON = 742;
ANIM_MONKEY_BARS_OFF = 743;
ANIM_MONKEY_BARS_FAIL = 11949;

OBJ_PRESSURE_PAD_ID = 3585;
ANIM_PRESSURE_PAD_PASS = 1115;
ANIM_PRESSURE_PAD_FAIL = 1125;

OBJ_SPINNING_BLADES_ID = 3550;
ANIM_SPINNING_BLADES_PASS = 1115;
ANIM_SPINNING_BLADES_FAIL = 1114;

OBJ_POISON_DARTS_ID = 3550;
ANIM_POISON_DARTS_FAIL = 11942;
ANIM_POISON_DARTS_PASS = 1110;

INV_CAKE_1_ID = 1891; //FULL cake
INV_CAKE_2_ID = 1893; //2/3 cake
INV_CAKE_3_ID = 1895; //1/3 or 'slice of cake'
INV_GOLD_ID = 995;
INV_ARENA_TICKET_ID = 2996;

OBJ_TICKET_DISPENSER_ID = 3608;
OBJ_TICKET_DISPENSER_DARTS_ID = 3581;//also shoots darts

const
nano = -2;
mini = -1;
small = 0;
med = 1;
large = 2;

WAIT_NANO = 100;
WAIT_MINI = 250;
WAIT_SMALL = 350;
WAIT_MED = 700;
WAIT_LARGE = 1050;

TICKET_STATUS_NONE = 3;
TICKET_STATUS_FIRST = 15;
TICKET_STATUS_PENDING = 7;
TICKET_STATUS_GOT_TICKET = 6;
ITEM_TICKET_ID = 2996;

TIME_TO_MOVE = 1500;
BREAK_TIME = 10000;
BREAK_TIME_LONG = 15000;
//times to try each operation
NUM_TRIES = 5;

//time we spend waiting on uptext
OPTION_WAIT_TIME = 300;

OBJ_SEARCH_DISTANCE = 25;

////////////////////////////////////////////////////////////////////////////////
//CONSTRUCTORS

function node(N, E, S, W: obstacle): array of TObstacle;
begin
SetLength(Result, 4);
Result[DIR_NORTH] := obstacles[ord(N)];
Result[DIR_EAST] := obstacles[ord(E)];
Result[DIR_SOUTH] := obstacles[ord(S)];
Result[DIR_WEST] := obstacles[ord(W)];
end;

function obs(Name: obstacle; level, exp: integer; func: obsFunc): TObstacle;
begin
Result.Name := Name;
Result.Level := Level;
Result.Exp := Exp;
Result.doObstacle := func;
Result.Tile := Tile(-1, -1);
end;

////////////////////////////////////////////////////////////////////////////////
//MISC

procedure aDebugTPA(TPA: TPointArray);
begin
if Debug then
DebugTPA(TPA, '');
end;

procedure Write(a: string);
begin
if Debug then
Writeln(a);
end;

procedure CDebug(a: string);
begin
if CrapDebug then
Writeln(a);
end;

function getOrd(a: obstacle): integer;
begin
Result := ord(a);
end;

function GetHP: Integer;
begin
if ValidInterface(748) then
Result := StrToIntDef(GetInterfaceText(748, 8), -1);
end;

{3 red
15 first green
7 green - ticket pending
6 got ticket}
function GetTicketStatus: Integer;
begin
Result := GetSetting(309);
end;

//top floor = floorindex 3
//bottom floor = floorindex 0

function getWait(size: integer): integer;
begin
case size of
nano: Result := WAIT_NANO + Random(WAIT_NANO/(nano+3));
mini: Result := WAIT_MINI + Random(WAIT_MINI/(mini+3));
small: Result := WAIT_SMALL + Random(WAIT_SMALL/(small+3));
med: Result := WAIT_MED + Random(WAIT_MED/(med+3));
large: Result := WAIT_LARGE + Random(WAIT_LARGE/(large+3));
end;
end;

procedure doWait(size: integer);
begin
Wait(getWait(size));
end;

//fixes (exits) when flag gets stuck and when character gets stuck
function WalkTo(Tile: TTile): Boolean;
var
wTile: TPoint;
dist, t, t2: Integer;
begin
Result := False;
wTile := TileToMM(Tile);
if not rs_OnMiniMap(wTile.X, wTile.Y) then
begin
Writeln('Walk to '+ToStr(Tile)+' failed');
Exit;
end;
Mouse(wTile.x, wTile.y, 1, 1, true);
if not WaitToMove(TIME_TO_MOVE) then Exit;
t := GetSystemTime;
while GetSpeed > 0 do //waits for a complete stop
begin
dist := DistanceFromFlag;
if dist > 0 then
begin
t2 := GetSystemTime;
while dist = DistanceFromFlag do
if (GetSystemTime - t) > 2000 then Exit;
end;
end;
Result := (GetSystemTime - t) < 20000;
end;

//GOOD FUCKING IDEA
function WaitTillCameraStopsMoving: Boolean;
var
camX, camY, tmpX, tmpY, a: Integer;
begin
Result := False;
camX := GetCamPosX;
camY := GetCamPosY;
a := GetSystemTime;
while (not(Result)) and (GetSystemTime - a < 20000) do
begin
Wait(50);
tmpX := GetCamPosX;
tmpY := GetCamPosY;
//Writeln('CamX:'+Inttostr(iAbs(tmpX - camX)));
//Writeln('CamY:'+Inttostr(iAbs(tmpY - camY)));
if (iAbs(tmpX - camX) < 30) and (iAbs(tmpY - camY) < 30) then
Result := True
else
begin
camX := tmpX;
camY := tmpY;
end;
end;
end;

//DONT USE THIS IT DOESNT FUCKING WORK!
function SortTilesFrom(TileArr: TTileArray; Tile: TTile): TTileArray;
var
Hi, i: integer;
begin
if Tile.x = -1 then Exit;
Hi := High(TileArr);
SetLength(Result, Hi+1);
for i := 0 to Hi do ;
// QuickTPASort
end;

function SortObjectsFrom(Objects: TRSObjectArray; Tile: TTile): TRSObjectArray;
begin
SetLength(Result, 0);
end;

procedure Eat;
var
Items: TInvItemArray;
Cake: TInvItem;
HP, Timer: Integer;
begin
HP := GetHP;
if (HP > 30) or (HP = -1) then Exit;
if not R_ItemIDExistsEx([INV_CAKE_1_ID, INV_CAKE_2_ID, INV_CAKE_3_ID], Items) then
begin
Writeln('Out of cakes. Terminating');
TerminateScript;
end;
Cake := Items[0];
R_ClickItem(Cake.Slot, True, '');
Timer := GetSystemTime;
while GetSystemTime < Timer + 3000 do
begin
HP := GetHP;
if HP > 30 then Exit;
end;
if (HP <= 30) or (HP = -1) then
begin
Writeln('We somehow failed to heal. Terminating.');
TerminateScript;
end;
end;

////////////////////////////////////////////////////////////////////////////////
//OPTIMAL COLOR METHODS (DYNAMIC)

function GetColorInfo(Colors: TIntegerArray; CTS: integer): TColorInfo;
var
i, Color: Integer;
a, b, c: Integer;
d, e, f: Extended;
begin
if (Length(Colors) < 1) then
Exit;
Result.ColorArray := Colors;
Result.MinR := 500; Result.MaxR := 0;
Result.MinG := 500; Result.MaxG := 0;
Result.MinB := 500; Result.MaxB := 0;
Result.MinH := 500; Result.MaxH := 0;
Result.MinS := 500; Result.MaxS := 0;
Result.MinL := 500; Result.MaxL := 0;
Result.MinX := 500; Result.MaxX := 0;
Result.MinY := 500; Result.MaxY := 0;
Result.MinZ := 500; Result.MaxZ := 0;
for i := 0 to High(Colors) do
begin
Color := Colors[i];
a := (Color and $ff);
b := ((Color and $ff00) shr 8);
c := ((Color and $ff0000) shr 16);
Result.MinR := Min(a, Result.MinR); Result.MaxR := Max(a, Result.MaxR);
Result.MinG := Min(b, Result.MinG); Result.MaxG := Max(b, Result.MaxG);
Result.MinB := Min(c, Result.MinB); Result.MaxB := Max(c, Result.MaxB);
ColorToXYZ(Color, d, e, f);
Result.MinX := MinE(d, Result.MinX); Result.MaxX := MaxE(d, Result.MaxX);
Result.MinY := MinE(e, Result.MinY); Result.MaxY := MaxE(e, Result.MaxY);
Result.MinZ := MinE(f, Result.MinZ); Result.MaxZ := MaxE(f, Result.MaxZ);
ColorToHSL(Color, d, e, f);
Result.MinH := MinE(d, Result.MinH); Result.MaxH := MaxE(d, Result.MaxH);
Result.MinS := MinE(e, Result.MinS); Result.MaxS := MaxE(e, Result.MaxS);
Result.MinL := MinE(f, Result.MinL); Result.MaxL := MaxE(f, Result.MaxL);
end;
case CTS of
0, 1:
begin
a := Ceil((Result.MaxR - Result.MinR) / 2.0);
b := Ceil((Result.MaxG - Result.MinG) / 2.0);
c := Ceil((Result.MaxB - Result.MinB) / 2.0);
Result.BestColor := (a + Result.MinR) + ((b + Result.MinG) shl 8) + ((c + Result.Minb) shl 16);
if (CTS = 0) then
Result.BestTolerance := Max(Max(a, b), c)
else
Result.BestTolerance := Ceil(Sqrt(Sqr(a) + Sqr(b) + Sqr(c)));
end;
2, 3:
begin
d := (Result.MaxH - Result.MinH) / 2.0;
e := (Result.MaxS - Result.MinS) / 2.0;
f := (Result.MaxL - Result.MinL) / 2.0;
Result.BestColor := HSLtoColor(d + Result.MinH, e + Result.MinS, f + Result.MinL);
ColorToHSL(Result.BestColor, d, e, f);
d := MaxE(Abs(Result.MaxH - d), Abs(d - Result.MinH));
e := MaxE(Abs(Result.MaxS - e), Abs(e - Result.MinS));
f := MaxE(Abs(Result.MaxL - f), Abs(f - Result.MinL));
Result.BestTolerance := Ceil(f);
Result.HueMod := d / Max(Result.BestTolerance, 1);
Result.SatMod := e / Max(Result.BestTolerance, 1);
while ((Result.HueMod * Result.BestTolerance) < d) do
Result.HueMod := Result.HueMod + 0.01;
while ((Result.SatMod * Result.BestTolerance) < e) do
Result.SatMod := Result.SatMod + 0.01;
end;
end;
end;

function BestColor(Colors: TIntegerArray): integer;
var
ColorInfo: TColorInfo;
begin
ClearSameIntegers(Colors);
ColorInfo := GetColorInfo(Colors, 1);
Result := ColorInfo.BestColor;
// Result.Tolerance := ColorInfo.BestTolerance;
// Writeln(Result.Color);
// Writeln(Result.Tolerance);
// writeln(colors);
end;

function newColTol(colors: TIntegerArray; CTS: integer): TColorInfo;
begin
ClearSameIntegers(Colors);
Result := GetColorInfo(Colors, CTS);
end;

procedure setNewBestColTol(colors: TIntegerArray; index: integer);
// best: integer;
begin
{algo 1:
best := BestColor(colors);
autocolors[index].Colors := CombineIntArray([best], autocolors[index].Colors);
autocolors[index] := newColTol(autocolors[index].Colors);}
//algo 2
//range check?
Exit; //NOTICE THIS LINE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
autocolors[index] := newColTol(colors, GetToleranceSpeed);
end;

procedure FilterBadPoints(var Pts: TPointArray; var Colors: TIntegerArray; index: integer);
var
tmpColors: TIntegerArray;
tmpPts: TPointArray;
tmpIndex, Hi, i: integer;
H, S, L: Extended;
begin

Hi := High(Colors);
SetLength(tmpColors, Hi+1);
SetLength(tmpPts, Hi+1);
for i := 0 to Hi do
if PointInBox(Pts[i], IntToBox(MSX1, MSY1, MSX2, MSY2))then
begin
tmpColors[tmpIndex] := Colors[i];
tmpPts[tmpIndex] := Pts[i];
Inc(tmpIndex);
end;
SetLength(tmpColors, tmpIndex);
SetLength(tmpPts, tmpIndex);
Pts := tmpPts;
Colors := tmpColors;

Exit; //NOTICE THIS LINE
if (autocolors[index].MaxH = 0) then Exit;
ClearSameIntegersAndTPA(colors, Pts);
Hi := High(Colors);
SetLength(tmpColors, Hi+1);
SetLength(tmpPts, Hi+1);
for i := 0 to Hi do
begin
ColorToHSL(Colors[i], H, S, L);
if (H <= autocolors[index].MaxH) and (H >= autocolors[index].MinH) and
(S <= autocolors[index].MaxS) and (S >= autocolors[index].MinS) and
(L <= autocolors[index].MaxL) and (H >= autocolors[index].MinL) then
begin
tmpPts[tmpIndex] := Pts[i];
tmpColors[tmpIndex] := Colors[i];
Inc(tmpIndex);
end;
end;
Pts := tmpPts;
Colors := tmpColors;
end;

////////////////////////////////////////////////////////////////////////////////
//MOUSE, OPTION, OTHER TPA METHODS

function MyWaitUpTextMulti(Options: TStringArray; Time: integer): Boolean;
begin
Result := WaitUpTextMulti(Options, Time);
if Result then
begin
Wait(120);
Result := IsUpTextMultiCustom(Options);
end;
end;

function R_MyWaitOptionMulti(Options: TStringArray; Time: Integer): Boolean;
var
T: Integer;
begin
Result := False;
T := GetSystemTime + Time;
while (GetSystemTime < T) do
begin
if (R_ChooseOptionMulti(Options)) then
begin
Result := True;
Exit;
end;
//Wait(20 + Random(10));
end;
end;

function R_MyWaitUpTextMulti(Options: TStringArray; Time: Integer): Boolean;
var
T: Integer;
begin
Result := false;
T := GetSystemTime + Time;
while (GetSystemTime < T) do
begin
if (R_IsUpTextMulti(Options)) then
begin
Wait(120);
Result := R_IsUpTextMulti(Options);
Exit;
end;
//Wait(20 + Random(20));
end;
end;

function Clicky(click: TPoint; options: TStringArray): Boolean;
var
x, y: integer;
begin
if (click.x = -1) then Exit;
MMouse(click.x, click.y, 1, 1);
GetMousePos(x, y);
if Random(2) = 1 then
begin
//doWait(nano);
Mouse(x, y, 0, 0, False);
//Result := WaitOptionMulti(options, 1200);
Result := R_MyWaitOptionMulti(options, OPTION_WAIT_TIME);
end else
begin
//Result := MyWaitUpTextMulti(options, 1200);
Result := R_MyWaitUpTextMulti(options, OPTION_WAIT_TIME);
if Result then
Mouse(x, y, 0, 0, True)
else
begin
Mouse(x, y, 0, 0, False);
Result := R_MyWaitOptionMulti(options, OPTION_WAIT_TIME);
end;
end;
end;

function LeftClicky(click: TPoint; options: TStringArray): Boolean;
var
x, y: integer;
begin
if (click.x = -1) then Exit;
MMouse(click.x, click.y, 0, 0);
GetMousePos(x, y);
Result := R_MyWaitUpTextMulti(options, OPTION_WAIT_TIME);
if Result then
Mouse(x, y, 0, 0, True);
end;

function RightClicky(click: TPoint; options: TStringArray): Boolean;
begin
if (click.x = -1) then Exit;
Mouse(click.x, click.y, 0, 0, False);
Result := R_MyWaitOptionMulti(options, OPTION_WAIT_TIME);
end;

function SearchUpText(Pt1, Pt2: TPoint; UpText: TStringArray): Boolean;
var
newX, newY, i, Stops: integer;
newPt, lastPt: TPoint;
begin
Stops := 5;//actually 6
for i := 0 to Stops do
begin
newX := Round(Pt1.x + (Pt2.x-Pt1.x)*i/Stops);
newY := Round(Pt1.y + (Pt2.y-Pt1.y)*i/Stops);
newPt := Point(newX, newY);
if (newPt <> lastPt) then
begin
MMouse(newX, newY, 0, 0);
Result := R_MyWaitUpTextMulti(UpText, OPTION_WAIT_TIME/2);
if Result then
begin
ClickMouse2(True);
Exit;
end;
lastPt := newPt;
end;
end;
end;

function GetBestPoint(P: TPointArray): TPoint;
var
H, i, dist, minDist: integer;
aPoint: TPoint;
begin
aPoint := MiddleTPA(P);
Result := aPoint;
if (not(PointInTPA(Result, P))) then
begin
H := High(P);
for i := 0 to H do
begin
dist := Distance(P[i].x, P[i].y, aPoint.x, aPoint.y);
if (i = 0) or (dist < minDist) then
begin
minDist := Dist;
Result := P[i];
end;
end;
end;
end;

////////////////////////////////////////////////////////////////////////////////
//POSITION FUNCTIONS

function GetProjectedTile(nodeY, nodeX: integer): TTile;
begin
Result := Tile(-1, -1);
if (nodeY < 0) or (nodeY > 4) then Exit;
if (nodeX < 0) or (nodeX > 4) then Exit;

if (map[NodeY][nodeX][DIR_NORTH].Name = None) or
(map[NodeY][nodeX][DIR_NORTH].Name = Hand_Holds) or
(map[NodeY][nodeX][DIR_NORTH].Name = Rope_Swing) then
Result.x := map[nodeY][nodeX][DIR_SOUTH].Tile.x
else
Result.x := map[nodeY][nodeX][DIR_NORTH].Tile.x;

if (map[NodeY][nodeX][DIR_WEST].Name = None) or //only node this will have a problem with is [2,0]
(map[NodeY][nodeX][DIR_WEST].Name = Hand_Holds) or
(map[NodeY][nodeX][DIR_WEST].Name = Rope_Swing) then
Result.y := map[nodeY][nodeX][DIR_EAST].Tile.y
else
begin
Result.y := map[nodeY][nodeX][DIR_WEST].Tile.y;
if (nodeY = 2) and (nodeX = 0) then
Dec(Result.y);
end;
end;

function GetClosestNodeTo(Tile: TTile): TPoint;
var
aTile: TTile;
tmpDist, lowDist, x, y: Integer;
begin
Result := Point(-1, -1);
lowDist := -1;
for y := 0 to 4 do
for x := 0 to 4 do
begin
aTile := GetProjectedTile(y, x);
tmpDist := Distance(Tile.x, Tile.y, aTile.x, aTile.y);
if (tmpDist < lowDist) or (lowDist = -1) then
begin
lowDist := tmpDist;
Result := Point(x, y);
end;
end;
end;

function GetCurrNode: TPoint;
begin
Result := GetClosestNodeTo(GetMyPos);
end;

//MINIMAP MUST BE FACING NORTH
function getTargetNode(currY, currX: Integer): TPoint;
var
Pts: TPointArray;
Hi, i, tmpDist, farDist, Timer: integer;
FurthestPoint: TPoint;

lowDist, x, y, tx, ty, xDev, yDev: integer;
Loc, TheTile: TTile;
aPt: TPoint;

lowDistE, tmpDistE, a, b, c, m, n: Extended;
aTile: TTile;
begin
Result := Point(-1, -1);
//get mm point
ColorToleranceSpeed(2);
SetColorspeed2Modifiers(autocolors[15].HueMod, autocolors[15].SatMod);
Timer := GetSystemTime;
while not
FindColorsPie(Pts, autocolors[15].BestColor, autocolors[15].BestTolerance,
0, 360, 0, 75, MMX1, MMY1, MMX2, MMY2, MMCX, MMCY)
do
begin
if GetSystemTime - Timer > 5000 then
begin
Writeln('Could not find our target.');
Exit;
end;
//Wait(10);
end;
ColorToleranceSpeed(1);
Hi := High(Pts);
for i := 0 to Hi do
begin
tmpDist := Distance(Pts[i].x, Pts[i].y, MMCX, MMCY);
if tmpDist > farDist then
begin
farDist := tmpDist;
FurthestPoint := Pts[i];
end;
end;

//if tile is on mm, get closest using pixels
if (InCircle(FurthestPoint.x, FurthestPoint.y, MMCX, MMCY, 66)) then
begin
for y := -1 to 1 do
for x := -1 to 1 do
begin
aTile := GetProjectedTile(currY+y, currX+x);
aPt := TileToMM(aTile);
if (aPt.x > -1) then
begin
tmpDist := Distance(FurthestPoint.x, FurthestPoint.y, aPt.x, aPt.y);
if (tmpDist < 15) then
begin
Result := Point(currX+x, currY+y);
Exit;
end;
end;
end;
end;

//convert mm point to tile
xDev := (FurthestPoint.x - MMCX)/4;
yDev := (FurthestPoint.y - MMCY)/4;
Loc := GetMyPos;
Loc.x := Loc.x + xDev;
Loc.y := Loc.y - yDev; //runescape y axis is inverted
tx := -11;
for x := -2 to 2 do
for y := -2 to 2 do
begin
aPt := TileToMM(Tile(Loc.x+x, Loc.y+y));
if (aPt.x > -1) then
begin
tmpDist := Distance(aPt.x, aPt.y, FurthestPoint.x, FurthestPoint.y);
if (tmpDist < lowDist) or (lowDist = -1) then
begin
lowDist := tmpDist;
tx := x;
ty := y;
end;
end;
end;
if (tx > -11) then
TheTile := Tile(Loc.x+tx, Loc.y+ty)
else
TheTile := Loc;

//shortest distance from point to line
Loc := GetMyPos;
CDebug(tostr(loc)+'-'+tostr(thetile));
{if (TheTile.y - Loc.y) = 0 then
Slope := 0
else
if (TheTile.x - Loc.x) = 0 then
begin
if (TheTile.y - Loc.y) < 0 then
Slope := -99999999
else
Slope := 99999999;
end else
Slope := (TheTile.y - Loc.y)*1.0/(TheTile.x - Loc.x);
writeln(tostr(TheTile.y - Loc.y)+'/'+tostr(thetile.x-loc.x));
Writeln('slope: '+tostr(slope)); }
// y - y 1 = m(x - x 1 )
//y = Slope*x - Slope*Loc.x + Loc.y;
//http://www.worsleyschool.net/science/files/linepoint/method5.html
//http://bobobobo.wordpress.com/2008/01/07/solving-linear-equations-ax-by-c-0/
{a := Slope;
b := -1;
c := -1*Slope*Loc.x + Loc.y;
write(tostr(a)+';'+tostr(b)+';'+tostr(c));}
a := (TheTile.y - Loc.y);
b := (Loc.x - TheTile.x);
c := (TheTile.x*Loc.y) - Loc.x*TheTile.y;
lowDistE := -1.0;
for y := 0 to 4 do
for x := 0 to 4 do
begin
aTile := GetProjectedTile(y, x);
if (Distance(aTile.x, aTile.y, TheTile.x, TheTile.y) < Distance(aTile.x, aTile.y, Loc.x, Loc.y)) then
begin
m := aTile.x;
n := aTile.y;
tmpDistE := Abs(a*m + b*n + c) / Sqrt(Sqr(a) + Sqr(b));
CDebug(tostr(point(y, x))+':'+tostr(tmpdiste));
if (tmpDistE < lowDistE) or (lowDistE = -1.0) then
begin
lowDistE := tmpDistE;
Result := Point(x, y);
CDebug(ToStr(Result)+'-'+ToStr(aTile));
end;
end;
end;

end;

function GetLocalMMArrowPoint: TPoint;
var
L, a, BigY, i, Hi: Integer;
TPA: TPointArray;
begin
Result := Point(-1, -1);
L := 0;
a := GetSystemTime;
ColorToleranceSpeed(2);
SetColorspeed2Modifiers(0.29, 2.41);
while (L = 0) and (GetSystemTime - a < 1000) do
begin
FindColorsTolerance(TPA, 2641247, MMX1, MMY1, MMX2, MMY2, 2); //outline
L := Length(TPA);
end;
ColorToleranceSpeed(1);
if (L = 0) then
begin
Write('GetLocalMMArrowPoint failed');
Exit;
end;

Hi := High(TPA);
for i := 0 to Hi do
if rs_OnMinimap(TPA[i].x, TPA[i].y) then
if TPA[i].y > BigY then
begin
BigY := TPA[i].y;
Result := TPA[i];
end;
end;

////////////////////////////////////////////////////////////////////////////////
//OBSTACLE FUNCTIONS

//Climb Climbing rope
procedure recover;
var
climbing_rope: TRSObject;
click: TPoint;
a, tries: integer;
Pts: TPointArray;
col, tol: integer;
colors: TIntegerArray;
begin
while (GetAnimation > -1) or (GetSpeed > 0) do ;
doWait(med);
WaitTillCameraStopsMoving;
Eat;
while (not(GetPlaneIndex = 3)) and (tries < NUM_TRIES + 1) do
begin
//get climbing rope object
climbing_rope := GetObjectByID(OBJ_CLIMBING_ROPE_ID, OBJECT_TYPE_INTERACTABLE, OBJ_SEARCH_DISTANCE);
if (climbing_rope.ID <> OBJ_CLIMBING_ROPE_ID) then
begin
Writeln('failed to locate the climbing rope');
end else
begin

//get the MS point to click
click := TileToMS(climbing_rope.Tile, 760);
if (click.x = -1) then
begin
WalkTo(climbing_rope.Tile)
WaitTillCameraStopsMoving;
click := TileToMS(climbing_rope.Tile, 760);
end;

col := autocolors[getOrd(None)].BestColor;
tol := autocolors[getOrd(None)].BestTolerance;
if FindColorsTolerance(Pts, col, click.x-30, click.y-60, click.x+30, click.y+60, tol) then
begin
colors := GetColors(Pts);
FilterBadPoints(Pts, colors, getOrd(None));
click := GetBestPoint(Pts);
aDebugtpa(pts);
end;
//try to click
if (leftClicky(click, ['imb', 'ope'])) then
begin
a := GetSystemTime;
//timeout after 10 seconds
repeat
if (GetPlaneIndex = 3) then
begin
while GetAnimation > -1 do ;
if Length(pts) > 0 then
begin
setNewBestColTol(colors, getOrd(None));
end;
doWait(small);
Exit;
end;
until GetSystemTime - a > BREAK_TIME;
Writeln('failed to climb the rope, timed out');
end;

end;
tries := tries + 1;
end;

if (GetPlaneIndex = 0) then
begin
Writeln('failed to climb the rope '+tostr(NUM_TRIES)+' times, terminating');
TerminateScript;
end;
end;

{ground ground ground
air air air
air air swing- TILE
swing air air
air air air
ground ground ground}

//Swing-on Rope swing
function obsSwing(tile: ttile): Boolean;
var
click: TPoint;
anim, timer, tries: integer;
col, tol: integer;
Pts: TPointArray;
colors: TIntegerArray;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;
anim := -1;

// once the rope swing has been used once, the object is erased from the client
// if anyone knows why this happens, PLEASE LET ME KNOW!!!!
//search for obj
{swing := GetObjectByID(OBJ_SWING_ID, OBJECT_TYPE_INTERACTABLE, OBJ_SEARCH_DISTANCE);
if (swing.ID <> OBJ_SWING_ID) then
begin
Writeln('failed to locate the swing');
end else }
begin

//click on obj

click := TileToMS(Tile, 70);
if (click.x = -1) then
begin
WalkTo(Tile);
WaitTillCameraStopsMoving;
doWait(small);
click := TileToMS(Tile, 70);
end;

col := autocolors[getOrd(Rope_Swing)].BestColor;
tol := autocolors[getOrd(Rope_Swing)].BestTolerance;
if FindColorsTolerance(Pts, col, click.x-30, click.y-30, click.x+30, click.y+30, tol) then
begin
colors := GetColors(Pts);
FilterBadPoints(Pts, colors, getOrd(Rope_Swing));
click := GetBestPoint(Pts);
aDebugtpa(pts);
end; //flag-safe
if RightClicky(click, ['wing-on', 'g-on', 'on']) and WaitToMove(TIME_TO_MOVE) then
begin

Inc(bins[GetOrd(Rope_Swing)].numAttempted);

//wait for anim to start
timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at swinging, timer 1');
Break;
end;
anim := GetAnimation;
until anim > -1;

//wait for anim to finish
if (anim > -1) then
begin
Result := anim = ANIM_SWING_PASS;
while GetAnimation = anim do ;
doWait(small);
WaitTillCameraStopsMoving;
end;

if Result then
begin
IncEx(bins[GetOrd(Rope_Swing)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Rope_Swing)].numPassed);
end;

//if we failed, restart
if (anim = ANIM_SWING_FAIL) then
begin
recover;
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
//update color
if Length(pts) > 0 then
setNewBestColTol(colors, getOrd(Rope_Swing));
end;
end;
end;

tries := tries + 1;
end;
if Result then
if Length(pts) > 0 then
begin
setNewBestColTol(colors, getOrd(Rope_Swing));
end;
end;


{ground plank
ground plank- TILE
ground plank}
//Walk-on Plank
function obsPlank(tile: ttile): Boolean;
var
click: TPoint;
anim, timer, tries, i, Hi, y: integer;
Plank: TRSObjectArray;
target, loc: TTile;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;
anim := -1;

//search for obj
Plank := GetObjectsByID([OBJ_PLANK_FAIL_ID], OBJECT_TYPE_FLOORDECOR, OBJ_SEARCH_DISTANCE);
Hi := High(Plank);
if (Hi < 0) then
begin
Writeln('failed to find a safe plank');
end else
begin

//SortObjectsFrom(Plank, GetMyLoc???????/??????/?//////??);
//get safe plank
for y := Tile.y - 1 to Tile.y + 1 do
begin
Result := True; //for lack of a better variable
for i := 0 to Hi do
if (Plank[i].Tile.y = y) then
Result := False;
if Result then
begin
Target := PointToTile(Point(Tile.x, y));
Break;
end;
end;
Result := False;

//click on obj
click := TileToMS(target, 15);
if (click.x = -1) then
begin
WalkTo(target);
WaitTillCameraStopsMoving;
click := TileToMS(target, 15);
end;

if Clicky(click, ['alk-on', 'k-on', 'on']) and WaitToMove(TIME_TO_MOVE) then
begin
doWait(mini);
Inc(bins[GetOrd(Planks)].numAttempted);

//wait for arr matey to cross the plank arr
timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at crossing planks, timer 1');
Break;
end;
anim := GetAnimation;
loc := GetMyPos; //all planks are horizontal, fortunately
Result := iAbs(loc.x-tile.x) = 6;
until (anim > -1) or (Result);
doWait(mini);
WaitTillCameraStopsMoving;

if Result then
begin
IncEx(bins[GetOrd(Planks)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Planks)].numPassed);
end;

if (anim > -1) then
begin
while GetAnimation = anim do ;
doWait(small);
recover;
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;
end;
end;

tries := tries + 1;
end;
end;

//first hold - tile
//start: 1117, 1121
//mid: 1118, 1122
//end: 1120, 1124
//fail: 1119, 1123
//Climb-across Hand holds
function obsHolds(tile: ttile): Boolean;
var
click, click2: TPoint;
anim, timer, tries, anim2, i: integer;
Pts: TPointArray;
cols: TIntegerArray;
ATPA: T2DPointArray;
xe, ye: Extended;
begin
doWait(mini);
case Tile of
map[0][2][DIR_EAST].Tile:
begin
xe := 0.6;
ye := 1.0;
end;
map[0][3][DIR_WEST].Tile:
begin
xe := 0.4;
ye := 1.0;
end;

map[2][0][DIR_SOUTH].Tile:
begin
xe := 0.3;
ye := 1.5;
end;
map[3][0][DIR_NORTH].Tile:
begin
xe := 0.3;
ye := 1.0;
end;

map[4][2][DIR_EAST].Tile:
begin
xe := 0.6;
ye := 0.0;
end;
map[4][3][DIR_WEST].Tile:
begin
xe := 0.4;
ye := 0.0;
end;
end;
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;
anim := -1;

//click on obj
click := TileToMSEx(Tile, xe, ye, 640);
if (click.x = -1) then
begin
WalkTo(tile);
WaitTillCameraStopsMoving;
click := TileToMSEx(Tile, xe, ye, 640);
end;

//if we cant find the hold using reflection, use color
if (tries > 0) then
begin
ColorToleranceSpeed(2);
SetColorspeed2Modifiers(autocolors[getOrd(Hand_Holds)].HueMod, autocolors[getOrd(Hand_Holds)].SatMod);
if FindColorsTolerance(Pts, autocolors[getOrd(Hand_Holds)].BestColor, click.x-10, click.y-30, click.x+10, click.y+30, autocolors[getOrd(Hand_Holds)].BestTolerance) then
begin
cols := GetColors(Pts);
FilterBadPoints(Pts, cols, getOrd(Hand_Holds));
ATPA := SplitTPA(Pts, 2);
SetLength(Pts, 0);
for i := 0 to High(ATPA) do
if Length(ATPA[i]) > Length(Pts) then
Pts := ATPA[i];
Click2 := GetBestPoint(Pts);
aDebugTPA(pts);
end;
ColorToleranceSpeed(1);
end else
Click2 := click;

if SearchUpText(click2, click, ['limb', 'limb-across', 'b-ac', 'cro', 'oss'])
and WaitToMove(TIME_TO_MOVE) then
begin

//wait for anim
timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at crossing hand holds, timer 1');
Break;
end;
anim := GetAnimation;
until (anim > -1);

if (anim > -1) then
begin

Inc(bins[GetOrd(Hand_Holds)].numAttempted);

anim2 := anim;
//get the second animation
while anim2 = anim do
begin
anim2 := GetAnimation;
end;
//wait to finish any animation
while GetAnimation > -1 do ;

//check to see if we pass or fail
Result := (anim2 - anim) = 1; //fail = 2

if Result then
begin
IncEx(bins[GetOrd(Hand_Holds)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Hand_Holds)].numPassed);
end;

//if we failed, recover
if (not(Result)) then
begin
doWait(med);
recover;
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
//update color
if Length(Pts) > 0 then
setNewBestColTol(cols, getOrd(Hand_Holds));
end;
end;

end;
tries := tries + 1;
end;
if Result then
if Length(Pts) > 0 then
setNewBestColTol(cols, getOrd(Hand_Holds));

end;

//ground, wall-tile, wall-tile, ground
//Climb-over Low wall
function obsWall(tile: ttile): Boolean;
var
click, click2: TPoint;
anim, timer, tries: integer;
walls: array of TRSObject;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;
anim := -1;

//search for obj
walls := GetObjectsByID([OBJ_LOW_WALL_ID], OBJECT_TYPE_INTERACTABLE, OBJ_SEARCH_DISTANCE);
if (Length(walls) < 2) then
begin
Writeln('failed to find the low wall');
Wait(3000);
end else
begin

//get middle of both wall objects
click := TileToMS(walls[0].Tile, 9);
click2 := TileToMS(Walls[1].Tile, 9);
if (click.x = -1) or (click2.x = -1) then
begin
WalkTo(walls[1].Tile);
WaitTillCameraStopsMoving;
click := TileToMS(walls[0].Tile, 9);
click2 := TileToMS(Walls[1].Tile, 9);
end;
click := MiddleTPA([click, click2]);
//click on obj
if Clicky(click, ['limb', 'limb-over', 'b-o', 'ver']) and WaitToMove(TIME_TO_MOVE) then
begin

//wait to climb
timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at climbing low wall, timer 1');
Break;
end;
anim := GetAnimation;
until (anim > -1);

if (anim > -1) then
begin

Inc(bins[GetOrd(Low_Wall)].numAttempted);

while GetAnimation = anim do ;
Result := anim = ANIM_LOW_WALL_PASS;
while GetObjectByID(OBJ_LOW_WALL_ID, OBJECT_TYPE_INTERACTABLE, 5) = NULL_RSOBJECT do
Wait(10);
doWait(small);

if Result then
begin
IncEx(bins[GetOrd(Low_Wall)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Low_Wall)].numPassed);
end;

//never had this happen
if (not(Result)) then
begin
if (GetPlaneIndex = 0) then
Recover;
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;
end;
end;
end;

tries := tries + 1;
end;
end;

{rope1 - tile
rope2
rope2}
//Walk-on Balancing rope
function obsBalanceRope(tile: ttile): Boolean;
var
click, click2: TPoint;
timer, tries, i, anim: integer;
rope1, rope2: TRSObject;
Pts: TPointArray;
cols: TIntegerArray;
ATPA: T2DPointArray;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
//search for obj
//rope1 := GetObjectByID(OBJ_BALANCING_ROPE_ID_1, OBJECT_TYPE_FLOORDECOR, OBJ_SEARCH_DISTANCE);

//case of the disappearing object, again.. refer to obsSwing for an explanation

rope1 := NewObject(OBJ_BALANCING_ROPE_ID_1, OBJECT_TYPE_FLOORDECOR, Tile);
rope2 := GetObjectByID(OBJ_BALANCING_ROPE_ID_2, OBJECT_TYPE_FLOORDECOR, OBJ_SEARCH_DISTANCE);
if (rope1.ID <> OBJ_BALANCING_ROPE_ID_1) or (rope2.ID <> OBJ_BALANCING_ROPE_ID_2) then
begin
Writeln('failed to find the balancing rope');
Wait(3000);
end else
begin

//writeln(rope1.Tile);
//writeln(rope2.Tile);
//get middle of both objects
click := TileToMS(rope1.Tile, 9);
click2 := TileToMS(rope2.Tile, 9);
if (click.x = -1) or (click2.x = -1) then
begin
WalkTo(rope2.Tile);
WaitTillCameraStopsMoving;
doWait(med);
click := TileToMS(rope1.Tile, 9);
click2 := TileToMS(rope2.Tile, 9);
end;

//writeln('click b4: '+tostr(click));
//if we cant find the hold using reflection, use color
//if (tries > 0) then
if (click.x > -1) and (click2.x > -1) then
begin
click := MiddleTPA([click, click2]);
ColorToleranceSpeed(2);
SetColorspeed2Modifiers(autocolors[getOrd(Balancing_Rope)].HueMod, autocolors[getOrd(Balancing_Rope)].SatMod);
if FindColorsTolerance(Pts, autocolors[getOrd(Balancing_Rope)].BestColor, click.x-30, click.y-30, click.x+30, click.y+30, autocolors[getOrd(Balancing_Rope)].BestTolerance) then
begin
cols := GetColors(Pts);
//writeln('len b4:'+tostr(length(pts)));
//FilterBadPoints(Pts, cols, getOrd(Balancing_Rope));
//writeln('len after:'+tostr(length(pts)));
ATPA := SplitTPA(Pts, 2);
SetLength(Pts, 0);
for i := 0 to High(ATPA) do
if Length(ATPA[i]) > Length(Pts) then
Pts := ATPA[i];
Click := GetBestPoint(Pts);
aDebugTPA(pts);
end;
ColorToleranceSpeed(1);
end;
//writeln('click after: '+tostr(click));
//click on obj
if (click.x > -1) then
begin
if RightClicky(click, ['alk-on', 'k-on', 'on']) and WaitToMove(TIME_TO_MOVE) then
begin

Inc(bins[GetOrd(Balancing_Rope)].numAttempted);

//wait to move
timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at walking balancing rope, timer 1');
Break;
end;
Result := DistanceFrom(Tile) >= 7;
anim := GetAnimation;
until (anim > -1) or Result;

while GetAnimation > -1 do ;
doWait(large);
WaitTillCameraStopsMoving;
Result := DistanceFrom(Tile) >= 7;

if Result then
begin
doWait(mini);
IncEx(bins[GetOrd(Balancing_Rope)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Balancing_Rope)].numPassed);
end;

//assuming failed
if (GetPlaneIndex = 0)then
begin
doWait(small);
recover;
if Length(Pts) > 0 then
setNewBestColTol(cols, getOrd(Balancing_Rope));
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;
end;
end;
end;

tries := tries + 1;
end;
if Result then
if Length(Pts) > 0 then
setNewBestColTol(cols, getOrd(Balancing_Rope));
end;

{ground
log - tile
log
log}
//Walk-on Log balance
function obsLog(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries: integer;
colors: TIntegerArray;
TPA: TPointArray;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

click := TileToMS(Tile, 9);
if (click.x = -1) then
begin
WalkTo(Tile);
WaitTillCameraStopsMoving;
click := TileToMS(Tile, 9);
end;

if (tries > 0) then
begin
ColorToleranceSpeed(2);
SetColorspeed2Modifiers(autocolors[getOrd(Log_Balance)].HueMod, autocolors[getOrd(Log_Balance)].SatMod);
if FindColorsTolerance(TPA, autocolors[getOrd(Log_Balance)].BestColor, click.x-30, click.y-30, click.x+30, click.y+30, autocolors[getOrd(Log_Balance)].BestTolerance) then
begin
colors := GetColors(TPA);
FilterBadPoints(TPA, colors, getOrd(Log_Balance));
click := GetBestPoint(TPA);
aDebugtpa(TPA);
end;
ColorToleranceSpeed(1);
end;

if (click.x > -1) and (Clicky(click, ['alk-on', 'k-on', 'on'])) and WaitToMove(TIME_TO_MOVE) then
begin
doWait(small);
Inc(bins[GetOrd(Log_Balance)].numAttempted);
timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at completing log balance obstacle, timer 1');
Break;
end;
until (GetAnimation > -1); //id = 9908
while GetAnimation > -1 do ;
doWait(small);
WaitTillCameraStopsMoving;
Result := DistanceFrom(Tile) >= 6;

if Result then
begin
IncEx(bins[GetOrd(Log_Balance)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Log_Balance)].numPassed);
end;

if GetPlaneIndex = 0 then //assuming failed
begin
Recover;
if Length(TPA) > 0 then
setNewBestColTol(colors, GetOrd(Log_Balance));
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;
end;

tries := tries + 1;
end;
if Result and (Length(TPA) > 0) then
setNewBestColTol(colors, GetOrd(Log_Balance));
end;

{ground-tile
saw
saw
ground}
function obsBlade(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries, ms, x, y, binTimer: integer;
stand: TRSObject;
//aTile: TTile;
//xDiff, yDiff: Integer;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

if tries > 0 then //will work for this one
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;

//search for obj
if (GetMyPos = Tile) then
begin //old getTarget tile
{SetLength(stand, 3);
stand[0] := GetObjectByID(OBJ_BLADE_STAND_HERE_ID_1, OBJECT_TYPE_FLOORDECOR, OBJ_SEARCH_DISTANCE);
stand[1] := GetObjectByID(OBJ_BLADE_STAND_HERE_ID_2, OBJECT_TYPE_FLOORDECOR, OBJ_SEARCH_DISTANCE);
if (stand[0].ID = -1) and (stand[1].ID = -1) then
begin
Writeln('big uh oh in obsBlade, we couldn''t find any objects');
end else
if (stand[0].ID = -1) then
ID := stand[1].ID
else
if (stand[1].ID = -1) then
ID := stand[0].ID
else
begin
//stand[2] := GetObjectByID(OBJ_BLADE_SAW_UP, OBJECT_TYPE_INTERACTABLE, OBJ_SEARCH_DISTANCE)
//if (stand[2].ID = -1) then
// stand[2] := GetObjectByID(OBJ_BLADE_SAW_DOWN_ID_1, OBJECT_TYPE_FLOORDECOR, OBJ_SEARCH_DISTANCE
// sortfrom(^
//if shit goes down use ^
x := DistanceFrom(TileToPoint(stand[0].Tile));
y := DistanceFrom(TileToPoint(stand[1].Tile));
if (x = y) then
begin
Writeln('shit, we have to guess in obsBlade.');
ID := stand[0].ID;
end else
if (x < y) then
ID := stand[0].ID
else
ID := stand[1].ID;
end; }
end else
begin
click := TileToMS(Tile, 9);
if (click.x = -1) then
begin
WalkTo(Tile);
WaitTillCameraStopsMoving;
click := TileToMS(Tile, 9);
end;
Mouse(click.x, click.y, 1, 1, True);
R_Flag;
//WaitTillCameraStopsMoving;
end;

if (not(GetMyPos = Tile)) then
begin
Writeln('Failed to stand in saw spot');
end else
begin

stand := GetObjectByID(OBJ_BLADE_SAW_UP, OBJECT_TYPE_INTERACTABLE, OBJ_SEARCH_DISTANCE);
if (stand.ID = -1) then
stand := GetObjectByID(OBJ_BLADE_SAW_DOWN_ID_1, OBJECT_TYPE_FLOORDECOR, OBJ_SEARCH_DISTANCE);

if (stand.ID = -1) then
begin
Writeln('Failed to find a saw object');
Wait(300);
end else
begin
ms := MouseSpeed;
MouseSpeed := 500;

//get target tile
{aTile := Tile;
xDiff := stand.Tile.x - Tile.x;
yDiff := stand.Tile.y - Tile.y;
for x := 1 to 3 do
begin
aTile.x := aTile.x + xDiff
aTile.y := aTile.y + yDiff;
end; }
//so that if delta = 1, + 3; if delta = 2, + 5
stand.Tile.x := stand.Tile.x + ceil((stand.Tile.x - Tile.x)*2.3);
stand.Tile.y := stand.Tile.y + ceil((stand.Tile.y - Tile.y)*2.3);
click := TileToMS(stand.Tile, 9);
if (click.x = -1) then
begin //half distance
stand.Tile.x := stand.Tile.x - (stand.Tile.x - Tile.x)/2;
stand.Tile.y := stand.Tile.y - (stand.Tile.y - Tile.y)/2;
click := TileToMS(stand.Tile, 9);
end;
Write('blade: from '+tostr(tile)+' to '+tostr(stand.tile));
MMouse(click.x, click.y, 1, 1);
GetMousePos(x, y);

Inc(bins[GetOrd(Blade)].numAttempted);
binTimer := GetSystemTime;

repeat //appear
stand := GetObjectByID(OBJ_BLADE_SAW_UP, OBJECT_TYPE_INTERACTABLE, OBJ_SEARCH_DISTANCE);
until stand.ID > -1;
repeat //disappear
stand := GetInteractableAt(stand.Tile);
until stand.ID = -1;
HoldMouse(x, y, mouse_Left);
Wait(15);
ReleaseMouse(x, y, mouse_Left);

timer := GetSystemTime;
while not IsMoving do
begin
Wait(10);
if (GetSystemTime - timer) > 2000 then
begin
Writeln('failed at completing blade obstacle, timer 1');
Break;
end;
end;
while IsMoving do ;
while GetAnimation > -1 do ;
WaitTillCameraStopsMoving;
Result := DistanceFrom(Tile)>=3;

if Result then
begin
IncEx(bins[GetOrd(Blade)].totalTime, GetSystemTime - binTimer);
Inc(bins[GetOrd(Blade)].numPassed);
end;

Eat;
MouseSpeed := ms;
end;

end;
tries := tries + 1;
end;
end;

{ground, ledge - tile, ledge, ledge,}
//Walk-across Balancing ledge
function obsLedge(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries, anim: integer;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

click := TileToMS(Tile, 330);
if (click.x = -1) then
begin
WalkTo(Tile);
WaitTillCameraStopsMoving;
click := TileToMS(Tile, 330);
end;

if (Clicky(click, ['alk-acr', 'k-ac', 'ross', 'os', 'ss'])) and WaitToMove(TIME_TO_MOVE) then
begin

Inc(bins[GetOrd(Balancing_Ledge)].numAttempted);

timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at crossing the balancing ledge, timer 1');
Break;
end;
anim := GetAnimation;
Result := DistanceFrom(Tile) >= 6;
until Result or (anim = ANIM_BALANCING_LEDGE_FAIL);

while GetAnimation > -1 do ;
doWait(small);

if Result then
begin
WaitTillCameraStopsMoving;
IncEx(bins[GetOrd(Balancing_Ledge)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Balancing_Ledge)].numPassed);
end;

if anim = ANIM_BALANCING_LEDGE_FAIL then
begin
doWait(nano);
Recover;
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;
end;

tries := tries + 1;
end;
end;

{ground-start
spike
spike
ground-finish-TILE}
function obsSpikes(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries, anim: integer;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

Click := TileToMM(RandomizeTile(Tile, 0, 0));
if (Click.x = -1) then
begin
Writeln('Could not pass the floor spikes obstacle');
end else
begin

//WalkToTile(Tile, 0, 0);
Mouse(Click.x, Click.y, 3, 3, True);
if not WaitToMove(TIME_TO_MOVE) then Continue;

Inc(bins[GetOrd(Floor_Spikes)].numAttempted);

timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at crossing the floor spikes, timer 1');
Break;
end;
anim := GetAnimation;
Result := GetMyPos = Tile;
until (Result) or (anim = ANIM_SPINNING_BLADES_FAIL);

while GetAnimation > -1 do ;
doWait(small);

if Result then
begin
WaitTillCameraStopsMoving;
IncEx(bins[GetOrd(Floor_Spikes)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Floor_Spikes)].numPassed);
end;

if anim = ANIM_SPINNING_BLADES_FAIL then
begin
tries := -1;
Eat;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;

end;
tries := tries + 1;
end;
end;

{ground
pillar - tile
pillar
pillar}
//Jump-on Pillar
function obsPillars(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries, anim: integer;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

click := TileToMS(Tile, 10);
if (click.x = -1) then
begin
WalkTo(Tile);
WaitTillCameraStopsMoving;
click := TileToMS(Tile, 10);
end;

if Clicky(click, ['ump', 'ump-on', 'p-o', 'on']) and WaitToMove(TIME_TO_MOVE) then
begin
doWait(med);
Inc(bins[GetOrd(Pillars)].numAttempted);

timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME_LONG then
begin
Writeln('failed at crossing the pillars, timer 1');
Break;
end;
anim := GetAnimation;
Result := DistanceFrom(Tile) >= 6;
until (Result) or (anim = ANIM_PILLARS_FAIL);

while GetAnimation > -1 do ;
doWait(small);
WaitTillCameraStopsMoving;
Result := DistanceFrom(Tile) >= 6;

if Result then
begin
IncEx(bins[GetOrd(Pillars)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Pillars)].numPassed);
end;

if anim = ANIM_PILLARS_FAIL then
begin
doWait(mini);
Recover;
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;
end;

tries := tries + 1;
end;
end;

{ground-start, pad, pad, ground-finish-TILE}
function obsPad(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries, anim: integer;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

Click := TileToMM(RandomizeTile(Tile, 0, 0));
if (Click.x = -1) then
begin
Writeln('Could not pass the pressure pad obstacle');
end else
begin

Mouse(Click.x, Click.y, 3, 3, True);
if not WaitToMove(TIME_TO_MOVE) then continue;

Inc(bins[GetOrd(Pressure_Pad)].numAttempted);

timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at crossing the pressure pad, timer 1');
Break;
end;
anim := GetAnimation;
Result := GetMyPos = Tile;
until (Result) or (anim = ANIM_PRESSURE_PAD_FAIL);

while GetAnimation > -1 do ;
doWait(mini);

if Result then
begin
IncEx(bins[GetOrd(Pressure_Pad)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Pressure_Pad)].numPassed);
end;

if anim = ANIM_PRESSURE_PAD_FAIL then
begin
doWait(mini);
tries := -1;
Eat;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;

end;
tries := tries + 1;
end;
end;

{bars bars-tile bars
bars
bars}
//Swing-across Monkey bars
function obsBars(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries, anim: integer;
obj: TRSObject;
Pts: TPointArray;
Cols: TIntegerArray;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

obj := GetObjectAt(Tile, OBJECT_TYPE_INTERACTABLE);
if (obj.ID <> OBJ_MONKEY_BARS_CLICK_ID) then
begin
Writeln('failed to find the monkey bars');
end else
begin

click := TileToMS(Tile, 900);
if (click.x = -1) then
begin
WalkTo(Tile);
WaitTillCameraStopsMoving;
doWait(small);
click := TileToMS(Tile, 900);
end;

if (click.x > -1) then
begin

ColorToleranceSpeed(2);
SetColorspeed2Modifiers(autocolors[getOrd(Monkey_Bars)].HueMod, autocolors[getOrd(Monkey_Bars)].SatMod);
if FindColorsTolerance(Pts, autocolors[getOrd(Monkey_Bars)].BestColor, click.x-10, click.y-10, click.x+10, click.y+10, autocolors[getOrd(Monkey_Bars)].BestTolerance) then
begin
cols := GetColors(Pts);
FilterBadPoints(Pts, cols, getOrd(Monkey_Bars));
aDebugTPA(pts);
Click := GetBestPoint(Pts);
end;
ColorToleranceSpeed(1);

if RightClicky(click, ['wing', 'ing', 'wing-acro', 'g-a', 'cr', 'os', 'ss']) and WaitToMove(TIME_TO_MOVE) then
begin

Inc(bins[GetOrd(Monkey_Bars)].numAttempted);

timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME_LONG then
begin
Writeln('failed at crossing the monkey bars, timer 1');
Break;
end;
anim := GetAnimation;
Result := DistanceFrom(Tile) >= 8;
until (Result) or (anim = ANIM_MONKEY_BARS_FAIL);

while GetAnimation > -1 do ;
doWait(small);

if Result then
begin
IncEx(bins[GetOrd(Monkey_Bars)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Monkey_Bars)].numPassed);
end;

if anim = ANIM_MONKEY_BARS_FAIL then
begin
Recover;
tries := -1;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
if Length(Pts) > 0 then
setNewBestColTol(Cols, GetOrd(Monkey_Bars));
end;
end;
end;
end;

tries := tries + 1;
end;
if Result then
begin
//doWait(small);
if (Length(Pts) > 0) then
setNewBestColTol(Cols, GetOrd(Monkey_Bars));
end;
end;

{ground-start interact interact ground-finish - TILE}
function obsDarts(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries, anim: integer;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

Click := TileToMM(RandomizeTile(Tile, 0, 0));
if (Click.x = -1) then
begin
Writeln('Could not pass the poison darts obstacle');
end else
begin

Mouse(Click.x, Click.y, 3, 3, True);
if not WaitToMove(TIME_TO_MOVE) then continue;

Inc(bins[GetOrd(Poison_Darts)].numAttempted);

timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at crossing the poison darts, timer 1');
Break;
end;
anim := GetAnimation;
Result := GetMyPos = Tile;
until (Result) or (anim = ANIM_POISON_DARTS_FAIL);

while GetAnimation > -1 do ;
doWait(small);


if Result then
begin
WaitTillCameraStopsMoving;
IncEx(bins[GetOrd(Poison_Darts)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Poison_Darts)].numPassed);
end;

if anim = ANIM_POISON_DARTS_FAIL then
begin
tries := -1;
Eat;
if (Target_Node <> getTargetNode(Current_Node.y, Current_Node.x)) or
(R_GetSkillLevel(Skill_Agility) < 40) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;

end;
tries := tries + 1;
end;
end;

{ blade
ground-start interact interact interact ground-finish-TILE}
function obsSpinningBlade(Tile: TTile): Boolean;
var
click: TPoint;
timer, tries, anim: integer;
begin
while (not(Result)) and (tries < NUM_TRIES + 1) do
begin
Result := False;

Click := TileToMM(RandomizeTile(Tile, 0, 0));
if (Click.x = -1) then
begin
Writeln('Could not pass the spinning blade obstacle');
end else
begin

//WalkToTile(Tile, 0, 0);
Mouse(Click.x, Click.y, 3, 3, True);
if not WaitToMove(TIME_TO_MOVE) then continue;

Inc(bins[GetOrd(Spinning_Blade)].numAttempted);

timer := GetSystemTime;
repeat
if (GetSystemTime - timer) > BREAK_TIME then
begin
Writeln('failed at crossing the spinning blades, timer 1');
Break;
end;
anim := GetAnimation;
Result := GetMyPos = Tile;
until (Result) or (anim = ANIM_SPINNING_BLADES_FAIL);
write('spnning blade tiles:'+tostr(getmypos)+'~'+tostr(tile));

while GetAnimation > -1 do ;
doWait(small);

if Result then
begin
IncEx(bins[GetOrd(Spinning_Blade)].totalTime, GetSystemTime - timer);
Inc(bins[GetOrd(Spinning_Blade)].numPassed);
end;

if anim = ANIM_SPINNING_BLADES_FAIL then
begin
tries := -1;
Eat;
if Target_Node <> getTargetNode(Current_Node.y, Current_Node.x) then
begin
Current_Node.x := -1;
Result := True;
Exit;
end;
end;

end;
tries := tries + 1;
end;
end;

function obsNone(Tile: TTile): Boolean;
begin
Result := False;
Writeln('This function shouldn''t be called');
Writeln('YOU FUCKED UP');
TerminateScript;
end;

////////////////////////////////////////////////////////////////////////////////
//PATH

function CalculateGScore(obstacle: obstacle): Integer;
var
avgTime, percFail: Extended;
begin
if Use_Primitive_G_Score then
begin
Result := bins[GetOrd(obstacle)].Danger;
Exit;
end;

//numFailed div numAttempted
percFail := (bins[GetOrd(obstacle)].numAttempted-bins[GetOrd(obstacle)].numPassed)*1.0 / bins[GetOrd(obstacle)].numAttempted;
//write('percFail:'+tostr(percfail));
avgTime := bins[GetOrd(obstacle)].totalTime*1.0 / bins[GetOrd(obstacle)].numPassed;
//write('avgTime:'+tostr(Avgtime));
//to seconds
Result := Round((avgTime * (percFail+1.0))); // / 1000);
end;

procedure InvertTIA2(a: TIntegerArray);
var
i, j, L, tmp: Integer;
begin
L := Length(a);
if L < 1 then Exit;
j := L-1;
for i := 0 to L/2 do
begin
tmp := a[i];
a[i] := a[j];
a[j] := tmp;
Dec(j);
end;
end;

function Dijkstra(source, dest: TPoint): TIntegerArray;
var
dist, previous: array[0..4] of array[0..4] of Integer;
y, x, Hi, Index, alt, agi: integer;
Q: TPointArray;
u, v: TPoint;
begin
// Initializations
for y := 0 to 4 do
for x := 0 to 4 do
begin
dist[y][x] := 90000001; // Unknown distance function from source to v
previous[y][x] := -1; // Previous node in optimal path from source
end;
dist[source.y][source.x] := 0; // Distance from source to source

agi := R_GetSkillLevel(Skill_Agility);
// All nodes in the graph are unoptimized - thus are not in Q
Hi := High(Q);
u := source;
while Hi < 24 do // The main loop
begin

if (dist[u.y][u.x] = -1) then
Break;
//writeln(u);

//for each neighbor v of u: where v has not yet been added to Q.
// Relax (u,v,a)
//N
v := Point(u.x, u.y-1);
if (v.y >= 0) and (not(PointInTPA(v, Q))) and
(agi >= map[u.y][u.x][DIR_NORTH].Level) then
begin
alt := dist[u.y][u.x] + CalculateGScore(map[u.y][u.x][DIR_NORTH].Name);
if (alt < dist[v.y][v.x]) then
begin
dist[v.y][v.x] := alt;
previous[v.y][v.x] := DIR_NORTH;
end;
end;

//E
v := Point(u.x+1, u.y);
if (v.x <= 4) and (not(PointInTPA(v, Q))) and
(agi >= map[u.y][u.x][DIR_EAST].Level) then
begin
alt := dist[u.y][u.x] + CalculateGScore(map[u.y][u.x][DIR_EAST].Name);
if (alt < dist[v.y][v.x]) then
begin
dist[v.y][v.x] := alt;
previous[v.y][v.x] := DIR_EAST;
end;
end;

//S
v := Point(u.x, u.y+1);
if (v.y <= 4) and (not(PointInTPA(v, Q))) and
(agi >= map[u.y][u.x][DIR_SOUTH].Level) then
begin
alt := dist[u.y][u.x] + CalculateGScore(map[u.y][u.x][DIR_SOUTH].Name);
if (alt < dist[v.y][v.x]) then
begin
dist[v.y][v.x] := alt;
previous[v.y][v.x] := DIR_SOUTH;
end;
end;

//W
v := Point(u.x-1, u.y);
if (v.x >= 0) and (not(PointInTPA(v, Q))) and
(agi >= map[u.y][u.x][DIR_WEST].Level) then
begin
alt := dist[u.y][u.x] + CalculateGScore(map[u.y][u.x][DIR_WEST].Name);
if (alt < dist[v.y][v.x]) then
begin
dist[v.y][v.x] := alt;
previous[v.y][v.x] := DIR_WEST;
end;
end;

//add u to Q
Inc(Hi);
//if (u = dest) then
//Break;
SetLength(Q, Hi+1);
Q[Hi] := u;

u := Point(-1, -1); //u := vertex not in Q with smallest dist
for x := 0 to 4 do
for y := 0 to 4 do
if not PointInTPA(Point(x, y), Q) then
if (u.x = -1) or (dist[y][x] < dist[u.y][u.x]) then
begin
u := Point(x, y);
end;
end;

u := dest;
SetLength(Result, Hi+1);
Index := 0;
CDebug('distances:'+tostr(dist));
while (previous[u.y][u.x] > -1) do
begin
//writeln('Result['+tostr(index)+'] := '+tostr(previous[u.y][u.x]));
Result[Index] := previous[u.y][u.x];
case Result[index] of
DIR_NORTH: Inc(u.y);
DIR_EAST: Dec(u.x);
DIR_SOUTH: Dec(u.y);
DIR_WEST: Inc(u.x);
end;

Inc(Index);
end;

SetLength(Result, Index);
InvertTIA2(Result);

//another way to think of it
{u := dest;
SetLength(Q, 0);
SetLength(Q, Hi+1);
Index := 0;
while (not(u = source)) do
begin
Q[Index] := previouss[u.y][u.x];
writeln(q[index]);
u := Q[Index];
Inc(Index);
end;
SetLength(Q, Index);
InvertTPA(Q);
Writeln(Q); }
end;

////////////////////////////////////////////////////////////////////////////////
//OBJECTIVE METHODS

//Tag Ticket Dispenser
function GrabTicket: Boolean;
var
Pillar: TRSObjectArray;
OldStatus, Timer: Integer;
Click: TPoint;
begin
Result := False;

Pillar := GetObjectsByID([OBJ_TICKET_DISPENSER_DARTS_ID, OBJ_TICKET_DISPENSER_ID], OBJECT_TYPE_INTERACTABLE, OBJ_SEARCH_DISTANCE);
Click := TileToMS(Pillar[0].Tile, 40);
if (Click.x = -1) then
begin
WalkTo(Pillar[0].Tile);
WaitTillCameraStopsMoving;
Click := TileToMS(Pillar[0].Tile, 40);
end;

OldStatus := GetTicketStatus;
if (OldStatus = TICKET_STATUS_NONE) or (OldStatus = TICKET_STATUS_PENDING) then
begin
Timer := GetSystemTime;
if (Clicky(Click, ['ag', 'Tag'])) then
begin
while GetTicketStatus = OldStatus do
if GetSystemTime - Timer > 4000 then
Exit;
if (GetTicketStatus = TICKET_STATUS_GOT_TICKET) then
begin
Inc(Players[CurrentPlayer].Integers[0]);
Result := True;
end;
end;
end;
end;

///////////////////////////////////////////////////////////////////////////////
//INI/STATS

procedure defaultStats;
begin
SetLength(bins, 14);
//90% success rate, 7 seconds
bins[getOrd(Balancing_Ledge)].numAttempted := 10;
bins[getOrd(Balancing_Ledge)].numPassed := 9;
bins[getOrd(Balancing_Ledge)].totalTime := 63000;
bins[getOrd(Balancing_Ledge)].Danger := 2;

//90% success rate, 7 seconds
bins[getOrd(Log_Balance)].numAttempted := 10;
bins[getOrd(Log_Balance)].numPassed := 9;
bins[getOrd(Log_Balance)].totalTime := 63000;
bins[getOrd(Log_Balance)].Danger := 1;

//60% success rate, 3 seconds
bins[getOrd(Rope_Swing)].numAttempted := 10;
bins[getOrd(Rope_Swing)].numPassed := 6;
bins[getOrd(Rope_Swing)].totalTime := 18000;
bins[getOrd(Rope_Swing)].Danger := 2;

//30% success rate, 8 seconds
bins[getOrd(Hand_Holds)].numAttempted := 10;
bins[getOrd(Hand_Holds)].numPassed := 3;
bins[getOrd(Hand_Holds)].totalTime := 24000;
bins[getOrd(Hand_Holds)].Danger := 4;

//100% success rate, 9 seconds
bins[getOrd(Planks)].numAttempted := 10;
bins[getOrd(Planks)].numPassed := 10;
bins[getOrd(Planks)].totalTime := 90000;
bins[getOrd(Planks)].Danger := 1;

//60% success rate, 9 seconds
bins[getOrd(Pillars)].numAttempted := 10;
bins[getOrd(Pillars)].numPassed := 6;
bins[getOrd(Pillars)].totalTime := 54000;
bins[getOrd(Pillars)].Danger := 2;

//50% success rate, 4 seconds
bins[getOrd(Floor_Spikes)].numAttempted := 10;
bins[getOrd(Floor_Spikes)].numPassed := 5;
bins[getOrd(Floor_Spikes)].totalTime := 20000;
bins[getOrd(Floor_Spikes)].Danger := 2;

//90% success rate, 7 seconds
bins[getOrd(Balancing_Rope)].numAttempted := 10;
bins[getOrd(Balancing_Rope)].numPassed := 9;
bins[getOrd(Balancing_Rope)].totalTime := 63000;
bins[getOrd(Balancing_Rope)].Danger := 1;

//40% success rate, 4 seconds
bins[getOrd(Pressure_Pad)].numAttempted := 10;
bins[getOrd(Pressure_Pad)].numPassed := 4;
bins[getOrd(Pressure_Pad)].totalTime := 16000;
bins[getOrd(Pressure_Pad)].Danger := 2;

//60% success rate, 7 seconds
bins[getOrd(Monkey_Bars)].numAttempted := 10;
bins[getOrd(Monkey_Bars)].numPassed := 6;
bins[getOrd(Monkey_Bars)].totalTime := 42000;
bins[getOrd(Monkey_Bars)].Danger := 1;

//100% success rate, 5 seconds
bins[getOrd(Low_Wall)].numAttempted := 10;
bins[getOrd(Low_Wall)].numPassed := 10;
bins[getOrd(Low_Wall)].totalTime := 50000;
bins[getOrd(Low_Wall)].Danger := 1;

//20% success rate, 3 seconds
bins[getOrd(Poison_Darts)].numAttempted := 10;
bins[getOrd(Poison_Darts)].numPassed := 2;
bins[getOrd(Poison_Darts)].totalTime := 6000;
bins[getOrd(Poison_Darts)].Danger := 4;

//30% success rate, 3 seconds
bins[getOrd(Spinning_Blade)].numAttempted := 10;
bins[getOrd(Spinning_Blade)].numPassed := 3;
bins[getOrd(Spinning_Blade)].totalTime := 9000;
bins[getOrd(Spinning_Blade)].Danger := 3;

//5 seconds, 0% fail
bins[getOrd(Blade)].numAttempted := 10;
bins[getOrd(Blade)].numPassed := 10;
bins[getOrd(Blade)].totalTime := 50000;
bins[getOrd(Blade)].Danger := 1;
end;

procedure _loadStats;
begin
SetLength(bins, 14);
if FileExists(INI_Path) then
begin

bins[getOrd(Balancing_Ledge)].numAttempted := StrToIntDef(ReadINI('Balancing_Ledge', 'numAttempted', INI_Path), 0);
bins[getOrd(Balancing_Ledge)].numPassed := StrToIntDef(ReadINI('Balancing_Ledge', 'numPassed', INI_Path), 0);
bins[getOrd(Balancing_Ledge)].totalTime := StrToIntDef(ReadINI('Balancing_Ledge', 'totalTime', INI_Path), 0);
bins[getOrd(Balancing_Ledge)].Danger := StrToIntDef(ReadINI('Balancing_Ledge', 'Danger', INI_Path), 0);

bins[getOrd(Log_Balance)].numAttempted := StrToIntDef(ReadINI('Log_Balance', 'numAttempted', INI_Path), 0);
bins[getOrd(Log_Balance)].numPassed := StrToIntDef(ReadINI('Log_Balance', 'numPassed', INI_Path), 0);
bins[getOrd(Log_Balance)].totalTime := StrToIntDef(ReadINI('Log_Balance', 'totalTime', INI_Path), 0);
bins[getOrd(Log_Balance)].Danger := StrToIntDef(ReadINI('Log_Balance', 'Danger', INI_Path), 0);

bins[getOrd(Rope_Swing)].numAttempted := StrToIntDef(ReadINI('Rope_Swing', 'numAttempted', INI_Path), 0);
bins[getOrd(Rope_Swing)].numPassed := StrToIntDef(ReadINI('Rope_Swing', 'numPassed', INI_Path), 0);
bins[getOrd(Rope_Swing)].totalTime := StrToIntDef(ReadINI('Rope_Swing', 'totalTime', INI_Path), 0);
bins[getOrd(Rope_Swing)].Danger := StrToIntDef(ReadINI('Rope_Swing', 'Danger', INI_Path), 0);

bins[getOrd(Hand_Holds)].numAttempted := StrToIntDef(ReadINI('Hand_Holds', 'numAttempted', INI_Path), 0);
bins[getOrd(Hand_Holds)].numPassed := StrToIntDef(ReadINI('Hand_Holds', 'numPassed', INI_Path), 0);
bins[getOrd(Hand_Holds)].totalTime := StrToIntDef(ReadINI('Hand_Holds', 'totalTime', INI_Path), 0);
bins[getOrd(Hand_Holds)].Danger := StrToIntDef(ReadINI('Hand_Holds', 'Danger', INI_Path), 0);

bins[getOrd(Planks)].numAttempted := StrToIntDef(ReadINI('Planks', 'numAttempted', INI_Path), 0);
bins[getOrd(Planks)].numPassed := StrToIntDef(ReadINI('Planks', 'numPassed', INI_Path), 0);
bins[getOrd(Planks)].totalTime := StrToIntDef(ReadINI('Planks', 'totalTime', INI_Path), 0);
bins[getOrd(Planks)].Danger := StrToIntDef(ReadINI('Planks', 'Danger', INI_Path), 0);

bins[getOrd(Pillars)].numAttempted := StrToIntDef(ReadINI('Pillars', 'numAttempted', INI_Path), 0);
bins[getOrd(Pillars)].numPassed := StrToIntDef(ReadINI('Pillars', 'numPassed', INI_Path), 0);
bins[getOrd(Pillars)].totalTime := StrToIntDef(ReadINI('Pillars', 'totalTime', INI_Path), 0);
bins[getOrd(Pillars)].Danger := StrToIntDef(ReadINI('Pillars', 'Danger', INI_Path), 0);

bins[getOrd(Floor_Spikes)].numAttempted := StrToIntDef(ReadINI('Floor_Spikes', 'numAttempted', INI_Path), 0);
bins[getOrd(Floor_Spikes)].numPassed := StrToIntDef(ReadINI('Floor_Spikes', 'numPassed', INI_Path), 0);
bins[getOrd(Floor_Spikes)].totalTime :=StrToIntDef(ReadINI('Floor_Spikes', 'totalTime', INI_Path), 0);
bins[getOrd(Floor_Spikes)].Danger := StrToIntDef(ReadINI('Floor_Spikes', 'Danger', INI_Path), 0);

bins[getOrd(Balancing_Rope)].numAttempted := StrToIntDef(ReadINI('Balancing_Rope', 'numAttempted', INI_Path), 0);
bins[getOrd(Balancing_Rope)].numPassed := StrToIntDef(ReadINI('Balancing_Rope', 'numPassed', INI_Path), 0);
bins[getOrd(Balancing_Rope)].totalTime := StrToIntDef(ReadINI('Balancing_Rope', 'totalTime', INI_Path), 0);
bins[getOrd(Balancing_Rope)].Danger := StrToIntDef(ReadINI('Balancing_Rope', 'Danger', INI_Path), 0);

bins[getOrd(Pressure_Pad)].numAttempted := StrToIntDef(ReadINI('Pressure_Pad', 'numAttempted', INI_Path), 0);
bins[getOrd(Pressure_Pad)].numPassed := StrToIntDef(ReadINI('Pressure_Pad', 'numPassed', INI_Path), 0);
bins[getOrd(Pressure_Pad)].totalTime := StrToIntDef(ReadINI('Pressure_Pad', 'totalTime', INI_Path), 0);
bins[getOrd(Pressure_Pad)].Danger := StrToIntDef(ReadINI('Pressure_Pad', 'Danger', INI_Path), 0);

bins[getOrd(Monkey_Bars)].numAttempted := StrToIntDef(ReadINI('Monkey_Bars', 'numAttempted', INI_Path), 0);
bins[getOrd(Monkey_Bars)].numPassed := StrToIntDef(ReadINI('Monkey_Bars', 'numPassed', INI_Path), 0);
bins[getOrd(Monkey_Bars)].totalTime := StrToIntDef(ReadINI('Monkey_Bars', 'totalTime', INI_Path), 0);
bins[getOrd(Monkey_Bars)].Danger := StrToIntDef(ReadINI('Monkey_Bars', 'Danger', INI_Path), 0);

bins[getOrd(Low_Wall)].numAttempted := StrToIntDef(ReadINI('Low_Wall', 'numAttempted', INI_Path), 0);
bins[getOrd(Low_Wall)].numPassed := StrToIntDef(ReadINI('Low_Wall', 'numPassed', INI_Path), 0);
bins[getOrd(Low_Wall)].totalTime := StrToIntDef(ReadINI('Low_Wall', 'totalTime', INI_Path), 0);
bins[getOrd(Low_Wall)].Danger := StrToIntDef(ReadINI('Low_Wall', 'Danger', INI_Path), 0);

bins[getOrd(Poison_Darts)].numAttempted := StrToIntDef(ReadINI('Poison_Darts', 'numAttempted', INI_Path), 0);
bins[getOrd(Poison_Darts)].numPassed := StrToIntDef(ReadINI('Poison_Darts', 'numPassed', INI_Path), 0);
bins[getOrd(Poison_Darts)].totalTime := StrToIntDef(ReadINI('Poison_Darts', 'totalTime', INI_Path), 0);
bins[getOrd(Poison_Darts)].Danger := StrToIntDef(ReadINI('Poison_Darts', 'Danger', INI_Path), 0);

bins[getOrd(Spinning_Blade)].numAttempted := StrToIntDef(ReadINI('Spinning_Blade', 'numAttempted', INI_Path), 0);
bins[getOrd(Spinning_Blade)].numPassed := StrToIntDef(ReadINI('Spinning_Blade', 'numPassed', INI_Path), 0);
bins[getOrd(Spinning_Blade)].totalTime := StrToIntDef(ReadINI('Spinning_Blade', 'totalTime', INI_Path), 0);
bins[getOrd(Spinning_Blade)].Danger := StrToIntDef(ReadINI('Spinning_Blade', 'Danger', INI_Path), 0);

bins[getOrd(Blade)].numAttempted := StrToIntDef(ReadINI('Blade', 'numAttempted', INI_Path), 0);
bins[getOrd(Blade)].numPassed := StrToIntDef(ReadINI('Blade', 'numPassed', INI_Path), 0);
bins[getOrd(Blade)].totalTime := StrToIntDef(ReadINI('Blade', 'totalTime', INI_Path), 0);
bins[getOrd(Blade)].Danger := StrToIntDef(ReadINI('Blade', 'Danger', INI_Path), 0);
end else
defaultStats;

end;

procedure clearStats;
var
i: integer;
begin
for i := 0 to 13 do
begin
bins[i].numAttempted := 0;
bins[i].numPassed := 0;
bins[i].totalTime := 0;
bins[i].Danger := 0;
end;
end;

procedure saveStats;
begin
WriteINI('Balancing_Ledge', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Balancing_Ledge', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Balancing_Ledge', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Balancing_Ledge', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Log_Balance', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Log_Balance', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Log_Balance', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Log_Balance', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Rope_Swing', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Rope_Swing', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Rope_Swing', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Rope_Swing', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Hand_Holds', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Hand_Holds', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Hand_Holds', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Hand_Holds', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Planks', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Planks', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Planks', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Planks', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Pillars', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Pillars', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Pillars', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Pillars', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Floor_Spikes', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Floor_Spikes', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Floor_Spikes', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Floor_Spikes', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Balancing_Rope', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Balancing_Rope', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Balancing_Rope', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Balancing_Rope', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Pressure_Pad', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Pressure_Pad', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Pressure_Pad', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Pressure_Pad', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Monkey_Bars', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Monkey_Bars', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Monkey_Bars', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Monkey_Bars', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Low_Wall', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Low_Wall', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Low_Wall', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Low_Wall', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Poison_Darts', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Poison_Darts', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Poison_Darts', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Poison_Darts', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Spinning_Blade', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Spinning_Blade', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Spinning_Blade', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Spinning_Blade', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);

WriteINI('Blade', 'numAttempted', ToStr(bins[getOrd(Balancing_Ledge)].numAttempted), INI_Path);
WriteINI('Blade', 'numPassed', ToStr(bins[getOrd(Balancing_Ledge)].numPassed), INI_Path);
WriteINI('Blade', 'totalTime', ToStr(bins[getOrd(Balancing_Ledge)].totalTime), INI_Path);
WriteINI('Blade', 'Danger', ToStr(bins[getOrd(Balancing_Ledge)].Danger), INI_Path);
end;

////////////////////////////////////////////////////////////////////////////////
//MAIN
procedure _loadMap;
begin
SetLength(map, 5);

SetLength(map[0], 5);
map[0][0] := node(None, Balancing_Ledge, Blade, None);
map[0][1] := node(None, Low_Wall, Pressure_Pad, Balancing_Ledge);
map[0][2] := node(None, Hand_Holds, Balancing_Rope, Low_Wall);
map[0][3] := node(None, Planks, Log_Balance, Hand_Holds);
map[0][4] := node(None, None, Rope_Swing, Planks);

SetLength(map[1], 5);
map[1][0] := node(Blade, Log_Balance, Floor_Spikes, None);
map[1][1] := node(Pressure_Pad, Spinning_Blade, Monkey_Bars, Log_Balance);
map[1][2] := node(Balancing_Rope, Blade, Spinning_Blade, Spinning_Blade);
map[1][3] := node(Log_Balance, Pressure_Pad, Poison_Darts, Blade);
map[1][4] := node(Rope_Swing, None, Pillars, Pressure_Pad); //3608

SetLength(map[2], 5);
map[2][0] := node(Floor_Spikes, Rope_Swing, Hand_Holds, None);
map[2][1] := node(Monkey_Bars, Poison_Darts, Balancing_Rope, Rope_Swing);
map[2][2] := node(Spinning_Blade, Pillars, Low_Wall, Poison_Darts);
map[2][3] := node(Poison_Darts, Floor_Spikes, Monkey_Bars, Pillars);
map[2][4] := node(Pillars, None, Low_Wall, Floor_Spikes); //3608

SetLength(map[3], 5);
map[3][0] := node(Hand_Holds, Planks, Pillars, None);
map[3][1] := node(Balancing_Rope, Spinning_Blade, Floor_Spikes, Planks);
map[3][2] := node(Low_Wall, Poison_Darts, Blade, Spinning_Blade);
map[3][3] := node(Monkey_Bars, Pressure_Pad, Balancing_Rope, Poison_Darts);
map[3][4] := node(Low_Wall, None, Log_Balance, Pressure_Pad); //3608

SetLength(map[4], 5);
map[4][0] := node(Pillars, Balancing_Ledge, None, None);
map[4][1] := node(Floor_Spikes, Monkey_Bars, None, Balancing_Ledge);
map[4][2] := node(Blade, Hand_Holds, None, Monkey_Bars);
map[4][3] := node(Balancing_Rope, Balancing_Ledge, None, Hand_Holds);
map[4][4] := node(Log_Balance, None, None, Balancing_Ledge); //3608
end;

procedure _loadObstacles;
begin
SetLength(obstacles, 15);
obstacles[getOrd(Balancing_Ledge)] := obs(Balancing_Ledge, 1, 16, @obsLedge);
obstacles[getOrd(Log_Balance)] := obs(Log_Balance, 1, 12, @obsLog);
obstacles[getOrd(Rope_Swing)] := obs(Rope_Swing, 1, 20, @obsSwing);
obstacles[getOrd(Hand_Holds)] := obs(Hand_Holds, 20, 22, @obsHolds);
obstacles[getOrd(Planks)] := obs(Planks, 1, 6, @obsPlank);
obstacles[getOrd(Pillars)] := obs(Pillars, 1, 18, @obsPillars);
obstacles[getOrd(Floor_Spikes)] := obs(Floor_Spikes, 20, 24, @obsSpikes);
obstacles[getOrd(Balancing_Rope)] := obs(Balancing_Rope, 1, 10, @obsBalanceRope);
obstacles[getOrd(Pressure_Pad)] := obs(Pressure_Pad, 20, 26, @obsPad);
obstacles[getOrd(Monkey_Bars)] := obs(Monkey_Bars, 1, 14, @obsBars);
obstacles[getOrd(Low_Wall)] := obs(Low_Wall, 1, 8, @obsWall);
obstacles[getOrd(Poison_Darts)] := obs(Poison_Darts, 40, 30, @obsDarts);
obstacles[getOrd(Spinning_Blade)] := obs(Spinning_Blade, 40, 28, @obsSpinningBlade);
obstacles[getOrd(Blade)] := obs(Blade, 1, 0, @obsBlade);
obstacles[getOrd(None)] := obs(None, -1, -1, @obsNone);
end;

procedure _loadAutocolors;
begin
SetLength(autocolors, 16);
autocolors[15].BestColor := 2641247;//outline arrow
autocolors[15].HueMod := 0.29;
autocolors[15].SatMod := 2.41;
autocolors[15].BestTolerance := 2;

autocolors[getOrd(None)].BestColor := 930367; //climbing rope
autocolors[getOrd(None)].BestTolerance := 19;

autocolors[getOrd(Rope_Swing)].BestColor := 795688; //rope swing
autocolors[getOrd(Rope_Swing)].BestTolerance := 13;

autocolors[getOrd(Hand_Holds)].BestColor := 5599103;//holds
autocolors[getOrd(Hand_Holds)].BestTolerance := 6;
autocolors[getOrd(Hand_Holds)].HueMod := 0.08;
autocolors[getOrd(Hand_Holds)].SatMod := 0.13;

autocolors[getOrd(Balancing_Rope)].BestColor := 4808814; //balancing rope
autocolors[getOrd(Balancing_Rope)].BestTolerance := 13;
autocolors[getOrd(Balancing_Rope)].HueMod := 0.06;
autocolors[getOrd(Balancing_Rope)].SatMod := 0.11;

autocolors[getOrd(Log_Balance)].BestColor := 5994633;
autocolors[getOrd(Log_Balance)].BestTolerance := 15;
autocolors[getOrd(Log_Balance)].HueMod := 0.05;
autocolors[getOrd(Log_Balance)].SatMod := 0.19;

autocolors[getOrd(Monkey_Bars)].BestColor := 8161685;
autocolors[getOrd(Monkey_Bars)].BestTolerance := 15;
autocolors[getOrd(Monkey_Bars)].HueMod := 0.09;
autocolors[getOrd(Monkey_Bars)].SatMod := 0.30;
end;

procedure _loadTiles;
begin
//////////////////////////////////////////////////////
//FIRST ROW E->W
map[0][0][DIR_EAST].Tile := Tile(2764, 9590);
map[0][1][DIR_WEST].Tile := Tile(2769, 9590);

map[0][1][DIR_EAST].Tile := Tile(2777, 9590);//obsWall
map[0][2][DIR_WEST].Tile := Tile(2777, 9590);//unused in obsWall, but needed for getprojectedtile

map[0][2][DIR_EAST].Tile := Tile(2785, 9592); //holds, not center
map[0][3][DIR_WEST].Tile := Tile(2792, 9592);

map[0][3][DIR_EAST].Tile := Tile(2797, 9590);
map[0][4][DIR_WEST].Tile := Tile(2802, 9590);

/////////////////////////////////////////////////////
//FIRST ROW S->N
map[0][0][DIR_SOUTH].Tile := Tile(2761, 9586);//saw
map[1][0][DIR_NORTH].Tile := Tile(2761, 9583);

map[0][1][DIR_SOUTH].Tile := Tile(2772, 9583);//obsPad
map[1][1][DIR_NORTH].Tile := Tile(2772, 9586);

map[0][2][DIR_SOUTH].Tile := Tile(2783, 9588);
map[1][2][DIR_NORTH].Tile := Tile(2783, 9581);

map[0][3][DIR_SOUTH].Tile := Tile(2794, 9587);
map[1][3][DIR_NORTH].Tile := Tile(2794, 9582);

map[0][4][DIR_SOUTH].Tile := Tile(2806,9585); //swing, not center
map[1][4][DIR_NORTH].Tile := Tile(2804,9584);

//////////////////////////////////////////////////////
//SECOND ROW E->W
map[1][0][DIR_EAST].Tile := Tile(2764, 9579);
map[1][1][DIR_WEST].Tile := Tile(2769, 9579);

map[1][1][DIR_EAST].Tile := Tile(2780, 9579);//spinning blades
map[1][2][DIR_WEST].Tile := Tile(2776, 9579);

map[1][2][DIR_EAST].Tile := Tile(2787, 9579);
map[1][3][DIR_WEST].Tile := Tile(2790, 9579);

map[1][3][DIR_EAST].Tile := Tile(2801, 9579);//obsPad
map[1][4][DIR_WEST].Tile := Tile(2798, 9579);

////////////////////////////////////////////////////
//SECOND ROW S->N
map[1][0][DIR_SOUTH].Tile := Tile(2761, 9572);
map[2][0][DIR_NORTH].Tile := Tile(2761, 9575);

map[1][1][DIR_SOUTH].Tile := Tile(2772, 9577);
map[2][1][DIR_NORTH].Tile := Tile(2772, 9570);

map[1][2][DIR_SOUTH].Tile := Tile(2783, 9572);//spinning blades
map[2][2][DIR_NORTH].Tile := Tile(2783, 9576);

map[1][3][DIR_SOUTH].Tile := Tile(2794, 9572);//obsDarts
map[2][3][DIR_NORTH].Tile := Tile(2794, 9575);

map[1][4][DIR_SOUTH].Tile := Tile(2805, 9576);
map[2][4][DIR_NORTH].Tile := Tile(2805, 9571);

////////////////////////////////////////////////////
//THIRD ROW E->W
map[2][0][DIR_EAST].Tile := Tile(2766,9569);//swing, not aligned
map[2][1][DIR_WEST].Tile := Tile(2767,9567);

map[2][1][DIR_EAST].Tile := Tile(2779, 9568);//darts
map[2][2][DIR_WEST].Tile := Tile(2776, 9568);

map[2][2][DIR_EAST].Tile := Tile(2786, 9568);
map[2][3][DIR_WEST].Tile := Tile(2791, 9568);

map[2][3][DIR_EAST].Tile := Tile(2801, 9568);//spikes
map[2][4][DIR_WEST].Tile := Tile(2798, 9568);

///////////////////////////////////////////////////
//THIRD ROW S->N
map[2][0][DIR_SOUTH].Tile := Tile(2759, 9566-1);
map[3][0][DIR_NORTH].Tile := Tile(2759, 9559-1);

map[2][1][DIR_SOUTH].Tile := Tile(2772, 9566);
map[3][1][DIR_NORTH].Tile := Tile(2772, 9559);

map[2][2][DIR_SOUTH].Tile := Tile(2783, 9563);//LOW WALL
map[3][2][DIR_NORTH].Tile := Tile(2783, 9562);

map[2][3][DIR_SOUTH].Tile := Tile(2794, 9566);
map[3][3][DIR_NORTH].Tile := Tile(2794, 9559);

map[2][4][DIR_SOUTH].Tile := Tile(2805, 9563);//LOW WALL
map[3][4][DIR_NORTH].Tile := Tile(2805, 9562);

/////////////////////////////////////////////////////
//FOURTH ROW E->W
map[3][0][DIR_EAST].Tile := Tile(2764, 9557);
map[3][1][DIR_WEST].Tile := Tile(2769, 9557);

map[3][1][DIR_EAST].Tile := Tile(2780, 9557);//spinning blade
map[3][2][DIR_WEST].Tile := Tile(2776, 9557);

map[3][2][DIR_EAST].Tile := Tile(2790, 9557);//darts
map[3][3][DIR_WEST].Tile := Tile(2787, 9557);

map[3][3][DIR_EAST].Tile := Tile(2801, 9557);//pressure pad
map[3][4][DIR_WEST].Tile := Tile(2798, 9557);

////////////////////////////////////////////////////////
//FOURTH ROW S->N
map[3][0][DIR_SOUTH].Tile := Tile(2761, 9554);
map[4][0][DIR_NORTH].Tile := Tile(2761, 9549);

map[3][1][DIR_SOUTH].Tile := Tile(2772, 9551);
map[4][1][DIR_NORTH].Tile := Tile(2772, 9553);

map[3][2][DIR_SOUTH].Tile := Tile(2783, 9553);
map[4][2][DIR_NORTH].Tile := Tile(2783, 9550);

map[3][3][DIR_SOUTH].Tile := Tile(2794, 9555);
map[4][3][DIR_NORTH].Tile := Tile(2794, 9548);

map[3][4][DIR_SOUTH].Tile := Tile(2805, 9554);
map[4][4][DIR_NORTH].Tile := Tile(2805, 9549);

//////////////////////////////////////////////////////////
//FIFTH ROW E->W
map[4][0][DIR_EAST].Tile := Tile(2764, 9546);
map[4][1][DIR_WEST].Tile := Tile(2769, 9546);

map[4][1][DIR_EAST].Tile := Tile(2774, 9546);
map[4][2][DIR_WEST].Tile := Tile(2781, 9546);

map[4][2][DIR_EAST].Tile := Tile(2785, 9544);
map[4][3][DIR_WEST].Tile := Tile(2792, 9544);

map[4][3][DIR_EAST].Tile := Tile(2797, 9546);
map[4][4][DIR_WEST].Tile := Tile(2802, 9546);
end;

procedure _Load;
begin
_loadObstacles;
_loadAutocolors;
_loadMap;
_loadTiles;
//_loadStats;
defaultStats;
end;

procedure _Setup;
begin
Smart_Members := True;
Smart_Signed := True;
Smart_Server := SMART_WORLD;
SetupSRL;
SetupPlayers;
SetupReflectionEx(True);

_Load;
MouseSpeed := 40;
ColorToleranceSpeed(1);
AddOnTerminate('Progress');
end;

function isRSReady: Boolean;
begin
Result := RSReady and (GetColor(5, 5) > 0);
end;

procedure Progress;
var
i, Hi, h, m, s: integer;
tph: extended;
begin
Writeln('______________________________________________________');
Writeln(TheTime+' on '+TheDate(Date_Formal));
Writeln('Script ran for '+TimeRunning);
Hi := High(Players);
for i := 0 to Hi do
begin
ConvertTime(Players[i].Worked, h, m, s);
try
tph := Players[i].Integers[0]*1.0/(h*1.0 + m/60.0 + s/60.0/60.0);
// writeln(ToStr(Players[i].Integers[0]*1.0)+'/'+ToStr(h*1.0)+'+'+ToStr(m/60.0)+'+'+tostr(s/60.0/60));
except
tph := -1;
end;
Writeln(Players[i].Name+':'+ToStr(Players[i].Active)+':worked '+MSToTime(Players[i].Worked, Time_Formal)+
':got '+ToStr(Players[i].Integers[0])+' tickets:~'+ToStr(Round(tph))+' TPH:gained '+ToStr(Players[i].Integers[1])+' exp');
end;
Writeln('______________________________________________________');
end;

procedure MainLoop;
var
target, tmp: TPoint;
x, y, i, Hi, a, c, LastReport, ticketStatus, ConsecutiveObstacleFails: Integer;
Path: TIntegerArray;
begin
_Setup;

while not SmartEnabled do ;
while not isRSReady do ;

repeat
LogInPlayer;
Wait(5000);
ClickNorth(True);
SetRun(True);
LastReport := GetSystemTime;

//DECLARE AS X,Y
//ACCESS AS Y,X
tmp := GetCurrNode;
y := tmp.y;
x := tmp.x;

repeat
a := GetSystemTime;
ticketStatus := GetTicketStatus;
if (ticketStatus = TICKET_STATUS_GOT_TICKET) or (ticketStatus = TICKET_STATUS_FIRST) then
begin
while (ticketStatus = TICKET_STATUS_GOT_TICKET) or (ticketStatus = TICKET_STATUS_FIRST) do
begin
Wait(100);
if GetSystemTime - a > 70000 then
begin
Writeln('Something went wrong after getting tickets, continuing anyway..');
Break;
end;
ticketStatus := GetTicketStatus;
end;
Wait(500); //time for arrow to move
end;

Writeln('Starting from: '+tostr(Point(y, x)));

target := getTargetNode(y, x);
if target.x = -1 then
begin
c := c + 1;
if (c = 1) then
begin
Writeln('Failed getting our target node, trying to follow previous path.');
end else
if (c mod 3) = 0 then
begin
Writeln('Failed getting our target node, doing a random obstacle.');
Path := [Random(4)];
while (map[y][x][Path[0]].Name = None) do
Path := [Random(4)];
end else
if c > 15 then
begin
Writeln('Failed getting our target node after 15 tries, terminating.');
TerminateScript;
end else
begin
Writeln('Failed getting our target node, waiting for 5 seconds...');
Wait(5000);
Continue;
end;
end else
begin
c := 0;
Writeln('Going to: '+tostr(point(target.y, target.x)));//look

Path := Dijkstra(Point(x, y), target);
Writeln('Using path: '+tostr(Path));
Writeln('');
end;

if (getTargetNode(y, x) = target) then
begin
Hi := High(Path);
for i := 0 to Hi do
begin
Current_Node := Point(x, y);
Target_Node := target;

Inc(ConsecutiveObstacleFails);
if not map[y][x][Path[i]].doObstacle(map[y][x][Path[i]].Tile) then
begin
tmp := GetCurrNode;
y := tmp.y;
x := tmp.x;
Writeln('Failed obstacle '+ToStr(ConsecutiveObstacleFails)+' time, resetting path to try again');
if ConsecutiveObstacleFails > 5 then
begin
Writeln('Failed obstacle 6 times, setting player to false.');
Players[CurrentPlayer].Active := False;
end;
Break;
end;
if Current_Node.x = -1 then Break;
IncEx(Players[CurrentPlayer].Integers[1], map[y][x][Path[i]].exp);
ConsecutiveObstacleFails := 0;

case Path[i] of
DIR_NORTH: Dec(y);
DIR_EAST: Inc(x);
DIR_SOUTH: Inc(y);
DIR_WEST: Dec(x);
end;

tmp := getTargetNode(y, x);
if (tmp <> target) then
begin
target := tmp;
Break;
end;
end;
end;

tmp := GetLocalMMArrowPoint;
if (tmp.x > -1) and (Distance(tmp.x, tmp.y, MMCX, MMCY) < 35) then
begin
GrabTicket;
end;

//a lot of updates for accurate progress report
Players[CurrentPlayer].Worked := Players[CurrentPlayer].Worked + (GetSystemTime - PlayerStartTime);
PlayerStartTime := GetSystemTime;
if (GetSystemTime - LastReport > 60*1000*TIME_INBETWEEN_PROGGIES) then
begin
Progress;
LastReport := GetSystemTime;
end;

until not Players[CurrentPlayer].Active;
Progress;
Logout;
Inc(CurrentPlayer);
until AllPlayersInactive;
end;

procedure DumpObjects;
var
file1, i, j: integer;
objs: TRSObjectArray;
aTile: TTile;
aPt: TPoint;
begin
file1 := RewriteFile('C:\Users\Tom\Desktop\Simba\Scripts\Brimhaven Agility\debug.txt', true);

for i := 0 to 3 do
begin
objs := GetAllObjects(i);
for j := 0 to high(objs) do
begin
WriteFileString(file1, 'id:'+inttostr(objs[j].ID)+'');
WriteFileString(file1, 'type:'+inttostr(objs[j].objType)+'');
atile := objs[j].Tile;
apt := TileToPoint(atile);
WriteFileString(file1, 'tile:'+inttostr(apt.x)+','+inttostr(apt.y)+'');
WriteFileString(file1, ' ');
end;
end;
CloseFile(file1);
end;

procedure LoopAllObstacles;
var
y, x: integer;
begin
_Setup;
while not isRSReady do ;
LogInPlayer;
Wait(5000);
ClickNorth(True);

//horiz
for y := 4 to 4 do
begin
for x := 0 to 3 do
if not map[y][x][DIR_EAST].doObstacle(map[y][x][DIR_EAST].Tile) then Exit;
for x := 4 downto 1 do
if not map[y][x][DIR_WEST].doObstacle(map[y][x][DIR_WEST].Tile) then Exit;

if (y < 4) then
if not map[y][x][DIR_SOUTH].doObstacle(map[y][x][DIR_SOUTH].Tile) then Exit;
end;

//vert
for x := 0 to 4 do
begin
for y := 4 downto 1 do
if not map[y][x][DIR_NORTH].doObstacle(map[y][x][DIR_NORTH].Tile) then Exit;
for y := 0 to 3 do
if not map[y][x][DIR_SOUTH].doObstacle(map[y][x][DIR_SOUTH].Tile) then Exit;

if (x < 4) then
if not map[y][x][DIR_EAST].doObstacle(map[y][x][DIR_EAST].Tile) then Exit;
end;
end;

begin
MainLoop;
//LoopAllObstacles;
end.

HyperSecret

2010-09-20 07:04:15

Holy geez, nice username/password. The account is now mine, muhahaha, j/k.

So the reflection include needs things added to it or this script needs the reflection parts added to get it running?

What still needs to be done?

The Claw

2010-09-20 08:37:44


Holy geez, nice username/password. The account is now mine, muhahaha, j/k.


Fix'd in case JAD comes back.
Would be an epic script if it gets to a working state

Ps - can we ban JAD yet? lol

lordsaturn

2010-09-20 19:56:49

From: HyperSecret
Holy geez, nice username/password. The account is now mine, muhahaha, j/k.

So the reflection include needs things added to it or this script needs the reflection parts added to get it running?

What still needs to be done?


Yeah I tend to fail at that. Thanks for not stealing :)

So far I have hooked at least half of the hooks marked 'not updated' in the current hooks.simba file plus some extras. I got to hooking the interfaces and decided I needed to create a bcel refactorer to efficiently search for patterns in the class file which held the most amount of interface hooks (which honestly probably isn't the best place to look but requires the least amount of effort ) but I still want the refactorer for future use. Then some stuff came along and I hardly have an hour in the day to spare.

So to answer your question I need to hook the rest of the hooks that arent being hooked in hooks.simba :)

@claw, yeah i agree. I was pretty excited when I first got dijkstra working

Edit: has any one been able to figure out with confidence what this is yet?

Method

2010-09-20 21:05:27

From: lordsaturn
Edit: has any one been able to figure out with confidence what this is yet?


What are you referring to when you say "this"?

lordsaturn

2010-09-20 21:37:05

From: Method
What are you referring to when you say "this"?


the script. I forgot I put the name of the script in the thread title. So I was wondering if people knew what it was.

lordsaturn

2010-11-26 14:02:16

Hey guys, I can finish this now. but I really do need a members account to use, preferably with a decent agility level.

BraK

2010-11-26 16:49:01

From: lordsaturn
Hey guys, I can finish this now. but I really do need a members account to use, preferably with a decent agility level.


I got one for you I'll PM you it in a few.

~BraK

E: Has around 60 Agility I think. Let me know when Your Done with it.

lordsaturn

2010-12-05 15:05:22

Major update, thanks Brak!

It works now, you can run it. The only thing left to do is work out the distance between nodes for dijkstra's. Right now it uses a predefined distance based on the difficulty of the obstacle. Sooner or later it will be dynamic taking into account the time it takes to complete the obstacle and the chance your character has of failing it.

BraK

2010-12-05 15:47:25

Wow that sounds outstanding. I logged in once or twice and saw him moved around the dungeon. Glad I could help with this project.

~BraK

HyperSecret

2010-12-05 17:26:18

Looks awesome man, my agility sucks. I want to give this a try though.

lordsaturn

2010-12-06 07:28:18

______________________________________________________
06:28:23 AM on December 6th, 2010
Script ran for 1 Hours, 34 Minutes and 44 Seconds
****** ****:True:worked 1 Hours, 34 Minutes and 37 Seconds:got 69 tickets:~44 TPH:gained 5352 exp
______________________________________________________

Fixd multiplayer, added progress report. Many bugfixes. It now tries very hard to get unstuck.