Smartzkid
2009-05-06 09:11:54
This is a 'hot-pluggable' framework for finding a character's location. User-written location detectors are 'registered' with the framework. One function call will go through all registered location detectors, returning the first to return positive. So that it doesn't get bogged down, it automatically sorts individual location detectors by speed, running the fastest ones first. Future advancements will allow for only a few 'essential' detectors (such as lumbridge center) and the detectors located in one city (or for one skill) to be turned on at once. This will further increase the speed and robustness of this framework.
Please note that this framework is still in beta and has great room for optimizations. Also realize that all location detectors must be written by users; this is no magical bean stalk that can survive without others' contributions. I'd also like to point out that once this project reaches functional maturity, it will be relatively painless to extend into a walkable lattice of location nodes.
Included:
-LocationsTestScript.scar: A script I whipped up solely to make sure everything works how it should. Messy code, I apologize.
-Locations.scar: The actual framework. Includes a generic detector function at the end. Should be placed in includes folder.
I plan on commenting the framework soon, and optimizing it afterward. Questions and comments greatly appreciated - particularly on the first 30 lines; ie the SignificanceList and the LocationInfo data structures.
Coming soon:
-Removing locators
-Enabling and disabling locators (both individually and by city, etc)
-'Significance' field - I just have to figure out a proper name for it :p
-One locator triggering other locators
-Might move the searching/sorting into a separate function (ease of optimization)
In the future:
-Some sort of general-area locator that would trigger more specific locators
-A way to relate the positions of specific locators
LocationsTestScript.scar
Locations.scar:
Please note that this framework is still in beta and has great room for optimizations. Also realize that all location detectors must be written by users; this is no magical bean stalk that can survive without others' contributions. I'd also like to point out that once this project reaches functional maturity, it will be relatively painless to extend into a walkable lattice of location nodes.
Included:
-LocationsTestScript.scar: A script I whipped up solely to make sure everything works how it should. Messy code, I apologize.
-Locations.scar: The actual framework. Includes a generic detector function at the end. Should be placed in includes folder.
I plan on commenting the framework soon, and optimizing it afterward. Questions and comments greatly appreciated - particularly on the first 30 lines; ie the SignificanceList and the LocationInfo data structures.
Coming soon:
-Removing locators
-Enabling and disabling locators (both individually and by city, etc)
-'Significance' field - I just have to figure out a proper name for it :p
-One locator triggering other locators
-Might move the searching/sorting into a separate function (ease of optimization)
In the future:
-Some sort of general-area locator that would trigger more specific locators
-A way to relate the positions of specific locators
LocationsTestScript.scar
program New;
{.include SRL/SRL.scar}
{.include Locations.scar}
function AtGE (getInfo: boolean; var info: LocationInfo): Boolean;
var
x, y: integer;
begin
if(getInfo) then
with info do
begin
Name := 'Grand Exchange';
LegacyName := LEGACY.GE;
City := CITIES.Varrock;
// Significance := SIGNIFICANCE.GrandExchange;
FunctionName := 'AtGE';
Members := false;
Exit;
end;
if(FindSymbol(x, y, 'bank'))then
result := true;
writeln('fast');
end;
function LumbridgeCenter (getInfo: boolean; var info: LocationInfo): Boolean;
var
WaterSymbols: TPointArray;
TempAngle: extended;
i, j, CompassAngle, dx, dy, pieces, ArrayHigh: integer;
begin
if(getInfo) then
with info do
begin
Name := 'Lumbridge Center';
City := CITIES.Lumbridge;
// Significance := SIGNIFICANCE.GrandExchange;
FunctionName := 'LumbridgeCenter';
Members := false;
Exit;
end;
result := false;
CompassAngle := round(360 - rs_GetCompassAngleDegrees);
CompassAngle := CompassAngle mod 180;
FindSymbols(WaterSymbols, 'water');
// SortTPAFrom(WaterSymbols, Point(MMCX, MMCY));
ArrayHigh := high(WaterSymbols);
if(ArrayHigh = 3) then
inc(pieces);
if(ArrayHigh = 4) then //Because quest icon often gets counted as water symbol
inc(pieces);
if(FindSymbol(dx, dy, 'quest')) then
inc(pieces);
if(ArrayHigh >= 1) then
for i := 0 to ArrayHigh do
for j := i + 1 to ArrayHigh do
begin
dx := WaterSymbols[i].x - WaterSymbols[j].x;
dy := WaterSymbols[i].y - WaterSymbols[j].y;
if(dx = 0) then
dx := 1;
TempAngle := round(90 + Degrees(ArcTan(dy/dx)));
TempAngle := TempAngle + CompassAngle;
if((abs(TempAngle - 180) < 15) or (abs(TempAngle) < 10))then
if(abs(Distance(0, 0, dx, dy) - 60) < 7) then
IncEx(pieces, 3);
end;
writeln(inttostr(pieces));
if(pieces > 4) then
result := true;
Writeln('Middle-fast');
end;
function Wait2000 (getInfo: boolean; var info: LocationInfo): Boolean;
var
x, y: integer;
begin
if(getInfo) then
with info do
begin
Name := 'Slowest';
FunctionName := 'Wait2000';
Members := false;
Exit;
end;
wait(2000);
writeln('Slowest');
end;
function Fastest (getInfo: boolean; var info: LocationInfo): Boolean;
var
x, y: integer;
begin
if(getInfo) then
with info do
begin
Name := 'Fastest';
FunctionName := 'Fastest';
Members := false;
Exit;
end;
writeln('Fastest');
end;
procedure RegisterLocators;
begin
registerLocator(@AtGE);
registerLocator(@LumbridgeCenter);
registerLocator(@Fastest);
registerLocator(@Wait2000);
end;
var
currentLocation: LocationInfo;
begin
SetupSRL;
RegisterLocators;
cleardebug;
// getLocation.FunctionName; //'Line 176: [Error] (16933:25): Internal error (20) in script '
currentLocation := getLocation;
writeln(currentLocation.Name);
writeln(currentLocation.City.Name);
end.Locations.scar:
type TCity = record
Name: String;
ID: Integer;
end;
type TCityList = record
Lumbridge, Varrock, Falador, Draynor, AlKharid, Edgeville, BarbarianVillage,
Rimmington, PortSarim, Karajama: TCity;
end;
type TSignificanceList = record
Woodcutting, Fishing, Banking, Mining, Crafting, GeneralStore, SpecialStore,
TownCenter, WalkPoint, Fighting, GrandExchange: String;
end;
type TLegacyList = record
VEM, VEB, VWB, FEB, FWB, GE: String;
end;
type LocationInfo = record
City: TCity;
Name, Significance, LegacyName, FunctionName: String;
Members: Boolean;
end;
type LocatorFunction = Function(getInfo: boolean; var info: LocationInfo): Boolean;
var
LocationFinders: Array of LocatorFunction;
LocatorInformation: Array of LocationInfo;
Benchmarks: Array of Integer;
SpeedList: Array of Integer;
CITIES: TCityList;
SIGNIFICANCE: TSignificanceList;
LEGACY: TLegacyList;
LocationsInitialized: Boolean;
procedure SetupLocations;
begin
if(LocationsInitialized)then
Exit;
with CITIES do
begin
AlKharid.Name := 'Al Kharid';
AlKharid.ID := 1;
BarbarianVillage.Name := 'Barbarian Village';
BarbarianVillage.ID := 2;
Draynor.Name := 'Draynor';
Draynor.ID := 3;
Edgeville.Name := 'Edgeville';
Edgeville.ID := 4;
Falador.Name := 'Falador';
Falador.ID := 5;
Karajama.Name := 'Karajama';
Karajama.ID := 6;
Lumbridge.Name := 'Lumbridge';
Lumbridge.ID := 7;
PortSarim.Name := 'Port Sarim';
PortSarim.ID := 8;
Rimmington.Name := 'Rimmington';
Rimmington.ID := 9;
Varrock.Name := 'Varrock';
Varrock.ID := 10;
end;
with SIGNIFICANCE do
begin
Banking := 'Banking';
Crafting := 'Crafting';
Fighting := 'Fighting';
Fishing := 'Fishing';
GeneralStore := 'General Store';
GrandExchange := 'Grand Exchange';
Mining := 'Mining';
SpecialStore := 'Special Store';
TownCenter := 'Town Center';
Walkpoint := 'Walkpoint';
Woodcutting := 'Woodcutting';
end;
with LEGACY do
begin
FEB := 'FEB';
FWB := 'FWB';
GE := 'GE';
VEB := 'VEB';
VEM := 'VEM';
VWB := 'VWB';
end;
LocationsInitialized := true;
end;
function getLocation: LocationInfo;
var
i, j, k, bench: integer;
found: boolean;
begin
found := false;
for i := 0 to High(LocationFinders) do
for j := 0 to high(benchmarks) do
if(Benchmarks[SpeedList[i]] < Benchmarks[SpeedList[j]])then
begin
bench := SpeedList[i];
for k := i to high(benchmarks) - 1 do
SpeedList[k] := SpeedList[k + 1];
for k := high(benchmarks) downto j + 1 do
SpeedList[k] := SpeedList[k - 1];
SpeedList[k] := bench;
break;
end;
for i := 0 to High(LocationFinders) do
begin
bench := GetSystemTime;
if(LocationFinders[SpeedList[i]](false, result) = true)then
begin
found := true;
break;
end;
Benchmarks[SpeedList[i]] := GetSystemTime - bench;
end;
if(found) then
result := LocatorInformation[SpeedList[i]];
end;
procedure registerLocator(Locator: LocatorFunction);
var
LocatorInfo: LocationInfo;
ArrayLength: Integer;
begin
if(not(LocationsInitialized)) then
SetupLocations;
Locator(true, LocatorInfo);
ArrayLength := Length(LocationFinders);
SetLength(LocationFinders, ArrayLength + 1);
SetLength(LocatorInformation, ArrayLength + 1);
SetLength(Benchmarks, ArrayLength + 1);
SetLength(SpeedList, ArrayLength + 1);
LocationFinders[ArrayLength] := Locator;
LocatorInformation[ArrayLength] := LocatorInfo;
Benchmarks[ArrayLength] := -1;
SpeedList[ArrayLength] := ArrayLength;
end;
{function Generic (getInfo: boolean; var info: LocationInfo): Boolean;
//Locator template
begin
if(getInfo) then
with info do
begin
Name := '';
LegacyName := LEGACY.; //This field is for the 'traditional'/abbreviated name of a location
City := CITIES.; //City or nearest city
Significance := SIGNIFICANCE.; //What would one want to do at this location?
FunctionName := 'Generic'; //Name of this function
Members := false; //Is this location in a members-only area?
end;
//Location detection goes here
result := true;
end;}