Forum in READ ONLY mode! All questions and discussions on Discord official server, invite link: https://discord.gg/VxsGzJ7

Недокументированные функции

Часто задаваемые вопросы
Post Reply
BlackSpirit
Neophyte
Neophyte
Posts: 29
Joined: 20.10.2013 11:45

Недокументированные функции

Post by BlackSpirit »

Подскажите люди добрые, а что делают эти функции:

1. function GetAltName(id: Cardinal) : String; - просто синоним GetName или что-то большее?

2. function ConvertIntegerToFlags(Group: Byte; I : LongWord) : TTileDataFlagSet;

Вопрос больше про Group: Byte. Непонятно ни зачем этот параметр, ни как он работает. У меня эта функция почему-то всегда возвращает пустое множество.

На одной из веток, применительно к похожей по смыслу function GetTileFlags(Group : byte; Tile : Word) : Cardinal говорилось, что Group = 1 - тайл, 2 - объект, 3 - анимация. Но, хоть убей, не пойму, почему нельзя просто вот так:

Code: Select all

function GetTileFlags(Tile : Word) : LongWord;
begin
  Result := GetStaticTileData(Tile).Flags;
end;
или даже вот так:

Code: Select all

function GetArtFlags(Item: Cardinal) : LongWord;
begin
  Result := GetStaticTileData(GetType(Item)).Flags;
end;
Флаги ведь везде одинаковые?

Вообще, при наличии TTileDataFlagSet, который суть есть по особому интерпретируемый Паскалем обычный Integer, может, было бы правильнее, избавиться от LongWord?

3. function IsObjectExists(ObjectId: Cardinal): Boolean - что конкретно проверяет эта функция? Можно ли считать ее синонимом

Code: Select all

function IsObjectExists(ObjectId: Cardinal): Boolean;
begin
  Result := (GetType(ObjectId) > 0);
end;
Last edited by BlackSpirit on 30.10.2013 2:23, edited 1 time in total.
Uus Wis
User avatar
Vizit0r
Developer
Developer
Posts: 3958
Joined: 24.03.2005 17:05
Contact:

Re: Недокументированные функции

Post by Vizit0r »

1) ne pomnyu, zavtra posmotru
2) 1 - landtile, 2 - statictile.
ostaloe ne ponyal. set - eto set, integer - eto integer.
I net, flagi ne odinakovui u land i static.
3)da
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
CFA
Developer
Developer
Posts: 492
Joined: 20.04.2006 6:03
Contact:

Re: Недокументированные функции

Post by CFA »

По GetAltName:
CFA, 16.10.2011 16:34:12:
да, например для бекапака GetName будет просто backpack а GetAltName будет типа
a backpack (1 item)

CFA, 16.10.2011 16:34:42:
но это у вас, а у нас AltName'а в принципе ни у кого нет
Но работает это не на всех серверах (работает вроде бы только на сферах, да и то не на всех), там где не работает GetAltName возвратит пустую строк.

Заодно посмотрел что за group в ConvertIntegerToFlags
1 = tfLand возвращает флаги тайлов карты
2 = tfStatic возвращает флаги для тайлов статики
Некоторые значения этих флагов совпадают, некоторые различаются
BlackSpirit
Neophyte
Neophyte
Posts: 29
Joined: 20.10.2013 11:45

Re: Недокументированные функции

Post by BlackSpirit »

CFA wrote: Заодно посмотрел что за group в ConvertIntegerToFlags
0 = tfLand возвращает флаги тайлов карты
1 = tfStatic возвращает флаги для тайлов статики
Некоторые значения этих флагов совпадают, некоторые различаются
Если честно, мне осталось непонятна мысль, о том, что флаги чем-то различаются. Давно, давно, когда не было нормальной документации, о флагах я узнал отсюда http://uo.stratics.com/heptazane/fileformats.shtml, и прощупал используя InsedeUO http://uo.stratics.com/heptazane/insideuo/. Нигде упоминания о разных наборах флагов не нашел. Можно говорить лишь о том, что какие-то из флагов тайлов статики, обычно не встречаются на тайлах земли.

Исходя из написанного на Stratics, можно сделать такую штуку:

Code: Select all

