unit DataStructures; interface uses SysUtils, Classes, Data, Dialogs, StrUtils, OniDataClass; type Tstructure_entry = record Name: String; offset: LongWord; datatype: Word; // 1..4 : Integer[1..4] dec // 5..8 : Integer[1..4] hex // 9 : float // 10 : bitset // 11 : raw-addr // 12 : dat-file-ID // 13..16: Signed Integer[1..4] // 17 : level-ID // 100..300: dat-file-name[0..200] // 1000..9999: Unused data[0-8999] // 10000+: string[0+] description: String; end; TStructDefSub = record SubName: String; SubDesc: String; Entries: array of TStructure_entry; end; TStructDef = record Data: Boolean; Global: array of TStructure_entry; Subs: array of TStructDefSub; end; THandler = function(connection: TOniData; fileid: LongWord): TRawList; TRawListHandlers = record Ext: String[4]; needed: Boolean; Handler: THandler; end; var RawListHandlers: array of TRawListHandlers; Raws: String; function LoadStructureDefinition(connection: TOniData; fileid: LongWord): TStructDef; function GetDataType(typeid: Word): String; function GetTypeDataLength(datatype: Word): Word; implementation uses Functions, Forms, Template; function GetTypeDataLength(datatype: Word): Word; begin case datatype of 1..4: Result := datatype; 5..8: Result := datatype - 4; 9: Result := 4; 10: Result := 1; 11: Result := 4; 12: Result := 4; 13..16: Result := datatype - 12; 17: Result := 4; 100..300: Result := datatype - 100; 1000..9999: Result := datatype - 1000; 10000..65535: Result := datatype - 10000; end; end; function GetDataType(typeid: Word): String; begin case typeid of 1..4: Result := 'Int' + IntToStr(typeid * 8); 5..8: Result := 'Int' + IntToStr((typeid - 4) * 8); 9: Result := 'Float'; 10: Result := 'BitSet'; 11: Result := 'Raw-Address'; 12: Result := '.dat-file-ID'; 13..16: Result := 'SignedInt' + IntToStr((typeid - 12) * 8); 17: Result := 'LevelID'; 100..300: Result := '.dat-file-name(' + IntToStr(typeid - 100) + ')'; 1000..9999: Result := 'Unused(' + IntToStr(typeid - 1000) + ')'; 10000..65535: Result := 'String(' + IntToStr(typeid - 10000) + ')'; end; end; function AGDB(connection: TOniData; fileid: LongWord): TRawList; var link: LongWord; links: LongWord; i: LongWord; begin if not connection.OSisMac then begin connection.LoadDatFilePart(fileid, $1C, 4, @links); links := links * 2; SetLength(Result, links); for i := 0 to links - 1 do begin Result[i].src_offset := $20 + i * 4; connection.LoadDatFilePart(fileid, $20 + i * 4, 4, @link); Result[i].raw_addr := link; Result[i].raw_size := 32; Result[i].loc_sep := False; end; end; end; function AKVA(connection: TOniData; fileid: LongWord): TRawList; var link: LongWord; links: LongWord; i: LongWord; begin if not connection.OSisMac then begin connection.LoadDatFilePart(fileid, $1C, 4, @links); SetLength(Result, links); for i := 0 to links - 1 do begin Result[i].src_offset := $20 + i * $74 + $24; connection.LoadDatFilePart(fileid, $20 + i * $74 + $24, 4, @link); Result[i].raw_addr := link; connection.LoadDatFilePart(fileid, $20 + i * $74 + $28, 4, @link); Result[i].raw_size := link; Result[i].loc_sep := False; end; end; end; function BINA(connection: TOniData; fileid: LongWord): TRawList; var link: LongWord; datasize: LongWord; begin connection.LoadDatFilePart(fileid, $0C, 4, @link); connection.LoadDatFilePart(fileid, $08, 4, @datasize); SetLength(Result, 1); Result[0].src_offset := $0C; Result[0].raw_addr := link; Result[0].raw_size := datasize; Result[0].loc_sep := connection.OSisMac; end; function OSBD(connection: TOniData; fileid: LongWord): TRawList; var link: LongWord; datasize: LongWord; begin connection.LoadDatFilePart(fileid, $08, 4, @datasize); connection.LoadDatFilePart(fileid, $0C, 4, @link); SetLength(Result, 1); Result[0].src_offset := $0C; Result[0].raw_addr := link; Result[0].raw_size := datasize; Result[0].loc_sep := connection.OSisMac; end; function SNDD(connection: TOniData; fileid: LongWord): TRawList; var link: LongWord; datasize: LongWord; begin SetLength(Result, 1); if not connection.OSisMac then begin connection.LoadDatFilePart(fileid, $40, 4, @datasize); connection.LoadDatFilePart(fileid, $44, 4, @link); Result[0].src_offset := $44; end else begin connection.LoadDatFilePart(fileid, $10, 4, @datasize); connection.LoadDatFilePart(fileid, $14, 4, @link); Result[0].src_offset := $14; end; Result[0].raw_addr := link; Result[0].raw_size := datasize; Result[0].loc_sep := False; end; function SUBT(connection: TOniData; fileid: LongWord): TRawList; var baselink, lastlink: LongWord; links: LongWord; j, k: LongWord; Data: Tdata; begin connection.LoadDatFilePart(fileid, $18, 4, @baselink); connection.LoadDatFilePart(fileid, $1C, 4, @links); if links > 0 then begin connection.LoadDatFilePart(fileid, $20 + (links - 1) * 4, 4, @lastlink); SetLength(Data, lastlink + 1024); TOniDataDat(connection).LoadRawOffset(False, baselink, lastlink + 1024, Data); // connection.LoadRawFile(fileid,$1C,baselink,lastlink+1024,False,@data[0]); k := 0; for j := 0 to 1024 do begin if (Data[lastlink + j] = $00) or (j = 1024) then begin if j < 1024 then begin if k = 0 then begin k := 1; end else begin SetLength(Result, 1); Result[0].src_offset := $18; Result[0].raw_addr := baselink; Result[0].raw_size := lastlink + j; Break; end; end; end; end; end; end; function TRAM(connection: TOniData; fileid: LongWord): TRawList; var i: Integer; link: LongWord; frames: Word; tempb: Byte; tempw: Word; templ: LongWord; Data: Tdata; offset: Word; frame_count: Byte; begin SetLength(Result, 13); connection.LoadDatFilePart(fileid, $16C, 2, @frames); {y-pos} connection.LoadDatFilePart(fileid, $0C, 4, @link); Result[0].src_offset := $0C; Result[0].raw_addr := link; Result[0].raw_size := frames * 4; {x-z-pos} connection.LoadDatFilePart(fileid, $10, 4, @link); Result[1].src_offset := $10; Result[1].raw_addr := link; Result[1].raw_size := frames * 8; {attacks} connection.LoadDatFilePart(fileid, $182, 1, @tempb); connection.LoadDatFilePart(fileid, $14, 4, @link); Result[2].src_offset := $14; Result[2].raw_addr := link; Result[2].raw_size := tempb * 32; {damage} connection.LoadDatFilePart(fileid, $183, 1, @tempb); connection.LoadDatFilePart(fileid, $18, 4, @link); Result[3].src_offset := $18; Result[3].raw_addr := link; Result[3].raw_size := tempb * 8; {motionblur} connection.LoadDatFilePart(fileid, $184, 1, @tempb); connection.LoadDatFilePart(fileid, $1C, 4, @link); Result[4].src_offset := $1C; Result[4].raw_addr := link; Result[4].raw_size := tempb * 8; {shortcut} connection.LoadDatFilePart(fileid, $185, 1, @tempb); connection.LoadDatFilePart(fileid, $20, 4, @link); Result[5].src_offset := $20; Result[5].raw_addr := link; Result[5].raw_size := tempb * 8; {throw} connection.LoadDatFilePart(fileid, $24, 4, @link); Result[6].src_offset := $24; Result[6].raw_addr := link; if link > 0 then Result[6].raw_size := 24 else Result[6].raw_size := 0; {footstep} connection.LoadDatFilePart(fileid, $186, 1, @tempb); connection.LoadDatFilePart(fileid, $28, 4, @link); Result[7].src_offset := $28; Result[7].raw_addr := link; Result[7].raw_size := tempb * 4; {particle} connection.LoadDatFilePart(fileid, $187, 1, @tempb); connection.LoadDatFilePart(fileid, $2C, 4, @link); Result[8].src_offset := $2C; Result[8].raw_addr := link; Result[8].raw_size := tempb * 24; {position} connection.LoadDatFilePart(fileid, $30, 4, @link); Result[9].src_offset := $30; Result[9].raw_addr := link; Result[9].raw_size := frames * 8; {particle} connection.LoadDatFilePart(fileid, $154, 2, @tempw); connection.LoadDatFilePart(fileid, $38, 4, @link); Result[11].src_offset := $38; Result[11].raw_addr := link; Result[11].raw_size := tempw * 34; {extent} connection.LoadDatFilePart(fileid, $138, 4, @templ); connection.LoadDatFilePart(fileid, $13C, 4, @link); Result[12].src_offset := $13C; Result[12].raw_addr := link; Result[12].raw_size := templ * 12; connection.LoadDatFilePart(fileid, $34, 4, @link); if link > 0 then begin connection.LoadDatFilePart(fileid, $160, 2, @tempw); frame_count := 0; i := 0; SetLength(Data, $FFFF); TOniDataDat(connection).LoadRawOffset(False, link, $FFFF, Data); offset := Data[$24] + Data[$25] * 256; while (offset + i < Length(Data)) and (frame_count < frames - 1) do begin Inc(i, tempw); frame_count := frame_count + Data[offset + i]; Inc(i); end; if offset + i < Length(Data) then begin Inc(i, tempw); Result[10].raw_size := offset + i; end else begin Result[10].raw_size := 0; end; end; Result[10].src_offset := $34; Result[10].raw_addr := link; end; function TXMP(connection: TOniData; fileid: LongWord): TRawList; var link_pc: LongWord; link_mac: LongWord; x, y: Word; storetype: Byte; datasize: LongWord; begin connection.LoadDatFilePart(fileid, $8C, SizeOf(x), @x); connection.LoadDatFilePart(fileid, $8E, SizeOf(y), @y); connection.LoadDatFilePart(fileid, $90, SizeOf(storetype), @storetype); connection.LoadDatFilePart(fileid, $9C, 4, @link_pc); connection.LoadDatFilePart(fileid, $A0, 4, @link_mac); case storetype of 0, 1, 2: datasize := x * y * 2; 8: datasize := x * y * 4; 9: datasize := x * y div 2; end; SetLength(Result, 1); if not connection.OSisMac then begin Result[0].src_offset := $9C; Result[0].raw_addr := link_pc; end else begin Result[0].src_offset := $A0; Result[0].raw_addr := link_mac; end; Result[0].raw_size := datasize; Result[0].loc_sep := connection.OSisMac; end; procedure InsertRawListHandler(ext: String; needed: Boolean; handler: THandler); begin SetLength(RawListHandlers, Length(RawListHandlers) + 1); RawListHandlers[High(RawListHandlers)].Ext := ext; RawListHandlers[High(RawListHandlers)].needed := needed; RawListHandlers[High(RawListHandlers)].handler := handler; Raws := Raws + ext; AddToolListEntry('rawedit', '', ext); end; function LoadStructureDefinition(connection: TOniData; fileid: LongWord): TStructDef; var i: LongWord; current_type: Byte; //0: Global, 1: Undynamic, 2: Dynamic current_base, current_package, current_package_size: LongWord; packages: LongWord; deffile: Text; structentry: TStructure_Entry; fields: TStringArray; filename: String; ext: String[4]; temps: String; Data: TData; begin SetLength(Result.Global, 0); SetLength(Result.Subs, 0); Result.Data := False; ext := connection.GetFileInfo(fileid).Extension; filename := ExtractFilePath(Application.ExeName) + '\StructDefs\' + ext + '.txt'; if FileExists(filename) then begin Data := connection.LoadDatFile(fileid); AssignFile(deffile, filename); Reset(deffile); current_type := 0; Result.Data := True; if not EOF(deffile) then begin ReadLn(deffile, temps); while not EOF(deffile) do begin ReadLn(deffile, temps); if (Length(temps) > 0) and (temps[1] <> '#') then begin if temps[1] = '*' then begin fields := Explode(temps, #9); case Length(fields) of 1..2: begin current_type := 1; current_base := 0; SetLength(Result.Subs, Length(Result.Subs) + 1); Result.Subs[High(Result.Subs)].SubName := MidStr(fields[0], 2, Length(fields[0]) - 1); if Length(fields) = 2 then Result.Subs[High(Result.Subs)].SubDesc := fields[1]; end; 3: begin current_type := 1; current_base := HexToLong(fields[2]); SetLength(Result.Subs, Length(Result.Subs) + 1); Result.Subs[High(Result.Subs)].SubName := MidStr(fields[0], 2, Length(fields[0]) - 1); Result.Subs[High(Result.Subs)].SubDesc := fields[1]; end; 6: begin current_type := 2; current_base := HexToLong(fields[2]); current_package := 0; current_package_size := StrToInt(fields[5]); if fields[4][1] <> '$' then begin case StrToInt(fields[4]) of 1: packages := Data[HexToLong(fields[3])]; 2: packages := Data[HexToLong(fields[3])] + Data[HexToLong(fields[3]) + 1] * 256; 4: packages := Data[HexToLong(fields[3])] + Data[HexToLong(fields[3]) + 1] * 256 + Data[HexToLong(fields[3]) + 2] * 256 * 256 + Data[HexToLong(fields[3]) + 3] * 256 * 256 * 256; end; end else begin packages := HexToLong(fields[4]); end; SetLength(Result.Subs, Length(Result.Subs) + packages); for current_package := 0 to packages - 1 do begin Result.Subs[High(Result.Subs) - packages + current_package + 1].SubName := MidStr(fields[0], 2, Length(fields[0]) - 1) + '[' + IntToStr(current_package) + ']' + '#' + IntToHex(current_base + current_package * current_package_size, 8) + '#' + IntToHex(current_package_size, 8); Result.Subs[High(Result.Subs) - packages + current_package + 1].SubDesc := fields[1]; end; end; end; end else begin fields := Explode(temps, #9); if (Length(fields) = 3) or (Length(fields) = 4) then begin if not AppSettings.HideUnusedData or ((StrToInt(fields[2]) < 1000) or (StrToInt(fields[2]) > 9999)) then begin structentry.Name := fields[0]; structentry.datatype := StrToInt(fields[2]); if Length(fields) = 4 then structentry.description := fields[3] else structentry.description := ''; if current_type in [0, 1] then begin structentry.offset := HexToLong(fields[1]) + current_base; if Length(Result.Subs) = 0 then begin SetLength(Result.Global, Length(Result.Global) + 1); Result.Global[High(Result.Global)] := structentry; end else begin SetLength(Result.Subs[High(Result.Subs)].Entries, Length(Result.Subs[High(Result.Subs)].Entries) + 1); Result.Subs[High(Result.Subs)].Entries[High( Result.Subs[High(Result.Subs)].Entries)] := structentry; end; end else begin for current_package := 0 to packages - 1 do begin structentry.offset := current_base + current_package * current_package_size + HexToLong(fields[1]); with Result.Subs[High(Result.Subs) - packages + current_package + 1] do begin SetLength(Entries, Length(Entries) + 1); Entries[High(Entries)] := structentry; end; end; end; end; end; end; end; end; end; CloseFile(deffile); end; end; begin Raws := ''; InsertRawListHandler('AGDB',False,AGDB); InsertRawListHandler('AKVA', True, AKVA); InsertRawListHandler('BINA', True, BINA); InsertRawListHandler('OSBD', True, OSBD); InsertRawListHandler('SNDD', True, SNDD); InsertRawListHandler('SUBT', True, SUBT); InsertRawListHandler('TRAM', True, TRAM); InsertRawListHandler('TXMP', True, TXMP); end.