SRL Archive - Unofficial Development

RS Bestiary API script [LaPe]


CynicRus

2013-10-20 12:56:37

Hello! Today I present you a script for getting the information about the RS monsters from RS Bestiary api. About Api you can read: http://services.runescape.com/m=rswiki/en/Bestiary_APIs This script is based on the my json helper library and works in the lape interpreter. With this you can always get fresh information about any RS Monster.

Requrements:
- Simba => 1.0;
- Lape

The script can be used as 'Include' for any combat scripts. This contains a test code to show how it works.

Just place json.simba into your Simba 'Include' directory and start the script.

- I wouldn't recommend getting info with this script in the loop because working with huge pieces of information can take a lot of time. Get the needed info while the script settings are being initialized.
json.simba:



//json helper library by Cynic

function CopyStop(const Str: string; const start: Integer; const Stop: Integer): string;
begin
Result := Copy(Str, Start, Stop - Start + 1);
end;

function DynArrayAppend(var V: TStringArray; const R: String): Integer; overload;
begin
Result := Length(V);
SetLength(V, Result + 1);
V[Result] := R;
end;

function DynArrayAppend(var V: TIntegerArray; const R: integer): Integer; overload;
begin
Result := Length(V);
SetLength(V, Result + 1);
V[Result] := R;
end;

function JSONEscapeDecode(const JSONData: string): string;
var
ptr: integer = 1;
moji_hex: string;
moji: string = '';
begin
Result := '';
repeat
while (ptr <= length(JSONData)) do
begin
if ptr > length(JSONData) then
Exit;
case JSONData[ptr] of
'\':
begin
if ptr >= length(JSONData) then
Exit;
inc(ptr);
case JSONData[ptr] of
'u':
begin
Inc(ptr);
Moji_Hex := '';
Moji_Hex := Uppercase(Copy(JSONData, ptr, 4));
Moji := '';
Moji := ('$' + Moji_Hex);
Result := Result + Moji;
Inc(ptr, 3);
end;
else
Result := Result + JSONData[ptr];
end;
end;
else
Result := Result + JSONData[ptr];
end;
Inc(ptr);
end;
until ptr >= length(JSONData);
end;

function JSONDataIsList(const JSONData: string): Boolean;
begin
Result := false;
if Length(Trim(JSONData)) = 0 then
exit;
if Trim(JSONData)[1] in ['{', '[', '('] then
Result := True;
end;

function JSONDataIsObject(const JSONData: string): Boolean;
begin
Result := false;
if Length(Trim(JSONData)) = 0 then
exit;
if Trim(JSONData)[1] in ['{'] then
Result := True;
end;

function JSONDataIsArray(const JSONData: string): Boolean;
begin
Result := false;
if Length(Trim(JSONData)) = 0 then
exit;
if Trim(JSONData)[1] in ['['] then
Result := True;
end;