const tfBackground  = $00000001;  // Фон  
const tfWeapon      = $00000002;  // Оружие
const tfTransparent = $00000004;  // Прозрачный
const tfTranslucent = $00000008;  // Полупразрачный
const tfWall        = $00000010;  // Стена
const tfDamaging    = $00000020;  // Может нанести урон
const tfImpassable  = $00000040;  // Непроходимый  
const tfWet         = $00000080;  // Мокрый (обычно вода либо ее источник)
const tfUnknown1    = $00000100;  
const tfSurface     = $00000200;  // Поверхность
const tfBridge      = $00000400;  // Мост
const tfGeneric     = $00000800;
const tfWindow      = $00001000;  // Окно в стене
const tfNoShoot     = $00002000;  // Не простреливается
const tfArticleA    = $00004000;  // Существительное с артиклем A
const tfArticleAn   = $00008000;  // Существительное с артиклем An
const tfInternal    = $00010000;  
const tfFoiliage    = $00020000;  // Листва деревьев
const tfPartialHue  = $00040000;  // Частично окрашен
const tfUnknown2    = $00080000;  
const tfMap         = $00100000;  
const tfContainer   = $00200000;  // Контейнер
const tfWearable    = $00400000;  // Можно одеть - т.е. одежда, броня, оружие и т.п.
const tfLightSource = $00800000;  // Источник света
const tfAnimation   = $01000000;  // Анимированный
const tfNoDiagonal  = $02000000;  // Нельзя пройти по диагонали
const tfMirrored    = $04000000;  // Зеркальный
const tfArmor       = $08000000;  // Броня
const tfRoof        = $10000000;  // Крыша здания
const tfDoor        = $20000000;  // Дверь
const tfStairBack   = $40000000;  // Лестница вниз  
const tfStairRight  = $80000000;  // Лестница наверх

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Возвращает истину, если набор флагов Flag содержится в наборе Flags
function InFlags(const Flag, Flags: LongWord): Boolean;
begin
  Result := (Flag = (Flag and Flags));
end;
Константы, приведенные выше представляют собой семейство чисел с побитовым сдвигом на одну позицию. Первая константа в бинарном виде "00000001", вторая "00000010", третья "00000100" и т.д.

Все это позволяет работать с флагами, например, вот так:

Code: Select all

//////////////////////////////////////////////////////////////////////
// получить набор флагов объекта
function GetArtFlags(Item: Cardinal) : LongWord;
begin
  Result := GetStaticTileData(GetType(Item)).Flags;
end;

//////////////////////////////////////////////////////////////////////
// Проверить, является ли объект "дверью"
function IsDoor(ObjectId: Cardinal): Boolean;
begin
  Result := InFlags(tfDoor+tfImpassable, GetArtFlags(ObjectId));
end;
Для более удобного отображения содержимого флагов или для тестов можно сделать такую функцию:

Code: Select all

//////////////////////////////////////////////////////////////////////
// Строковая расшифровка набора флагов Flags.
function FlagsToStr(Flags: LongWord): String;
begin
  if Flags = -1 then Result := '[All flags]'
  else begin
    Result := '[';
    if InFlags(tfBackground, Flags) then Result := Result+'Background,';
    if InFlags(tfWeapon, Flags) then Result := Result+'Weapon,';
    if InFlags(tfTransparent, Flags) then Result := Result+'Transparent,';
    if InFlags(tfTranslucent, Flags) then Result := Result+'Translucent,';
    if InFlags(tfWall, Flags) then Result := Result+'Wall,';
    if InFlags(tfDamaging, Flags) then Result := Result+'Damaging,';
    if InFlags(tfImpassable, Flags) then Result := Result+'Impassable,';
    if InFlags(tfWet, Flags) then Result := Result+'Wet,';
    if InFlags(tfUnknown1, Flags) then Result := Result+'Unknown1,';
    if InFlags(tfSurface, Flags) then Result := Result+'Surface,';
    if InFlags(tfBridge, Flags) then Result := Result+'Bridge,';
    if InFlags(tfGeneric, Flags) then Result := Result+'Generic,';
    if InFlags(tfWindow, Flags) then Result := Result+'Window,';
    if InFlags(tfNoShoot, Flags) then Result := Result+'NoShoot,';
    if InFlags(tfArticleA, Flags) then Result := Result+'ArticleA,';
    if InFlags(tfArticleAn, Flags) then Result := Result+'ArticleAn,';
    if InFlags(tfInternal, Flags) then Result := Result+'Internal,';
    if InFlags(tfFoiliage, Flags) then Result := Result+'Foiliage,';
    if InFlags(tfPartialHue, Flags) then Result := Result+'PartialHue,';
    if InFlags(tfUnknown2, Flags) then Result := Result+'Unknown2,';
    if InFlags(tfMap, Flags) then Result := Result+'Map,';
    if InFlags(tfContainer, Flags) then Result := Result+'Container,';
    if InFlags(tfWearable, Flags) then Result := Result+'Wearable,';
    if InFlags(tfLightSource, Flags) then Result := Result+'LightSource,';
    if InFlags(tfAnimation, Flags) then Result := Result+'Animation,';
    if InFlags(tfNoDiagonal, Flags) then Result := Result+'NoDiagonal,';
    if InFlags(tfMirrored, Flags) then Result := Result+'Mirrored,';
    if InFlags(tfArmor, Flags) then Result := Result+'Armor,';
    if InFlags(tfRoof, Flags) then Result := Result+'Roof,';
    if InFlags(tfDoor, Flags) then Result := Result+'Door,';
    if InFlags(tfStairBack, Flags) then Result := Result+'StairBack,';
    if InFlags(tfStairRight, Flags) then Result := Result+'StairRight,';
    if Result[Length(Result)]=',' then Result[Length(Result)] := ']' else Result := Result+']';
  end;
