UNIT Unit9_data_structures; INTERFACE USES SysUtils, ABSMain, DB, ABSDecUtil, Classes, Unit3_data, Dialogs, StrUtils; 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] // 1000..9999: Unused data[0-8999] // 10000+: string[0+] description:String; END; TStructDefSub=RECORD SubName:String; Entries:Array OF TStructure_entry; END; TStructDef=RECORD Data:Boolean; Global:Array OF TStructure_entry; Subs:Array OF TStructDefSub; END; THandler=FUNCTION(fileid:LongWord):TRawList; TRawListHandlers=RECORD Ext:String[4]; needed:Boolean; Handler:THandler; END; VAR RawListHandlers:Array OF TRawListHandlers; FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef; FUNCTION GetDataType(typeid:Word):String; FUNCTION GetTypeDataLength(datatype:Word):Word; FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo; FUNCTION GetRawList(fileid:LongWord):TRawList; IMPLEMENTATION USES Unit2_functions, Forms; 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; 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); 1000..9999: Result:='Unused('+IntToStr(typeid-1000)+')'; 10000..65535: Result:='String('+IntToStr(typeid-10000)+')'; END; END; FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo; VAR i:LongWord; raw_list:TRawList; BEGIN raw_list:=GetRawList(fileid); Result.src_id:=0; Result.src_offset:=0; Result.raw_addr:=0; Result.raw_size:=0; FOR i:=0 TO High(raw_list) DO BEGIN IF raw_list[i].src_offset=dat_offset THEN BEGIN Result.src_id:=fileid; Result.src_offset:=raw_list[i].src_offset; Result.raw_addr:=raw_list[i].raw_addr; Result.raw_size:=raw_list[i].raw_size; Result.loc_sep:=raw_list[i].loc_sep; Break; END; END; END; FUNCTION GetRawList(fileid:LongWord):TRawList; VAR i:LongWord; Query:TABSQuery; BEGIN IF opened_state=opened_dat THEN BEGIN FOR i:=0 TO High(RawListHandlers) DO IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN IF RawListHandlers[i].needed THEN BEGIN Result:=RawListHandlers[i].Handler(fileid); Break; END ELSE Break; END ELSE BEGIN SetLength(Result,0); Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;'; Query.Open; IF Query.RecordCount>0 THEN BEGIN Query.First; SetLength(Result,Query.RecordCount); i:=0; REPEAT Result[i].src_id:=fileid; Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger; Result[i].raw_addr:=0; Result[i].raw_size:=Query.FieldByName('size').AsInteger; Inc(i); Query.Next; UNTIL Query.EOF; END; Query.Close; END; END; FUNCTION AGDB(fileid:LongWord):TRawList; VAR link:LongWord; links:LongWord; i:LongWord; BEGIN IF NOT dat_os_mac THEN BEGIN 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; LoadDatFilePart(fileid,$20+i*4,4,@link); Result[i].raw_addr:=link; Result[i].raw_size:=0{????????????????????????????????}; Result[i].loc_sep:=False; END; END; END; FUNCTION AKVA(fileid:LongWord):TRawList; VAR link:LongWord; links:LongWord; i:LongWord; BEGIN IF NOT dat_os_mac THEN BEGIN LoadDatFilePart(fileid,$1C,4,@links); SetLength(Result,links); FOR i:=0 TO links-1 DO BEGIN Result[i].src_offset:=$20+i*$74+$24; LoadDatFilePart(fileid,$20+i*$74+$24,4,@link); Result[i].raw_addr:=link; LoadDatFilePart(fileid,$20+i*$74+$28,4,@link); Result[i].raw_size:=link; Result[i].loc_sep:=False; END; END; END; FUNCTION BINA(fileid:LongWord):TRawList; VAR link:LongWord; datasize:LongWord; BEGIN LoadDatFilePart(fileid,$0C,4,@link); 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:=dat_os_mac; END; FUNCTION OSBD(fileid:LongWord):TRawList; VAR link:LongWord; datasize:LongWord; BEGIN LoadDatFilePart(fileid,$08,4,@datasize); 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:=dat_os_mac; END; FUNCTION SNDD(fileid:LongWord):TRawList; VAR link:LongWord; datasize:LongWord; BEGIN IF NOT dat_os_mac THEN BEGIN LoadDatFilePart(fileid,$40,4,@datasize); LoadDatFilePart(fileid,$44,4,@link); Result[0].src_offset:=$44; END ELSE BEGIN LoadDatFilePart(fileid,$10,4,@datasize); LoadDatFilePart(fileid,$14,4,@link); Result[0].src_offset:=$14; END; SetLength(Result,1); Result[0].raw_addr:=link; Result[0].raw_size:=datasize; Result[0].loc_sep:=False; END; FUNCTION SUBT(fileid:LongWord):TRawList; VAR baselink,link:LongWord; links:LongWord; i,j,k:LongWord; data:Tdata; BEGIN LoadDatFilePart(fileid,$18,4,@baselink); LoadDatFilePart(fileid,$1C,4,@links); IF links>0 THEN BEGIN LoadDatFilePart(fileid,$20+(links-1)*4,4,@link); SetLength(data,link+1024); LoadRawFile(fileid,$1C,baselink,link+1024,False,@data[0]); k:=0; FOR j:=0 TO 1024 DO BEGIN IF (data[link+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:=link+j; Break; END; END; END; END; END; END; FUNCTION TRAM(fileid:LongWord):TRawList; VAR i:Byte; link:LongWord; frames:Word; tempb:Byte; tempw:Word; templ:LongWord; data:Tdata; offset:Word; BEGIN SetLength(Result,13); LoadDatFilePart(fileid,$16C,2,@frames); {y-pos} LoadDatFilePart(fileid,$0C,4,@link); Result[0].src_offset:=$0C; Result[0].raw_addr:=link; Result[0].raw_size:=frames*4; {x-z-pos} LoadDatFilePart(fileid,$10,4,@link); Result[1].src_offset:=$10; Result[1].raw_addr:=link; Result[1].raw_size:=frames*8; {attacks} LoadDatFilePart(fileid,$182,1,@tempb); LoadDatFilePart(fileid,$14,4,@link); Result[2].src_offset:=$14; Result[2].raw_addr:=link; Result[2].raw_size:=tempb*32; {damage} LoadDatFilePart(fileid,$183,1,@tempb); LoadDatFilePart(fileid,$18,4,@link); Result[3].src_offset:=$18; Result[3].raw_addr:=link; Result[3].raw_size:=tempb*8; {motionblur} LoadDatFilePart(fileid,$184,1,@tempb); LoadDatFilePart(fileid,$1C,4,@link); Result[4].src_offset:=$1C; Result[4].raw_addr:=link; Result[4].raw_size:=tempb*8; {shortcut} LoadDatFilePart(fileid,$185,1,@tempb); LoadDatFilePart(fileid,$20,4,@link); Result[5].src_offset:=$20; Result[5].raw_addr:=link; Result[5].raw_size:=tempb*8; {throw} 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} LoadDatFilePart(fileid,$186,1,@tempb); LoadDatFilePart(fileid,$28,4,@link); Result[7].src_offset:=$28; Result[7].raw_addr:=link; Result[7].raw_size:=tempb*4; {particle} LoadDatFilePart(fileid,$187,1,@tempb); LoadDatFilePart(fileid,$2C,4,@link); Result[8].src_offset:=$2C; Result[8].raw_addr:=link; Result[8].raw_size:=tempb*24; {position} LoadDatFilePart(fileid,$30,4,@link); Result[9].src_offset:=$30; Result[9].raw_addr:=link; Result[9].raw_size:=frames*8; {particle} LoadDatFilePart(fileid,$154,2,@tempw); LoadDatFilePart(fileid,$38,4,@link); Result[11].src_offset:=$38; Result[11].raw_addr:=link; Result[11].raw_size:=tempw*34; {extent} LoadDatFilePart(fileid,$138,4,@templ); LoadDatFilePart(fileid,$13C,4,@link); Result[12].src_offset:=$13C; Result[12].raw_addr:=link; Result[12].raw_size:=templ*12; LoadDatFilePart(fileid,$34,4,@link); tempw:=0; IF link>0 THEN BEGIN {BODY ANIMATIONS PART DECODE!!!} SetLength(data,$FFFF); LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]); offset:=data[24]+data[25]*255; {} END; Result[10].src_offset:=$34; Result[10].raw_addr:=link; Result[10].raw_size:=tempw; END; FUNCTION TXMP(fileid:LongWord):TRawList; VAR link_pc:LongWord; link_mac:LongWord; x,y:Word; storetype:Byte; datasize:LongWord; BEGIN LoadDatFilePart(fileid,$8C,SizeOf(x),@x); LoadDatFilePart(fileid,$8E,SizeOf(y),@y); LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype); LoadDatFilePart(fileid,$9C,4,@link_pc); 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 dat_os_mac 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:=dat_os_mac; 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; END; FUNCTION LoadStructureDefinition(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:TStringList; filename:String; ext:String[4]; temps:String; data:TData; BEGIN SetLength(Result.Global,0); SetLength(Result.Subs,0); Result.Data:=False; ext:=GetFileInfo(fileid).Extension; filename:=ExtractFilePath(Application.ExeName)+'\StructDefs\'+ext+'.txt'; IF FileExists(filename) THEN BEGIN data:=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 THEN BEGIN IF temps[1]='*' THEN BEGIN fields:=Explode(temps,'#'); CASE Length(fields) OF 1: 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); END; 2: BEGIN current_type:=1; current_base:=HexToLong(fields[1]); SetLength(Result.Subs, Length(Result.Subs)+1); Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1); END; 5: BEGIN current_type:=2; current_base:=HexToLong(fields[1]); current_package:=0; current_package_size:=StrToInt(fields[4]); CASE StrToInt(fields[3]) OF 1: packages:=data[HexToLong(fields[2])]; 2: packages:=data[HexToLong(fields[2])]+data[HexToLong(fields[2])+1]*256; 4: packages:=data[HexToLong(fields[2])]+data[HexToLong(fields[2])+1]*256+data[HexToLong(fields[2])+2]*256*256+data[HexToLong(fields[2])+3]*256*256*256; 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); END; END; END; END ELSE BEGIN fields:=Explode(temps,#9); IF (Length(fields)=3) OR (Length(fields)=4) 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; CloseFile(deffile); END; END; BEGIN // InsertRawListHandler('AGDB',True,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.