function JSONDataIsNumber(const JSONData: string): Boolean;
var
IndexPOS: Integer;
begin
Result := false;
if Length(Trim(JSONData)) = 0 then
exit;
Result := True;
for IndexPos := 1 to Length(JSONData) do
if not (JSONData[IndexPos] in [' ', '.', 'e', 'E', '-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) then
begin
Result := False;
Exit;
end;
end;

function JSONDataIsString(const JSONData: string): Boolean;
begin
Result := false;
if Length(Trim(JSONData)) = 0 then
exit;
if Trim(JSONData)[1] in ['"'] then
Result := True;
end;

function JSONDataIsKeyValuePair(const JSONData: string): Boolean;
var
InputPos: Integer = 0;
SeparCount: Integer = 0;
InQuote: Boolean = False;
BraceLevel: Integer = 0;
begin
Result := false;
if Length(Trim(JSONData)) = 0 then
exit;
while (InputPOS < length(JSONData)) do
begin
Inc(InputPos);
case JSONData[InputPos] of
'"':
begin
if InputPos = 1 then
InQuote := not InQuote
else if JSONData[InputPos - 1] <> '\' then
InQuote := not InQuote;
end;
'{': Inc(BraceLevel);
'}': Dec(BraceLevel);
end;
if (not InQuote) and (BraceLevel = 0) then
if JSONData[InputPos] = ':' then
inc(SeparCount);
end;
Result := (SeparCount = 1);
end;

function JSON2TSA(const JSONString: AnsiString; var Decoded: TStringArray): Integer;
const
ListItemSep = ',';

var
Pos: Integer;
NestCount: Integer = 0;
CopyPos: Integer = 1;
TmpStr: string;
InQuote: Boolean = False;
begin
SetLength(Decoded,0);
{ if not JSONDataIsList(JSONString) then
begin
Result := - 1;
Exit;
end; }
for Pos := 1 to Length(JSONString) do
begin
case JSONString[Pos] of
'"':
begin
if pos = 1 then
InQuote := not InQuote
else if JSONString[Pos - 1] <> '\' then
InQuote := not InQuote;
end;
'(', '[', '{':
if not InQuote then
Inc(NestCount);
')', ']', '}':
if not InQuote then
begin
Dec(NestCount);
if NestCount = 0 then
begin
TmpStr := Trim(CopyStop(JSONString, CopyPos + 1, Pos - 1));
// WriteLn(TMPStr);
DynArrayAppend(Decoded,tmpstr);
CopyPos := Pos;
end;
end;
ListItemSep:
if not InQuote then
begin
if NestCount = 1 then
begin
TmpStr := Trim(CopyStop(JSONString, CopyPos + 1, Pos - 1));
// WriteLn(TMPStr);
DynArrayAppend(Decoded,tmpstr);
CopyPos := Pos;
end;
end;
end;
end;
Result := 0;
end;

function JSONGetValueByKey(const JSONList: TStringArray; const Key: string): string;
var
i: integer;
_Key: string;
Len: integer;
DelimiterPos: Integer;
begin
Result := '';
Len := Length(JSONList);
for i := 0 to Len - 1 do
begin
DelimiterPos := Pos(':', JSONList[i]);
if DelimiterPOS > 1 then
begin
_key := copy(JSONList[i], 1, DelimiterPOS - 1);
if _key = key then
begin
Result := CopyStop(JSONList[i], DelimiterPOS + 1, Length(JSONList[i]));
Exit;
end;
end;
end;
end;

function JSONTreeGet(const JSONString: string; const JSONPath: string): string;
var
InputPOS: Integer;
SimpleKeyStartPos: Integer;
ThisKey: string;
JSONList: TSTringArray;
begin
SetLength(JSONList, 1);
if Length(JSONPath) = 0 then
exit;
InputPOS := 0;
SimpleKeyStartPos := 0;
Result := JSONString;
repeat
Inc(InputPOS);
SimpleKeyStartPos := InputPos;
while (InputPOS < length(JSONPath)) and (JSONPath[InputPos] <> ':') do
Inc(InputPos);
if JSONPath[InputPos] <> ':' then
ThisKey := CopyStop(JSONPath, SimpleKeyStartPos, InputPos)
else
ThisKey := CopyStop(JSONPath, SimpleKeyStartPos, InputPos - 1);
if Length(ThisKey) = 0 then
Exit;
JSON2TSA(Result, JSONList);
Result := JSONGetValueByKey(JSONList, ThisKey);
until InputPOS >= Length(JSONPath);
end;

procedure JSONTreeGetMultiple(const JSONString: string; const JSONPath: string; var ValueList: TStringArray);
var
InputPOS: Integer;
SimpleKeyStartPos: Integer;
ThisKey: string;
JSONList: TStringArray;
tmpStr: string;
Found: Boolean;
begin
SetLEngth(JsonList, 1);
if Length(JSONPath) = 0 then
exit;
repeat
Found := false;
InputPOS := 0;
SimpleKeyStartPos := 0;
tmpStr := JSONString;
repeat
Inc(InputPOS);
SimpleKeyStartPos := InputPos;
while (InputPOS < length(JSONPath)) and (JSONPath[InputPos] <> ':') do
Inc(InputPos);
if JSONPath[InputPos] <> ':' then
ThisKey := CopyStop(JSONPath, SimpleKeyStartPos, InputPos)
else
ThisKey := CopyStop(JSONPath, SimpleKeyStartPos, InputPos - 1);
if Length(ThisKey) = 0 then
Exit;
JSON2TSA(tmpStr, JSONList);
tmpStr := JSONGetValueByKey(JSONList, ThisKey);
if (InputPOS = Length(JSONPath)) and (tmpstr <> '') then
begin
DynArrayAppend(ValueList,TmpStr);
tmpStr := '';
Found := True;
end;
until InputPOS >= Length(JSONPath);
until not Found;
end;

function JSONGetKey(const JSONData: string): string;
var
InputPos: integer = 0;
begin
if Length(JSONData) = 0 then
exit;
if JSONData[1] in ['{', '[', '('] then
exit;
while (InputPOS < length(JSONData)) and (JSONData[InputPos] <> ':') do
Inc(InputPos);
case JSONData[InputPos] of
':': Result := Trim(CopyStop(JSONData, 1, InputPos - 1))
else
Result := '';
end;
end;

function JSONGetValue(const JSONData: string): string;
var
InputPos: integer = 0;
begin
Result := 'not set';
if Length(JSONData) = 0 then
exit;
if JSONData[1] in ['{', '[', '('] then
exit;
while (InputPOS < length(JSONData)) and (JSONData[InputPos] <> ':') do
Inc(InputPos);
case JSONData[InputPos] of
':': Result := Trim(CopyStop(JSONData, InputPos + 1, Length(JSONData)))
else
Result := 'notfound';
end;
end;

function DeQuote(const input: string): string;
var
p: integer;
begin
result := input;
p := pos('"', result);
if p > 0 then
result := copy(result, p + 1, length(result) - p);
p := pos('"', result);
if p > 0 then
result := copy(result, 1, p - 1);
end;

function DeBracket(const input: string): string;
var
p: integer;
begin
result := input;
p := pos('[', result);
if p > 0 then
result := copy(result, p + 1, length(result) - p);
p := pos(']', result);
if p > 0 then
result := copy(result, 1, p - 1);
end;

function DeBrace(const input: string): string;
var
p: integer;
begin
result := input;
p := pos('{', result);
if p > 0 then
result := copy(result, p + 1, length(result) - p);
p := pos('}', result);
if p > 0 then
result := copy(result, 1, p - 1);
end;

function DeParen(const input: string): string;
var
p: integer;
begin
result := input;
p := pos('(', result);
if p > 0 then
result := copy(result, p + 1, length(result) - p);
p := pos(')', result);
if p > 0 then
result := copy(result, 1, p - 1);
end;


bestiary_api.simba:


program bestiary_api;

{$i json.simba}

type
TFindedMonsters = record
Names: TStringArray;
Ids: TIntegerArray;
end;

TMonster = record
xp: double;
name: string;
Life: integer;
lvl: integer;
SlayerCat: string;
Description: string;
Agressive,MembersOnly: boolean;
Areas: TStringArray;
end;
const
BeastSearchUrl = 'http://services.runescape.com/m=itemdb_rs/bestiary/beastSearch.json?term=';

function GetFormattedUrl(const ItemName: string):string;
begin
result:=Replace(ItemName,#32,'+',[rfReplaceAll, rfIgnoreCase]);
end;

function GetBeastSearchJson(const Name: string):string;
begin
result:=GetPage(BeastSearchUrl+GetFormattedUrl(name));
end;

function FindMonsters(const Beasts: string): TFindedMonsters;
var
i,Brace: integer;
page,value: string;
Json, Beast: TStringArray;
begin
SetLength(Result.Ids,0);
SetLength(Result.Names,0);

page:=GetBeastSearchJson(Beasts);

if JSONDataIsList(page) then
begin
Json2TSA(page,json);
for i:=0 to length(json) - 1 do
begin
Json2TSA(json[i],Beast);
if (Length(Beast) > 2) then
exit;
if JSONDataIsKeyValuePair(beast[0]) then
begin
DynArrayAppend(Result.Ids,StrToInt(DeQuote(JsonGetValue(beast[0]))));
Value:=DeQuote(JsonGetValue(beast[1]));
Brace:= Pos('(',Value);
Value:=CopyStop(Value,0,Brace-2);
if length(Value) > 0 then
DynArrayAppend(Result.Names,Value) else
DynArrayAppend(Result.Names,DeQuote(JsonGetValue(beast[1])));
end;
end;
end;

end;

function FindMonstersByABC(const ABC: char): TFindedMonsters;
const
URL = 'http://services.runescape.com/m=itemdb_rs/bestiary/bestiaryNames.json?letter=';
var
i,Brace: integer;
page,value: string;
Json, Beast: TStringArray;
begin
SetLength(Result.Ids,0);
SetLength(Result.Names,0);

page:=GetPage(URL+UpperCase(ABC));
if JSONDataIsList(page) then
begin
Json2TSA(page,json);
for i:=0 to length(json) - 1 do
begin
Json2TSA(json[i],Beast);
if (Length(Beast) > 2) then
exit;
if JSONDataIsKeyValuePair(beast[0]) then
begin
DynArrayAppend(Result.Ids,StrToInt(DeQuote(JsonGetValue(beast[0]))));
Value:=DeQuote(JsonGetValue(beast[1]));
Brace:= Pos('(',Value);
Value:=CopyStop(Value,0,Brace-2);
if length(Value) > 0 then
DynArrayAppend(Result.Names,Value) else
DynArrayAppend(Result.Names,DeQuote(JsonGetValue(beast[1])));
end;
end;
end;

end;

function FindMonstersByLvl(const StartLvl,EndLvl: integer): TFindedMonsters;
const
URL = 'http://services.runescape.com/m=itemdb_rs/bestiary/levelGroup.json?identifier=';
var
i,Brace: integer;
page,value: string;
Json, Beast: TStringArray;
begin
SetLength(Result.Ids,0);
SetLength(Result.Names,0);

page:=GetPage(URL+IntToStr(StartLvl)+'-'+IntToStr(EndLvl));
if JSONDataIsList(page) then
begin
Json2TSA(page,json);
for i:=0 to length(json) - 1 do
begin
Json2TSA(json[i],Beast);
if (Length(Beast) > 2) then
exit;
if JSONDataIsKeyValuePair(beast[0]) then
begin
DynArrayAppend(Result.Ids,StrToInt(DeQuote(JsonGetValue(beast[0]))));
Value:=DeQuote(JsonGetValue(beast[1]));
Brace:= Pos('(',Value);
Value:=CopyStop(Value,0,Brace-2);
if length(Value) > 0 then
DynArrayAppend(Result.Names,Value) else
DynArrayAppend(Result.Names,DeQuote(JsonGetValue(beast[1])));
end;
end;
end;

end;

function FindMonstersByArea(const AreaName: string): TFindedMonsters;
const
URL = 'http://services.runescape.com/m=itemdb_rs/bestiary/areaBeasts.json?identifier=';
var
i,Brace: integer;
page,value: string;
Json, Beast: TStringArray;
begin
SetLength(Result.Ids,0);
SetLength(Result.Names,0);

page:=GetPage(URL+GetFormattedUrl(AreaName));
if JSONDataIsList(page) then
begin
Json2TSA(page,json);
for i:=0 to length(json) - 1 do
begin
Json2TSA(json[i],Beast);
if (Length(Beast) > 2) then
exit;
if JSONDataIsKeyValuePair(beast[0]) then
begin
DynArrayAppend(Result.Ids,StrToInt(DeQuote(JsonGetValue(beast[0]))));
Value:=DeQuote(JsonGetValue(beast[1]));
Brace:= Pos('(',Value);
Value:=CopyStop(Value,0,Brace-2);
if length(Value) > 0 then
DynArrayAppend(Result.Names,Value) else
DynArrayAppend(Result.Names,DeQuote(JsonGetValue(beast[1])));
end;
end;
end;

end;
//for debugging
procedure PrintMonsters(Const Monsters: TFindedMonsters);
var
i: integer;
begin
if Length(Monsters.Ids) <> Length(Monsters.Names) then
exit;

for i:=0 to Length(Monsters.ids) -1 do
WriteLn('Monster ='+ Monsters.Names[i]+','+'Id ='+IntToStr(Monsters.Ids[i]));
end;

function GetMonsterById(const Id: integer): TMonster;
const
URL = 'http://services.runescape.com/m=itemdb_rs/bestiary/beastData.json?beastid=';
var
i,Brace: integer;
page,key: string;
Json, Beast: TStringArray;
begin
page:=GetPage(URL+IntToStr(Id));

if JSONDataIsList(page) then
begin
Json2TSA(page,json);
for i:=0 to length(json) - 1 do
begin
key:=DeQuote(JsonGetKey(Json[i]));
case key of
'slayercat': result.SlayerCat:=DeQuote(JsonGetValue(Json[i]));
'xp': result.xp:=StrToFloat(DeQuote(JsonGetValue(Json[i])));
'name': result.name:=DeQuote(JsonGetValue(Json[i]));
'level': result.lvl:= StrToInt(DeQuote(JsonGetValue(Json[i])));
'description': result.Description:= DeQuote(JsonGetValue(Json[i]));
'lifepoints': result.Life:=StrToInt(DeQuote(JsonGetValue(Json[i])));
'areas': JSON2Tsa(JsonGetValue(Json[i]),result.Areas);
'agressive': result.agressive:=StrToBool(DeQuote(JsonGetValue(Json[i])));
'members':Result.MembersOnly:=StrToBool(DeQuote(JsonGetValue(Json[i])));
end;

end;
end;

end;

function GetAreaNames(): TStringArray;
var
i: integer;
begin
end;

Procedure PrintMonster(const Monster: TMonster);
begin
WriteLn('Monster name: '+Monster.name);
WriteLn('Description: '+Monster.Description);
WriteLn('Lvl:'+inttostr(monster.lvl));
WriteLn('XP: '+floattostr(monster.xp));
WriteLn('Life:'+IntToStr(monster.life));
WriteLn('Members:'+Booltostr(Monster.Membersonly));
WriteLn(Monster.Areas);
WriteLn('Agressive:'+BoolToStr(Monster.Agressive));

end;

var
Monsters: TFindedMonsters;

MonstersABC: TFindedMonsters;

MonstersLVL : TFindedMonsters;

MonstersArea: TFindedMonsters;

Monster: Tmonster;

i: integer;
begin
Monsters:=FindMonsters('sheep cow');

PrintMonsters(Monsters);

MonstersABC:=FindMonstersByABC('y');

PrintMonsters(MonstersABC);
for i:= 0 to Length(MonstersABC.Ids) - 1 do
begin
Monster:=GetMonsterbyId(MonstersAbc.ids[i]);

PrintMonster(Monster);
end;

MonstersLVL:=FindMonstersByLvl(200,250);

PrintMonsters(MonstersLVL);

for i:= 0 to Length(MonstersLVL.Ids) - 1 do
begin
Monster:=GetMonsterbyId(MonstersLVL.ids[i]);

PrintMonster(Monster);
end;

MonstersArea:=FindMonstersByArea('Zanaris');

PrintMonsters(MonstersArea);

end.


Cheers,
Cynic.

Itankbots

2013-10-23 03:42:49

Damn, Very impressive…and super useful.

You never disappoint!

CynicRus

2013-10-23 05:28:43

Thank you!-)

J J

2013-10-23 07:29:46

Interesting, I've been working on some small Java projects to parse RuneScape hiscores, G/E prices and Bestiary information lately :P Nice to see that you made a JSON parser, should be helpful for many projects.