end;
Вообще описанный прием практически совпадает с конструкцией из манулала по RC1 http://stealth.od.ua/forum/viewtopic.php?f=6&t=1220

Code: Select all

TTileDataFlags = (tsfBackground, tsfWeapon, tsfTransparent, tsfTranslucent, tsfWall, tsfDamaging, tsfImpassable, tsfWet, tsfUnknown, tsfSurface, tsfBridge, tsfGeneric, tsfWindow, tsfNoShoot, tsfPrefixA, tsfPrefixAn, tsfInternal, tsfFoliage, tsfPartialHue, tsfUnknown1, tsfMap, tsfContainer, tsfWearable, tsfLightSource, tsfAnimated, tsfNoDiagonal, tsfUnknown2, tsfArmor, tsfRoof, tsfDoor, tsfStairBack, tsfStairRight, 
// флаги ниже по сути совпадают с флагами выше
tlfTranslucent, tlfWall, tlfDamaging, tlfImpassable, tlfWet, tlfSurface, tlfBridge, tlfPrefixA, tlfPrefixAn, tlfInternal, tlfMap, tlfUnknown3); 
TTileDataFlagSet = set of TTileDataFlags;
set - это условно говоря "длинное целое", обычно 32 или 64 бита, в котором каждый бит, аналогично означает наличие или отсутствие элемента в множестве. Вот причина того, что в Паскале нельзя в множестве хранить больше определенного числа элементов. Операции над множеством перегружены Паскалем, это арифметические действия имеющие смысл: объединение, пересечение, дополнение и др. - суть есть побитовые операции. Хорошей иллюстрацией работы с множеством может быть такой пример:

Code: Select all

Program setsample;

type Day = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);

type Days = Set of Day;

//////////////////////////////////////////////////////////////////////
//  Операция "проверка вхождения"
function InDays(const d1,d2: Days): Boolean;
begin
  Result := (d2 = (d1+d2));
end;

//////////////////////////////////////////////////////////////////////
//  Операция "объединение"

function UntDays(const d1,d2: Days): Days;
begin
  Result := d1+d2;
end;

//////////////////////////////////////////////////////////////////////
//  Операция "пересечение"
function IscDays(const d1,d2: Days): Days;
begin
  Result := d1*d2;
end;

//////////////////////////////////////////////////////////////////////
//  Операция "левое дополнение"
function LExclDays(const d1,d2: Days): Days;
begin
  Result := (d1-d2);
end; 

//////////////////////////////////////////////////////////////////////
//  Операция "полное дополнение"
function ExclDays(const d1,d2: Days): Days;
begin
  Result := (d1-d2)+(d2-d1);
end; 
   
begin 
  if InDays([Wed], IscDays(UntDays([Mon,Wed],[Thu]),[Tue,Wed]))  then AddToSystemJournal('ok');
end;
Преимущества set очевидны - компактно, быстро обрабатывается, наглядно. Но ничем от обычных побитовых операций над целым, вроде and, or, xor не отличается. И собственно мне осталось непонятно зачем преобразователю ConvertIntegerToFlags использовать еще один параметр. Кстати, в единственном известном примере использования функции этого параметра нет. У меня, почему-то при любом значении параметра Group получается пустое множество. Видимо я с чем-то не разобрался, если не затруднит, запостите, пожалуйста работающую версию IsDoor с помощью ConvertIntegerToFlags.

Если вернуться к тайлам, то мне, при их изучении очень помогла следующая самописная процедурка:

Code: Select all

procedure InfoXY(X,Y: Word);
var
  MapCell: TMapCell;
  LandTileData: TLandTileData;
  StaticCell: TStaticCell;
  StaticItem: TStaticItem;
  StaticTileData: TStaticTileData;
  i: Integer;
  FL: TStringList;
  Id: Cardinal;
  Z: ShortInt;
