Results 1 to 4 of 4

Thread: RS Bestiary API script [LaPe]

  1. #1
    Join Date
    May 2012
    Location
    Moscow, Russia
    Posts
    661
    Mentioned
    35 Post(s)
    Quoted
    102 Post(s)

    Default RS Bestiary API script [LaPe]

    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:
    Simba Code:
    //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:

    Simba Code:
    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.
    Per aspera ad Astra!
    ----------------------------------------
    Slow and steady wins the race.

  2. #2
    Join Date
    Nov 2011
    Location
    United States
    Posts
    815
    Mentioned
    6 Post(s)
    Quoted
    284 Post(s)

    Default

    Damn, Very impressive...and super useful.

    You never disappoint!

  3. #3
    Join Date
    May 2012
    Location
    Moscow, Russia
    Posts
    661
    Mentioned
    35 Post(s)
    Quoted
    102 Post(s)

    Default

    Thank you!-)
    Per aspera ad Astra!
    ----------------------------------------
    Slow and steady wins the race.

  4. #4
    Join Date
    Dec 2011
    Location
    The Netherlands
    Posts
    1,631
    Mentioned
    47 Post(s)
    Quoted
    254 Post(s)

    Default

    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.

    Script source code available here: Github

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •