UNIT Unit9_data_structures; INTERFACE USES SysUtils, ABSMain, DB, ABSDecUtil, Unit3_data; 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; 10000+: string[0+] description:String; END; Tstructure_info=RECORD extension:String; typedesc:String; entries:Array OF Tstructure_entry; END; Tstructures=Array OF Tstructure_info; VAR structure_infos:Tstructures; FUNCTION GetDataType(typeid:Word):String; FUNCTION GetStructureInfoId(ext:String):Integer; FUNCTION GetTypeDataLength(datatype:Word):Word; FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo; FUNCTION GetRawList(fileid:LongWord):TRawList; IMPLEMENTATION USES Unit2_functions; TYPE THandler=FUNCTION(fileid:LongWord):TRawList; TRawListHandlers=RECORD Ext:String[4]; needed:Boolean; Handler:THandler; END; VAR RawListHandlers:Array OF TRawListHandlers; 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; 10000..65535: Result:=datatype-10000; END; END; FUNCTION GetStructureInfoId(ext:String):Integer; VAR i:Integer; BEGIN FOR i:=0 TO High(structure_infos) DO BEGIN IF structure_infos[i].extension=ext THEN BEGIN Result:=i; Exit; END; END; Result:=-1; 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'; 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; Break; END; END; END; FUNCTION GetRawList(fileid:LongWord):TRawList; VAR i:LongWord; Query:TABSQuery; BEGIN IF opened_state=opened_dat THEN BEGIN FOR i:=1 TO Length(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 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{????????????????????????????????}; 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; 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; END; FUNCTION SNDD(fileid:LongWord):TRawList; VAR link:LongWord; datasize:LongWord; BEGIN LoadDatFilePart(fileid,$40,4,@datasize); LoadDatFilePart(fileid,$44,4,@link); SetLength(Result,1); Result[0].src_offset:=$44; Result[0].raw_addr:=link; Result[0].raw_size:=datasize; 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,@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,1,@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,@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: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); 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); Result[0].src_offset:=$9C; Result[0].raw_addr:=link; Result[0].raw_size:=datasize; END; PROCEDURE AddEntry(_ext:String; _name:String; _offset:LongWord; _datatype:Word; _description:String); VAR sid:Integer; BEGIN sid:=GetStructureInfoId(_ext); IF sid>=0 THEN BEGIN WITH structure_infos[sid] DO BEGIN SetLength(entries,Length(entries)+1); WITH entries[High(entries)] DO BEGIN name:=_name; offset:=_offset; datatype:=_datatype; description:=_description; END; END; END; END; PROCEDURE AddExtension(_ext:String; _typedesc:String); BEGIN IF GetStructureInfoId(_ext)<0 THEN BEGIN SetLength(structure_infos,Length(structure_infos)+1); WITH structure_infos[High(structure_infos)] DO BEGIN extension:=_ext; typedesc:=_typedesc; END; END; 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; BEGIN AddExtension('SUBT','Subtitles'); AddEntry('SUBT','ID',$00,4,'ID of this file'); AddEntry('SUBT','LevelID',$04,8,'ID of the level this file is in'); AddEntry('SUBT','Raw-Link',$18,11,'Address of the subtitle data in the .raw-file'); AddEntry('SUBT','Subtitle count',$1C,4,'Number of subtitles in this file'); AddExtension('TXMP','Texture'); AddEntry('TXMP','ID',$00,4,'ID of this file'); AddEntry('TXMP','LevelID',$04,8,'ID of the level this file is in'); AddEntry('TXMP','FileName',$08,10128,''); AddEntry('TXMP','Fading',$88,10,'Fading-Bitset'); AddEntry('TXMP','Depth',$89,10,'Depth-Bitset'); AddEntry('TXMP','Width',$8C,2,'x-resolution of image'); AddEntry('TXMP','Height',$8E,2,'y-resolution of image'); AddEntry('TXMP','Storetype',$90,10,'Storetype-Bitset'); AddEntry('TXMP','TXAN-Link',$94,8,'Link to the TXAN-file (if this TXMP is the first image of an animation)'); AddEntry('TXMP','TXMP-Link',$98,8,'Link to another TXMP-file'); AddEntry('TXMP','Raw-Link',$9C,11,'Address of the image data in the .raw-file'); 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.