begin
  FillNewWindow('********************* Info X='+IntToStr(X)+', Y='+IntToStr(Y)+' *********************');
  MapCell := GetMapCell(X,Y,WorldNum);
  LandTileData := GetLandTileData(MapCell.Tile);

  FillNewWindow('*  Land: Name="'+ConvertCharArray2String(LandTileData.Name)+'", Tile=$'+IntToHex(MapCell.Tile,4)+', Flags='+FlagsToStr(LandTileData.Flags)+', Z='+IntToStr(MapCell.Z));
  FillNewWindow('*  Statics:');
  StaticCell := ReadStaticsXY(X,Y,WorldNum);
  if StaticCell.StaticCount > 0 then begin
    for i := 0 to StaticCell.StaticCount-1 do begin
      StaticItem := StaticCell.Statics[i];
      StaticTileData := GetStaticTileData(StaticItem.Tile);
      FillNewWindow('*       Name="'+ConvertCharArray2String(StaticTileData.Name)+'", Tile=$'+IntToHex(StaticItem.Tile,4)+', Flags='+FlagsToStr(StaticTileData.Flags)+', Z='+IntToStr(StaticItem.Z));
    end;
  end; 
  FillNewWindow('*  Objects:');
  if FindAtCoord(X,Y) > 0 then begin
    FL := TStringList.Create;
    GetFindedList(FL);
    for i := 0 to FL.Count-1 do begin
      Id := StrToInt('$'+FL.Strings[i]);
      FillNewWindow('*       Name="'+GetArtName(Id)+'", Id=$'+IntToHex(Id,8)+', Type=$'+IntToHex(GetType(Id),4)+', Color=$'+IntToHex(GetColor(Id),4)+', Flags='+FlagsToStr(GetArtFlags(Id))+', Z='+IntToStr(GetZ(Id)));
    end;
    FL.Free;
  end;
  if IsWorldCellPassable(GetX(Self), GetY(Self), GetZ(Self), X,Y,Z, WorldNum) then  FillNewWindow('*  Passable point') else FillNewWindow('*  Impassable point') ;
  FillNewWindow('*');  
end;
Которую, начиная с 5-го Стелса можно обрамить таким образом:

Code: Select all

procedure info;
var t: TTargetInfo;
begin
  ClientRequestTileTarget;
  WaitForClientTargetResponse(15000);
  t := ClientTargetResponse;
  InfoXY(t.X, t.Y);  
end;
И забиндить на клавишу.

Тогда вы сможете тыкать на землю и видеть как устроены тайлы в нужной точке, получая в дополнительном окне сообщения такого типа:
********************* Info X=2852, Y=3536 *********************
* Land: Name="grass", Tile=$0003, Flags=[Mirrored], Z=0
* Statics:
* Objects:
* Name="a wooden door", Id=$4050DE1E, Type=$06A5, Color=$0000, Flags=[Wall,Impassable,NoShoot,ArticleA,Door], Z=7
* Impassable point
*
********************* Info X=2842, Y=3542 *********************
* Land: Name="grass", Tile=$00C0, Flags=[], Z=0
* Statics:
* Name="leaves", Tile=$0D8C, Flags=[Foiliage], Z=0
* Objects:
* Passable point
*
********************* Info X=2840, Y=3538 *********************
* Land: Name="grass", Tile=$0003, Flags=[Mirrored], Z=0
* Statics:
* Name="leaves", Tile=$0D52, Flags=[Foiliage], Z=0
* Objects:
* Passable point
*
*
:oops: сори за флуд, может кому-то будет полезно.
Uus Wis
User avatar
Vizit0r
Developer
Developer
Posts: 3958
Joined: 24.03.2005 17:05
Contact:

Re: Недокументированные функции

Post by Vizit0r »

1) имхо, кто знает - тому уже эти технические подробности не нужны.
А кто не знает - не нужны и подавно.

2) ты изобретаешь велосипед.

Code: Select all

      StaticData := DataGetStaticTile(StaticCell.Statics[I].Tile);
      FlagSet := DataConvertIntegerToFlags(tfStatic, StaticData.Flags);
      if not ((tsfImpassable in FlagSet) or (tsfSurface in FlagSet)
        or (tsfBridge in FlagSet) or (tsfNoDiagonal in FlagSet)) then
....
Можно говорить лишь о том, что какие-то из флагов тайлов статики, обычно не встречаются на тайлах земли.
можно лишь говорить, что некоторые флаги встречаются и там и там. некоторые нет. никаких "обычно".

Code: Select all

set - это условно говоря "длинное целое", обычно 32 или 64 бита, в котором каждый бит, аналогично означает наличие или отсутствие элемента в множестве. Вот причина того, что в Паскале нельзя в множестве хранить больше определенного числа элементов. Операции над множеством перегружены Паскалем, это арифметические действия имеющие смысл: объединение, пересечение, дополнение и др. - суть есть побитовые операции.
в старых дельфах - да. В новых все сложнее. Но опять же, кому нужны эти технические подробности?


Примеры хорошие, когда буду заполнять вики, вставлю втуда.
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
Post Reply